$NetBSD$ --- src/arch/netbsd/async/debug.c.orig 2017-11-02 06:34:33.813702898 +0000 +++ src/arch/netbsd/async/debug.c @@ -0,0 +1,216 @@ +#include "emu.h" +#include "dosemu_config.h" +#include "debug.h" +#include "sig.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static FILE *gdb_f = NULL; + +static void gdb_command(char *cmd) +{ + printf("%s", cmd); + fflush(stdout); + fprintf(gdb_f, "%s", cmd); + fflush(gdb_f); +} + +static int start_gdb(pid_t dosemu_pid) +{ + char *buf; + int ret; + + printf("Debug info:\n"); + fflush(stdout); + + ret = asprintf(&buf, "gdb %s", dosemu_proc_self_exe); + assert(ret != -1); + + printf("%s", buf); + putchar('\n'); + fflush(stdout); + + if (!(gdb_f = popen(buf, "w"))) { + free(buf); + return 0; + } + free(buf); + + ret = asprintf(&buf, "attach %i\n", dosemu_pid); + assert(ret != -1); + + gdb_command(buf); + free(buf); + + return 1; +} + +static void do_debug(void) +{ + char *cmd1 = "info registers\n"; +// char *cmd2 = "backtrace\n"; + char *cmd3 = "thread apply all backtrace full\n"; + + gdb_command(cmd1); +// gdb_command(cmd2); + gdb_command(cmd3); +} + +static int stop_gdb(void) +{ + char *cmd1 = "detach\n"; + char *cmd2 = "quit\n"; + int status; + + gdb_command(cmd1); + gdb_command(cmd2); + wait(&status); + pclose(gdb_f); + putchar('\n'); + fflush(stdout); + return !WEXITSTATUS(status); +} + +/* disable as this crashes under DPMI trying to trace through DOS stack */ +/* ... and re-enable because people fuck up instead of installing gdb. + * But run this only if the gdb trace fails. */ +#if 1 +/* Obtain a backtrace and print it to `stdout'. + (derived from 'info libc') + */ +static void print_trace (void) +{ +#define MAX_FRAMES 256 + void *array[MAX_FRAMES]; + int size; + char **strings; + size_t i; + + size = backtrace (array, MAX_FRAMES); + strings = backtrace_symbols (array, size); + fprintf(dbg_fd, "Obtained %d stack frames.\n", size); + + for (i = 0; i < size; i++) + fprintf(dbg_fd, "%s\n", strings[i]); + + free (strings); + fprintf(dbg_fd, "Backtrace finished\n"); +} +#endif + +static void collect_info(pid_t pid) +{ + char *cmd0 = "ldd %s"; + char *cmd1 = "getconf GNU_LIBC_VERSION"; + char *cmd2 = "getconf GNU_LIBPTHREAD_VERSION"; + char *cmd3 = "cat /proc/%i/maps"; + char *tmp; + int ret; + + printf("System info:\n"); + fflush(stdout); + + ret = asprintf(&tmp, cmd0, dosemu_proc_self_exe); + assert(ret != -1); + + if(system(tmp)) { + printf("command '%s' failed\n", tmp); + } + free(tmp); + + if(system(cmd1)) { + printf("command '%s' failed\n", cmd1); + } + + if(system(cmd2)) { + printf("command '%s' failed\n", cmd2); + } + + ret = asprintf(&tmp, cmd3, pid); + assert(ret != -1); + + if(system(tmp)) { + printf("command '%s' failed\n", tmp); + } + free(tmp); + + fflush(stdout); +} + +static int do_gdb_debug(void) +{ + int ret = 0; + pid_t dosemu_pid = getpid(); + pid_t dbg_pid; + int status; + sigset_t set, oset; + + if (getuid() != geteuid()) + return 0; + + sigemptyset(&set); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + sigprocmask(SIG_BLOCK, &set, &oset); + switch ((dbg_pid = fork())) { + case 0: + ioselect_done(); + signal_done(); + sigprocmask(SIG_SETMASK, &oset, NULL); + + dup2(fileno(dbg_fd), STDOUT_FILENO); + dup2(fileno(dbg_fd), STDERR_FILENO); + + collect_info(dosemu_pid); + + if (!start_gdb(dosemu_pid)) + _exit(1); + do_debug(); + if (!stop_gdb()) + _exit(1); + _exit(0); + break; + case -1: + error("fork failed, %s\n", strerror(errno)); + break; + default: + waitpid(dbg_pid, &status, 0); + if (WEXITSTATUS(status)) { + dbug_printf("backtrace failure\n"); + } else { + ret = 1; + dbug_printf("done backtrace\n"); + } + break; + } + sigprocmask(SIG_SETMASK, &oset, NULL); + return ret; +} + +void gdb_debug(void) +{ + int ret = do_gdb_debug(); +#if 0 + if (!ret) { + print_trace(); + error("Please install gdb!\n"); + } +#else + /* the problem with the above is that gdb usually doesn't work + * because of the security restrictions */ + if (!ret) + error("Please install gdb!\n"); + print_trace(); +#endif + + fprintf(dbg_fd, "\n"); + fflush(dbg_fd); + dump_state(); +}