#ifdef HAVE_CONFIG_H # include "config.h" #endif #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) #include #include #include #include #include #include #include #endif #if defined(__OpenBSD__) # include # include # include #endif #if defined(__linux__) # include # include # include #endif #include #include #include #include "edi_debug.h" #include "edi_process.h" #include "edi_config.h" #include "edi_private.h" Edi_Debug_Tool _debugger_tools[] = { { "gdb", "gdb", NULL, "run\n", "c\n", "set args %s\n", "set prompt\n"}, { "lldb", "lldb", NULL, "run\n", "c\n", "settings set target.run-args %s", NULL }, { "pdb", "pdb", NULL, NULL, "c\n", "run %s", NULL }, { "memcheck", "valgrind", "--tool=memcheck", NULL, NULL, NULL, NULL }, { "massif", "valgrind", "--tool=massif", NULL, NULL, NULL, NULL }, { "callgrind", "valgrind", "--tool=callgrind", NULL, NULL, NULL, NULL }, { "Mono Debug", "mono", "--debug", NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, }; Edi_Debug *_debugger = NULL; Edi_Debug *edi_debug_new(void) { _debugger = calloc(1, sizeof(Edi_Debug)); return _debugger; } Edi_Debug *edi_debug_get(void) { return _debugger; } Edi_Debug_Tool *edi_debug_tools_get(void) { return _debugger_tools; } Edi_Debug_Tool *edi_debug_tool_get(const char *name) { int i; for (i = 0; _debugger_tools[i].name && name; i++) { if (!strcmp(_debugger_tools[i].name, name) && ecore_file_app_installed(_debugger_tools[i].exec)) return &_debugger_tools[i]; } // Fallback, but not installed. if (name || !ecore_file_app_installed(_debugger_tools[0].exec)) return NULL; // Fallback to first. return &_debugger_tools[0]; } static int _system_pid_max_get(void) { static int pid_max = 0; if (pid_max > 0) return pid_max; #if defined(__linux__) FILE *f; char buf[128]; size_t n; f = fopen("/proc/sys/kernel/pid_max", "r"); if (f) { n = fread(buf, 1, sizeof(buf) - 1, f); buf[n] = 0x00; fclose(f); pid_max = atoi(buf); } #elif defined(PID_MAX) pid_max = PID_MAX; #endif if (pid_max <= 0) pid_max = 99999; return pid_max; } int _edi_debug_process_id_fallback(Edi_Debug *debugger) { Edi_Proc_Stats *p; int pid_max, debugger_pid, child_pid = -1; debugger_pid = ecore_exe_pid_get(debugger->exe); pid_max = _system_pid_max_get(); for (int i = 1; i <= pid_max; i++) { p = edi_process_stats_by_pid(i); if (!p) continue; if (p->ppid == debugger_pid) { if (!strcmp(debugger->program_name, p->command)) { child_pid = p->pid; if (!strcmp(p->state, "RUN") ||!strcmp(p->state, "SLEEP")) debugger->state = EDI_DEBUG_PROCESS_ACTIVE; else debugger->state = EDI_DEBUG_PROCESS_SLEEPING; } } free(p); if (child_pid != -1) break; } return child_pid; } /* Get the process ID of the child process being debugged in *our* session */ int edi_debug_process_id(Edi_Debug *debugger) { Edi_Proc_Stats *p; int debugger_pid, child_pid = -1; if (!debugger) return -1; if (!debugger->program_name) return -1; if (!debugger->exe) return -1; debugger_pid = ecore_exe_pid_get(debugger->exe); #if defined(__linux__) DIR *dir; struct dirent *dh; dir = opendir("/proc"); if (!dir) return -1; while ((dh = readdir(dir))) { const char *c = dh->d_name; while (*c) { if (!isdigit(*c)) break; ++c; } if (*c) continue; p = edi_process_stats_by_pid(atoi(dh->d_name)); if (!p) continue; if (p->ppid == debugger_pid) { if (!strcmp(debugger->program_name, p->command)) { child_pid = p->pid; if (!strcmp(p->state, "RUN") ||!strcmp(p->state, "SLEEP")) debugger->state = EDI_DEBUG_PROCESS_ACTIVE; else debugger->state = EDI_DEBUG_PROCESS_SLEEPING; } } free(p); if (child_pid != -1) break; } closedir(dir); return child_pid; #elif defined(__OpenBSD__) kvm_t *kern; struct kinfo_proc *kp; char errbuf[_POSIX2_LINE_MAX]; int pid_count; kern = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); if (!kern) return -1; kp = kvm_getprocs(kern, KERN_PROC_ALL, 0, sizeof(*kp), &pid_count); if (!kp) return -1; for (int i = 0; i < pid_count; i++) { p = edi_process_stats_by_pid(kp[i].p_pid); if (!p) continue; if (p->ppid == debugger_pid) { if (!strcmp(debugger->program_name, p->command)) { child_pid = p->pid; if (!strcmp(p->state, "RUN") ||!strcmp(p->state, "SLEEP")) debugger->state = EDI_DEBUG_PROCESS_ACTIVE; else debugger->state = EDI_DEBUG_PROCESS_SLEEPING; } } free(p); if (child_pid != -1) break; } kvm_close(kern); return child_pid; #elif defined(__FreeBSD__) || defined(__DragonFly__) kvm_t *kern; struct kinfo_proc *kp; char errbuf[_POSIX2_LINE_MAX]; int pid_count; kern = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); if (!kern) { // Most likely we don't have READ access to /dev/mem. return _edi_debug_process_id_fallback(debugger); } kp = kvm_getprocs(kern, KERN_PROC_PROC, 0, &pid_count); if (!kp) return -1; for (int i = 0; i < pid_count; i++) { p = edi_process_stats_by_pid(kp[i].ki_pid); if (!p) continue; if (p->ppid == debugger_pid) { if (!strcmp(debugger->program_name, p->command)) { child_pid = p->pid; if (!strcmp(p->state, "RUN") ||!strcmp(p->state, "SLEEP")) debugger->state = EDI_DEBUG_PROCESS_ACTIVE; else debugger->state = EDI_DEBUG_PROCESS_SLEEPING; } } free(p); if (child_pid != -1) break; } kvm_close(kern); return child_pid; #endif return _edi_debug_process_id_fallback(debugger); }