| // -*- C++ -*- | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include <__config> | |
| #include <array> | |
| #include <debugging> | |
| #include <fcntl.h> | |
| #include <string_view> | |
| #include <unistd.h> | |
| _LIBCPP_BEGIN_NAMESPACE_STD | |
| _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS | |
| [[gnu::weak]] bool is_debugger_present() noexcept { | |
| // https://docs.kernel.org/filesystems/proc.html | |
| alignas(8) array<char, 256 + 1> __buffer{}; | |
| constexpr std::string_view __tracer_key("\nTracerPid:\t"); // Linux >= 2.6.0 | |
| int __buf_read = ::open("/proc/self/status", O_RDONLY | O_CLOEXEC); | |
| const auto __result = ::read(__buf_read, __buffer.data(), __buffer.size() - 1); | |
| ::close(__buf_read); | |
| if (__result < 80) { | |
| return false; | |
| } | |
| // skip process name block | |
| std::string_view __view(__buffer.data() + 64, __result - 64); | |
| auto __tracerpid = __view.find(__tracer_key); | |
| if (__tracerpid == std::string_view::npos) { | |
| return false; | |
| } | |
| __view.remove_prefix(__tracerpid); // Remove everything upto \nTracerPid:\t | |
| __view.remove_prefix(__tracer_key.size()); // remove \nTracerPid:\t | |
| const auto __pidn = __view.find('\n'); | |
| if (__pidn == std::string_view::npos) { | |
| return false; | |
| } | |
| const std::string_view __pid = __view.substr(0, __pidn); // remove '\n' | |
| if (__pid[0] == '0') { | |
| return false; | |
| } | |
| auto __copied = std::string_view("/proc/").copy(__buffer.data(), __buffer.size()); | |
| __copied += __pid.copy(__buffer.data() + __copied, __buffer.size() - __copied); | |
| __copied += std::string_view("/comm").copy(__buffer.data() + __copied, __buffer.size() - __copied); | |
| __buffer[__copied] = '\0'; | |
| const int __tracer_read = ::open(__buffer.data(), O_RDONLY | O_CLOEXEC); // Linux >= 2.6.33 | |
| // https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L325 | |
| const auto __tracer_result = ::read(__tracer_read, __buffer.data(), 16 + 1); | |
| ::close(__tracer_read); | |
| if (__tracer_result <= 0) { | |
| return false; | |
| } | |
| const std::string_view __tracer_name( | |
| __buffer.data(), __tracer_result - 1); // remove newline from /proc/xyz/comm content | |
| // Sniff for known debuggers | |
| for (auto __i : {"gdb", "gdbserver", "lldb-server"}) { | |
| if (__tracer_name.starts_with(__i)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| _LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS | |
| _LIBCPP_END_NAMESPACE_STD |