1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include <__config>
11#include <array>
12#include <debugging>
13#include <fcntl.h>
14#include <string_view>
15#include <unistd.h>
16
17_LIBCPP_BEGIN_NAMESPACE_STD
18
19_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
20
21[[gnu::weak]] bool is_debugger_present() noexcept {
22 // https://docs.kernel.org/filesystems/proc.html
23 alignas(8) array<char, 256 + 1> __buffer{};
24 constexpr std::string_view __tracer_key("\nTracerPid:\t"); // Linux >= 2.6.0
25
26 int __buf_read = ::open(file: "/proc/self/status", O_RDONLY | O_CLOEXEC);
27 const auto __result = ::read(fd: __buf_read, buf: __buffer.data(), nbytes: __buffer.size() - 1);
28 ::close(fd: __buf_read);
29
30 if (__result < 80) {
31 return false;
32 }
33
34 // skip process name block
35 std::string_view __view(__buffer.data() + 64, __result - 64);
36 auto __tracerpid = __view.find(s: __tracer_key);
37
38 if (__tracerpid == std::string_view::npos) {
39 return false;
40 }
41
42 __view.remove_prefix(n: __tracerpid); // Remove everything upto \nTracerPid:\t
43 __view.remove_prefix(n: __tracer_key.size()); // remove \nTracerPid:\t
44
45 const auto __pidn = __view.find(c: '\n');
46 if (__pidn == std::string_view::npos) {
47 return false;
48 }
49
50 const std::string_view __pid = __view.substr(pos: 0, n: __pidn); // remove '\n'
51
52 if (__pid[0] == '0') {
53 return false;
54 }
55
56 auto __copied = std::string_view("/proc/").copy(s: __buffer.data(), n: __buffer.size());
57 __copied += __pid.copy(s: __buffer.data() + __copied, n: __buffer.size() - __copied);
58 __copied += std::string_view("/comm").copy(s: __buffer.data() + __copied, n: __buffer.size() - __copied);
59 __buffer[__copied] = '\0';
60
61 const int __tracer_read = ::open(file: __buffer.data(), O_RDONLY | O_CLOEXEC); // Linux >= 2.6.33
62 // https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L325
63 const auto __tracer_result = ::read(fd: __tracer_read, buf: __buffer.data(), nbytes: 16 + 1);
64 ::close(fd: __tracer_read);
65
66 if (__tracer_result <= 0) {
67 return false;
68 }
69
70 const std::string_view __tracer_name(
71 __buffer.data(), __tracer_result - 1); // remove newline from /proc/xyz/comm content
72
73 // Sniff for known debuggers
74 for (auto __i : {"gdb", "gdbserver", "lldb-server"}) {
75 if (__tracer_name.starts_with(s: __i)) {
76 return true;
77 }
78 }
79
80 return false;
81}
82
83_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
84
85_LIBCPP_END_NAMESPACE_STD
86