diff --git a/components/crashcatcher/crashcatcher.cpp b/components/crashcatcher/crashcatcher.cpp index 2e2ddd1f2..006b190ba 100644 --- a/components/crashcatcher/crashcatcher.cpp +++ b/components/crashcatcher/crashcatcher.cpp @@ -17,6 +17,7 @@ #include #include +#include namespace bfs = boost::filesystem; @@ -34,9 +35,13 @@ namespace bfs = boost::filesystem; #if defined(__APPLE__) #include +#include #endif -#define UNUSED(x) (void)(x) +#if defined(__FreeBSD__) +#include +#include +#endif static const char crash_switch[] = "--cc-handle-crash"; @@ -413,6 +418,39 @@ static void crash_handler(const char *logfile) exit(0); } +static void getExecPath(char **argv) +{ +#if defined (__FreeBSD__) + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + size_t size = sizeof(argv0); + + if (sysctl(mib, 4, argv0, &size, nullptr, 0) == 0) + return; +#endif + +#if defined (__APPLE__) + if(proc_pidpath(getpid(), argv0, sizeof(argv0)) > 0) + return; +#endif + int cwdlen; + const char *statusPaths[] = {"/proc/self/exe", "/proc/self/file", "/proc/curproc/exe", "/proc/curproc/file"}; + memset(argv0, 0, sizeof(argv0)); + + for(const char *path : statusPaths) + { + if (readlink(path, argv0, sizeof(argv0)) != -1) + return; + } + + if(argv[0][0] == '/') + snprintf(argv0, sizeof(argv0), "%s", argv[0]); + else if (getcwd(argv0, sizeof(argv0)) != NULL) + { + cwdlen = strlen(argv0); + snprintf(argv0+cwdlen, sizeof(argv0)-cwdlen, "/%s", argv[0]); + } +} + int crashCatcherInstallHandlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*)) { struct sigaction sa; @@ -424,20 +462,7 @@ int crashCatcherInstallHandlers(int argc, char **argv, int num_signals, int *sig cc_user_info = user_info; - if(argv[0][0] == '/') - snprintf(argv0, sizeof(argv0), "%s", argv[0]); - else - { - { - /* we don't want to disable "ignoring return value" warnings, so we make - * a special exception here. */ - char * unused; - unused = getcwd(argv0, sizeof(argv0)); - UNUSED(unused); - } - retval = strlen(argv0); - snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]); - } + getExecPath(argv); /* Set an alternate signal stack so SIGSEGVs caused by stack overflows * still run */ @@ -467,20 +492,24 @@ int crashCatcherInstallHandlers(int argc, char **argv, int num_signals, int *sig static bool is_debugger_present() { -#if !defined (__APPLE__) - bfs::ifstream file((bfs::path("/proc/self/status"))); - while (!file.eof()) +#if defined (__linux__) + bfs::path procstatus = bfs::path("/proc/self/status"); + if (bfs::exists(procstatus)) { - std::string word; - file >> word; - if (word == "TracerPid:") + bfs::ifstream file((procstatus)); + while (!file.eof()) { + std::string word; file >> word; - return word != "0"; + if (word == "TracerPid:") + { + file >> word; + return word != "0"; + } } } return false; -#else +#elif defined(__APPLE__) int junk; int mib[4]; struct kinfo_proc info; @@ -508,12 +537,24 @@ static bool is_debugger_present() // We're being debugged if the P_TRACED flag is set. return (info.kp_proc.p_flag & P_TRACED) != 0; +#elif defined(__FreeBSD__) + struct kinfo_proc info; + size_t size = sizeof(info); + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() }; + + if (sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) == 0) + return (info.ki_flag & P_TRACED) != 0; + else + perror("Failed to retrieve process info"); + return false; +#else + return false; #endif } void crashCatcherInstall(int argc, char **argv, const std::string &crashLogPath) { - if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_present()) + if ((argc == 2 && strcmp(argv[1], crash_switch) == 0) || !is_debugger_present()) { int s[5] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGABRT }; if (crashCatcherInstallHandlers(argc, argv, 5, s, crashLogPath.c_str(), nullptr) == -1)