Skip to content

Commit

Permalink
Unify corerun's implementation of the native debugger check with the …
Browse files Browse the repository at this point in the history
…minipal for all platforms (#109599)

Co-authored-by: Adeel Mujahid <[email protected]>
  • Loading branch information
jkoritzinsky and am11 authored Nov 7, 2024
1 parent e133fe4 commit ce6d835
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 99 deletions.
16 changes: 9 additions & 7 deletions src/coreclr/hosts/corerun/corerun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// Runtime headers
#include <coreclrhost.h>
#include <corehost/host_runtime_contract.h>
#include <minipal/debugger.h>

#include "corerun.hpp"
#include "dotenv.hpp"
Expand Down Expand Up @@ -73,21 +74,22 @@ namespace envvar

static void wait_for_debugger()
{
pal::debugger_state_t state = pal::is_debugger_attached();
if (state == pal::debugger_state_t::na)
if (!minipal_can_check_for_native_debugger())
{
pal::fprintf(stdout, W("Debugger attach is not available on this platform\n"));
return;
}
else if (state == pal::debugger_state_t::not_attached)

bool attached = minipal_is_native_debugger_present();
if (!attached)
{
uint32_t pid = pal::get_process_id();
pal::fprintf(stdout, W("Waiting for the debugger to attach (PID: %u). Press any key to continue ...\n"), pid);
(void)getchar();
state = pal::is_debugger_attached();
attached = minipal_is_native_debugger_present();
}

if (state == pal::debugger_state_t::attached)
if (attached)
{
pal::fprintf(stdout, W("Debugger is attached.\n"));
}
Expand Down Expand Up @@ -247,9 +249,9 @@ static int run(const configuration& config)
// Check if debugger attach scenario was requested.
if (config.wait_to_debug)
wait_for_debugger();

config.dotenv_configuration.load_into_current_process();

string_t exe_path = pal::get_exe_path();

// Determine the managed application's path.
Expand Down
92 changes: 0 additions & 92 deletions src/coreclr/hosts/corerun/corerun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,11 @@ namespace pal

template<typename T>
using malloc_ptr = std::unique_ptr<T, free_delete>;

enum class debugger_state_t
{
na,
attached,
not_attached,
};
}

#ifdef TARGET_WINDOWS
#define CDECL __cdecl
#include <Windows.h>
#include <minipal/debugger.h>

#define DLL_EXPORT __declspec(dllexport)
#define MAIN __cdecl wmain
Expand Down Expand Up @@ -137,11 +129,6 @@ namespace pal
return (uint32_t)::GetCurrentProcessId();
}

inline debugger_state_t is_debugger_attached()
{
return (minipal_is_native_debugger_present() == TRUE) ? debugger_state_t::attached : debugger_state_t::not_attached;
}

inline bool does_file_exist(const string_t& file_path)
{
return INVALID_FILE_ATTRIBUTES != ::GetFileAttributesW(file_path.c_str());
Expand Down Expand Up @@ -421,85 +408,6 @@ namespace pal
return (uint32_t)getpid();
}

inline debugger_state_t is_debugger_attached()
{
#if defined(__APPLE__)
// Taken from https://developer.apple.com/library/archive/qa/qa1361/_index.html
int junk;
int mib[4];
struct kinfo_proc info;
size_t size;

// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.

info.kp_proc.p_flag = 0;

// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.

mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();

// Call sysctl.

size = sizeof(info);
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
assert(junk == 0);

// We're being debugged if the P_TRACED flag is set.

return ( (info.kp_proc.p_flag & P_TRACED) != 0 ) ? debugger_state_t::attached : debugger_state_t::not_attached;

#else // !__APPLE__
// Use procfs to detect if there is a tracer process.
// See https://www.kernel.org/doc/html/latest/filesystems/proc.html
char status[2048];
int fd = ::open("/proc/self/status", O_RDONLY);
if (fd == -1)
{
// If the file can't be opened assume we are on a not supported platform.
return debugger_state_t::na;
}

// Attempt to read
ssize_t bytes_read = ::read(fd, status, sizeof(status) - 1);
::close(fd);

if (bytes_read > 0)
{
// We have data. At this point we can likely make a strong decision.
const char tracer_pid_name[] = "TracerPid:";
// null terminate status
status[bytes_read] = '\0';
const char* tracer_pid_ptr = ::strstr(status, tracer_pid_name);
if (tracer_pid_ptr == nullptr)
return debugger_state_t::not_attached;

// The number after the name is the process ID of the
// tracer application or 0 if none exists.
const char* curr = tracer_pid_ptr + (sizeof(tracer_pid_name) - 1);
const char* end = status + bytes_read;
for (;curr < end; ++curr)
{
if (::isspace(*curr))
continue;

// Check the first non-space if it is 0. If so, we have
// a non-zero process ID and a tracer is attached.
return (::isdigit(*curr) && *curr != '0') ? debugger_state_t::attached : debugger_state_t::not_attached;
}
}

// The read in data is either incomplete (i.e. small buffer) or
// the returned content is not expected. Let's fallback to not available.
return debugger_state_t::na;

#endif // !__APPLE__
}

inline bool does_file_exist(const char_t* file_path)
{
// Check if the specified path exists
Expand Down
16 changes: 16 additions & 0 deletions src/native/minipal/debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,44 @@

#if defined(_WIN32)
#include <windows.h>
#define MINIPAL_DEBUGGER_PRESENT_CHECK
#elif defined(__linux__)
#include <stdio.h>
#define MINIPAL_DEBUGGER_PRESENT_CHECK
#elif defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/sysctl.h>
#include <sys/types.h>
#define MINIPAL_DEBUGGER_PRESENT_CHECK
#elif defined(__NetBSD__)
#include <kvm.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
#define MINIPAL_DEBUGGER_PRESENT_CHECK
#elif defined(__sun)
#include <fcntl.h>
#include <procfs.h>
#include <errno.h>
#define MINIPAL_DEBUGGER_PRESENT_CHECK
#elif defined(_AIX)
#include <sys/proc.h>
#include <sys/types.h>
#include <sys/procfs.h>
#define MINIPAL_DEBUGGER_PRESENT_CHECK
#elif defined(__HAIKU__)
#include <OS.h>
#define MINIPAL_DEBUGGER_PRESENT_CHECK
#endif

bool minipal_can_check_for_native_debugger(void)
{
#if defined(MINIPAL_DEBUGGER_PRESENT_CHECK)
return true;
#else
return false;
#endif
}

bool minipal_is_native_debugger_present(void)
{
#if defined(_WIN32)
Expand Down
7 changes: 7 additions & 0 deletions src/native/minipal/debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
extern "C" {
#endif

/**
* Check if the minipal can check for a native debugger.
*
* @return true if the minipal can check if a native debugger is attached, false otherwise.
*/
bool minipal_can_check_for_native_debugger(void);

/**
* Check if a native debugger is attached to the current process.
*
Expand Down

0 comments on commit ce6d835

Please sign in to comment.