[libc-commits] [libc] 6ae71f3 - [libc] (Begin to) implement ptrace for linux (#201601)
via libc-commits
libc-commits at lists.llvm.org
Thu Jun 4 23:04:49 PDT 2026
Author: Pavel Labath
Date: 2026-06-05T08:04:45+02:00
New Revision: 6ae71f321933ff629755ca61978a276a6e816827
URL: https://github.com/llvm/llvm-project/commit/6ae71f321933ff629755ca61978a276a6e816827
DIFF: https://github.com/llvm/llvm-project/commit/6ae71f321933ff629755ca61978a276a6e816827.diff
LOG: [libc] (Begin to) implement ptrace for linux (#201601)
This function is more complicated than your average syscall wrapper,
which is why this PR is mainly about setting up the infrastructure. I've
made this an experimental entry point, as the only request it handles is
PTRACE_TRACEME.
I also added a test to verify the PTRACE_TRACEME behavior. It's an
integration test as anything ptrace-y requires two processes.
Assisted by Gemini.
Added:
libc/include/llvm-libc-macros/sys-ptrace-macros.h
libc/include/sys/ptrace.yaml
libc/src/__support/OSUtil/linux/syscall_wrappers/ptrace.h
libc/src/sys/ptrace/CMakeLists.txt
libc/src/sys/ptrace/linux/CMakeLists.txt
libc/src/sys/ptrace/linux/ptrace.cpp
libc/src/sys/ptrace/ptrace.h
libc/test/integration/src/sys/ptrace/CMakeLists.txt
libc/test/integration/src/sys/ptrace/linux/CMakeLists.txt
libc/test/integration/src/sys/ptrace/linux/ptrace_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/aarch64/headers.txt
libc/config/linux/arm/entrypoints.txt
libc/config/linux/arm/headers.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/riscv/headers.txt
libc/config/linux/x86_64/entrypoints.txt
libc/config/linux/x86_64/headers.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-macros/CMakeLists.txt
libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
libc/src/sys/CMakeLists.txt
libc/test/integration/src/sys/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 4c6b43a3dba8e..590b8c19bf1ef 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1282,8 +1282,12 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
libc.src.regex.regexec
libc.src.regex.regerror
libc.src.regex.regfree
+
+ # sys/ptrace.h entrypoints
+ libc.src.sys.ptrace.ptrace
+
# wchar.h entrypoints
- libc.src.wchar.swprintf
+ libc.src.wchar.swprintf
)
endif()
endif()
diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 37e526736b617..a7ce42c9c4a91 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -72,5 +72,8 @@ set(TARGET_PUBLIC_HEADERS
)
if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
- list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+ list(APPEND TARGET_PUBLIC_HEADERS
+ libc.include.regex
+ libc.include.sys_ptrace
+ )
endif()
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 49b30ef1830f3..0a03c9a997824 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -565,6 +565,9 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
libc.src.regex.regexec
libc.src.regex.regerror
libc.src.regex.regfree
+
+ # sys/ptrace.h entrypoints
+ libc.src.sys.ptrace.ptrace
)
endif()
endif()
diff --git a/libc/config/linux/arm/headers.txt b/libc/config/linux/arm/headers.txt
index 4f774a0fd8935..c8ca848b79f09 100644
--- a/libc/config/linux/arm/headers.txt
+++ b/libc/config/linux/arm/headers.txt
@@ -28,5 +28,8 @@ set(TARGET_PUBLIC_HEADERS
)
if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
- list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+ list(APPEND TARGET_PUBLIC_HEADERS
+ libc.include.regex
+ libc.include.sys_ptrace
+ )
endif()
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index e4116fd4c25ae..5cea007a6c3ae 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1415,6 +1415,9 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
libc.src.regex.regexec
libc.src.regex.regerror
libc.src.regex.regfree
+
+ # sys/ptrace.h entrypoints
+ libc.src.sys.ptrace.ptrace
)
endif()
endif()
diff --git a/libc/config/linux/riscv/headers.txt b/libc/config/linux/riscv/headers.txt
index 7b3b8d98ac130..ce9cda307caf3 100644
--- a/libc/config/linux/riscv/headers.txt
+++ b/libc/config/linux/riscv/headers.txt
@@ -71,5 +71,8 @@ set(TARGET_PUBLIC_HEADERS
)
if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
- list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+ list(APPEND TARGET_PUBLIC_HEADERS
+ libc.include.regex
+ libc.include.sys_ptrace
+ )
endif()
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index d5cac45df36f9..0bf88f504cd3c 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1508,6 +1508,10 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
libc.src.regex.regexec
libc.src.regex.regerror
libc.src.regex.regfree
+
+ # sys/ptrace.h entrypoints
+ libc.src.sys.ptrace.ptrace
+
# wchar.h entrypoints
libc.src.wchar.swprintf
)
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 59bcda72ef9bd..8b88ded158ebe 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -77,5 +77,8 @@ set(TARGET_PUBLIC_HEADERS
)
if(LLVM_LIBC_FULL_BUILD AND LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
- list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+ list(APPEND TARGET_PUBLIC_HEADERS
+ libc.include.regex
+ libc.include.sys_ptrace
+ )
endif()
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 8f00f875614f3..fcb3cbaa3f01b 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -715,6 +715,15 @@ add_header_macro(
.llvm_libc_common_h
)
+add_header_macro(
+ sys_ptrace
+ ../libc/include/sys/ptrace.yaml
+ sys/ptrace.h
+ DEPENDS
+ .llvm_libc_common_h
+ .llvm-libc-macros.sys_ptrace_macros
+)
+
add_header(
sys_queue
HDR
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 5574f44cab21c..892f2a8b5b198 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -225,6 +225,12 @@ add_macro_header(
sys-auxv-macros.h
)
+add_macro_header(
+ sys_ptrace_macros
+ HDR
+ sys-ptrace-macros.h
+)
+
add_macro_header(
sys_epoll_macros
HDR
diff --git a/libc/include/llvm-libc-macros/sys-ptrace-macros.h b/libc/include/llvm-libc-macros/sys-ptrace-macros.h
new file mode 100644
index 0000000000000..dd5c024ef7c8c
--- /dev/null
+++ b/libc/include/llvm-libc-macros/sys-ptrace-macros.h
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Definition of macros from sys/ptrace.h.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_SYS_PTRACE_MACROS_H
+#define LLVM_LIBC_MACROS_SYS_PTRACE_MACROS_H
+
+#define PTRACE_TRACEME 0
+#define PT_TRACE_ME PTRACE_TRACEME
+
+#endif // LLVM_LIBC_MACROS_SYS_PTRACE_MACROS_H
diff --git a/libc/include/sys/ptrace.yaml b/libc/include/sys/ptrace.yaml
new file mode 100644
index 0000000000000..b45ea0ec7f6c9
--- /dev/null
+++ b/libc/include/sys/ptrace.yaml
@@ -0,0 +1,19 @@
+header: sys/ptrace.h
+standards:
+ - linux
+macros:
+ - macro_name: PTRACE_TRACEME
+ macro_header: sys-ptrace-macros.h
+ - macro_name: PT_TRACE_ME
+ macro_header: sys-ptrace-macros.h
+types: []
+enums: []
+objects: []
+functions:
+ - name: ptrace
+ standards:
+ - linux
+ return_type: long
+ arguments:
+ - type: int
+ - type: '...'
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 02dfbfdcb49fb..c82c0a0d0393d 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -347,6 +347,18 @@ add_header_library(
libc.include.sys_syscall
)
+add_header_library(
+ ptrace
+ HDRS
+ ptrace.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
add_header_library(
utimensat
HDRS
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/ptrace.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/ptrace.h
new file mode 100644
index 0000000000000..db3328119e058
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/ptrace.h
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for ptrace.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PTRACE_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PTRACE_H
+
+#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<long> ptrace(int request) {
+ return syscall_checked<long>(SYS_ptrace, request);
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PTRACE_H
diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt
index 585b8f7b158eb..69e96c0e1705b 100644
--- a/libc/src/sys/CMakeLists.txt
+++ b/libc/src/sys/CMakeLists.txt
@@ -15,5 +15,6 @@ add_subdirectory(time)
add_subdirectory(utsname)
add_subdirectory(wait)
add_subdirectory(prctl)
+add_subdirectory(ptrace)
add_subdirectory(uio)
add_subdirectory(ioctl)
diff --git a/libc/src/sys/ptrace/CMakeLists.txt b/libc/src/sys/ptrace/CMakeLists.txt
new file mode 100644
index 0000000000000..7bb93a20e6ba4
--- /dev/null
+++ b/libc/src/sys/ptrace/CMakeLists.txt
@@ -0,0 +1,10 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+ ptrace
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.ptrace
+)
diff --git a/libc/src/sys/ptrace/linux/CMakeLists.txt b/libc/src/sys/ptrace/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..927c4a93102e5
--- /dev/null
+++ b/libc/src/sys/ptrace/linux/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_entrypoint_object(
+ ptrace
+ SRCS
+ ptrace.cpp
+ HDRS
+ ../ptrace.h
+ DEPENDS
+ libc.include.sys_ptrace
+ libc.src.__support.OSUtil.linux.syscall_wrappers.ptrace
+ libc.src.errno.errno
+)
diff --git a/libc/src/sys/ptrace/linux/ptrace.cpp b/libc/src/sys/ptrace/linux/ptrace.cpp
new file mode 100644
index 0000000000000..5675ebacddee2
--- /dev/null
+++ b/libc/src/sys/ptrace/linux/ptrace.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux implementation of the ptrace function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/ptrace/ptrace.h"
+
+#include "src/__support/OSUtil/linux/syscall_wrappers/ptrace.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long, ptrace, (int request, ...)) {
+ // TODO: Handle request arguments.
+ auto result = linux_syscalls::ptrace(request);
+
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+
+ return result.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/ptrace/ptrace.h b/libc/src/sys/ptrace/ptrace.h
new file mode 100644
index 0000000000000..e66005d71599a
--- /dev/null
+++ b/libc/src/sys/ptrace/ptrace.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for ptrace.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_PTRACE_PTRACE_H
+#define LLVM_LIBC_SRC_SYS_PTRACE_PTRACE_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+long ptrace(int request, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_PTRACE_PTRACE_H
diff --git a/libc/test/integration/src/sys/CMakeLists.txt b/libc/test/integration/src/sys/CMakeLists.txt
index 9a6b3cd220e86..3b7845b86a936 100644
--- a/libc/test/integration/src/sys/CMakeLists.txt
+++ b/libc/test/integration/src/sys/CMakeLists.txt
@@ -1 +1,2 @@
+add_subdirectory(ptrace)
add_subdirectory(sem)
diff --git a/libc/test/integration/src/sys/ptrace/CMakeLists.txt b/libc/test/integration/src/sys/ptrace/CMakeLists.txt
new file mode 100644
index 0000000000000..b4bbe81c92ff2
--- /dev/null
+++ b/libc/test/integration/src/sys/ptrace/CMakeLists.txt
@@ -0,0 +1,3 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${LIBC_TARGET_OS})
+endif()
diff --git a/libc/test/integration/src/sys/ptrace/linux/CMakeLists.txt b/libc/test/integration/src/sys/ptrace/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..83768523de781
--- /dev/null
+++ b/libc/test/integration/src/sys/ptrace/linux/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_custom_target(sys-ptrace-integration-tests)
+add_dependencies(libc-integration-tests sys-ptrace-integration-tests)
+
+add_integration_test(
+ ptrace_test
+ SUITE
+ sys-ptrace-integration-tests
+ SRCS
+ ptrace_test.cpp
+ DEPENDS
+ libc.include.sys_ptrace
+ libc.hdr.signal_macros
+ libc.src.sys.ptrace.ptrace
+ libc.src.unistd.fork
+ libc.src.signal.raise
+ libc.src.signal.kill
+ libc.src.sys.wait.waitpid
+ libc.src.stdlib.exit
+ libc.src.errno.errno
+)
diff --git a/libc/test/integration/src/sys/ptrace/linux/ptrace_test.cpp b/libc/test/integration/src/sys/ptrace/linux/ptrace_test.cpp
new file mode 100644
index 0000000000000..542c0a6936e82
--- /dev/null
+++ b/libc/test/integration/src/sys/ptrace/linux/ptrace_test.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Integration test for ptrace.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/signal_macros.h"
+#include "src/signal/kill.h"
+#include "src/signal/raise.h"
+#include "src/stdlib/exit.h"
+#include "src/sys/ptrace/ptrace.h"
+#include "src/sys/wait/waitpid.h"
+#include "src/unistd/fork.h"
+#include "test/IntegrationTest/test.h"
+#include <errno.h>
+#include <sys/ptrace.h>
+
+void trace_me_test() {
+ pid_t pid = LIBC_NAMESPACE::fork();
+ ASSERT_TRUE(pid >= 0);
+
+ if (pid == 0) {
+ // Child process
+ long ret = LIBC_NAMESPACE::ptrace(PTRACE_TRACEME, 0, nullptr, nullptr);
+ if (ret != 0)
+ LIBC_NAMESPACE::internal::exit(errno);
+ LIBC_NAMESPACE::raise(SIGSTOP);
+ LIBC_NAMESPACE::internal::exit(0);
+ }
+
+ // Parent process
+ int status;
+ pid_t wait_ret = LIBC_NAMESPACE::waitpid(pid, &status, 0);
+ ASSERT_EQ(wait_ret, pid);
+ ASSERT_TRUE(WIFSTOPPED(status));
+ ASSERT_EQ(WSTOPSIG(status), SIGSTOP);
+
+ // Kill the child
+ ASSERT_EQ(LIBC_NAMESPACE::kill(pid, SIGKILL), 0);
+ wait_ret = LIBC_NAMESPACE::waitpid(pid, &status, 0);
+ ASSERT_EQ(wait_ret, pid);
+ ASSERT_TRUE(WIFSIGNALED(status));
+ ASSERT_EQ(WTERMSIG(status), SIGKILL);
+}
+
+void errno_test() {
+ errno = 0;
+ ASSERT_EQ(LIBC_NAMESPACE::ptrace(-1, 0, nullptr, nullptr), -1L);
+ ASSERT_ERRNO_EQ(ESRCH);
+}
+
+TEST_MAIN() {
+ trace_me_test();
+ errno_test();
+ return 0;
+}
More information about the libc-commits
mailing list