How to detect if the current process is being run by GDB? How to detect if the current process is being run by GDB? linux linux

How to detect if the current process is being run by GDB?


On windows there is an API IsDebuggerPresent to check if process is under debugging. At linux, we can check this with another way (Not so efficient).

Check "/proc/self/status" for "TracerPid" attribute.

Example code:

#include <sys/stat.h>#include <string.h>#include <fcntl.h>#include <unistd.h>#include <ctype.h>bool debuggerIsAttached(){    char buf[4096];    const int status_fd = ::open("/proc/self/status", O_RDONLY);    if (status_fd == -1)        return false;    const ssize_t num_read = ::read(status_fd, buf, sizeof(buf) - 1);    ::close(status_fd);    if (num_read <= 0)        return false;    buf[num_read] = '\0';    constexpr char tracerPidString[] = "TracerPid:";    const auto tracer_pid_ptr = ::strstr(buf, tracerPidString);    if (!tracer_pid_ptr)        return false;    for (const char* characterPtr = tracer_pid_ptr + sizeof(tracerPidString) - 1; characterPtr <= buf + num_read; ++characterPtr)    {        if (::isspace(*characterPtr))            continue;        else            return ::isdigit(*characterPtr) != 0 && *characterPtr != '0';    }    return false;}


The code I ended up using was the following:

intgdb_check(){  int pid = fork();  int status;  int res;  if (pid == -1)    {      perror("fork");      return -1;    }  if (pid == 0)    {      int ppid = getppid();      /* Child */      if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0)        {          /* Wait for the parent to stop and continue it */          waitpid(ppid, NULL, 0);          ptrace(PTRACE_CONT, NULL, NULL);          /* Detach */          ptrace(PTRACE_DETACH, getppid(), NULL, NULL);          /* We were the tracers, so gdb is not present */          res = 0;        }      else        {          /* Trace failed so gdb is present */          res = 1;        }      exit(res);    }  else    {      waitpid(pid, &status, 0);      res = WEXITSTATUS(status);    }  return res;}

A few things:

  • When ptrace(PTRACE_ATTACH, ...) is successful, the traced process will stop and has to be continued.
  • This also works when gdb is attaching later.
  • A drawback is that when used frequently, it will cause a serious slowdown.
  • Also, this solution is only confirmed to work on Linux. As the comments mentioned, it won't work on BSD.

Anyway, thanks for the answers.


Previously as a comment: you could fork a child which would try to PTRACE_ATTACH its parent (and then detach if necessary) and communicates the result back. It does seem a bit inelegant though.

As you mention, this is quite costly. I guess it's not too bad if assertions fail irregularly. Perhaps it'd be worthwhile keeping a single long-running child around to do this - share two pipes between the parent and the child, child does its check when it reads a byte and then sends a byte back with the status.