diff --git a/coregrind/vg_errcontext.c b/coregrind/vg_errcontext.c index c1935efe8..892502ff7 100644 --- a/coregrind/vg_errcontext.c +++ b/coregrind/vg_errcontext.c @@ -253,21 +253,8 @@ void do_actions_on_error(Error* err, Bool allow_GDB_attach) if (allow_GDB_attach && VG_(is_action_requested)( "Attach to GDB", & VG_(clo_GDB_attach) )) { - Addr m_eip, m_esp, m_ebp; - - if (VG_(is_running_thread)( err->tid )) { - m_eip = VG_(baseBlock)[VGOFF_(m_eip)]; - m_esp = VG_(baseBlock)[VGOFF_(m_esp)]; - m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)]; - } else { - ThreadState* tst = & VG_(threads)[ err->tid ]; - m_eip = tst->m_eip; - m_esp = tst->m_esp; - m_ebp = tst->m_ebp; - } - VG_(printf)("starting gdb with eip=%p esp=%p ebp=%p\n", - m_eip, m_esp, m_ebp); - VG_(swizzle_esp_then_start_GDB)( m_eip, m_esp, m_ebp ); + VG_(printf)("starting gdb\n"); + VG_(start_GDB)( err->tid ); } /* Or maybe we want to generate the error's suppression? */ if (VG_(is_action_requested)( "Print suppression", diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index 4dc5b8c98..36fc10af7 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -1450,11 +1450,8 @@ extern Addr VG_(sysinfo_page_addr); which match pattern. */ extern void VG_(mash_colon_env)(Char *varp, const Char *pattern); -/* Something of a function looking for a home ... start up GDB. This - is called from VG_(swizzle_esp_then_start_GDB) and so runs on the - *client's* stack. This is necessary to give GDB the illusion that - the client program really was running on the real cpu. */ -extern void VG_(start_GDB_whilst_on_client_stack) ( void ); +/* Something of a function looking for a home ... start up GDB. */ +extern void VG_(start_GDB) ( Int tid ); /* VG_(bbs_done) in include/vg_skin.h */ @@ -1682,11 +1679,6 @@ extern Int VG_(clone) ( Int (*fn)(void *), void *stack, Int flags, void *arg, extern void VG_(switch_to_real_CPU) ( void ); -extern void VG_(swizzle_esp_then_start_GDB) ( Addr m_eip_at_error, - Addr m_esp_at_error, - Addr m_ebp_at_error ); - - /* --------------------------------------------------------------------- Exports of vg_dispatch.S ------------------------------------------------------------------ */ diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index ee26d20f3..b1a74a4b0 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -31,6 +31,13 @@ #include "vg_include.h" +#include +#include +#include +#include +#include +#include + /* --------------------------------------------------------------------- Compute offsets into baseBlock. See comments in vg_include.h. ------------------------------------------------------------------ */ @@ -1745,27 +1752,86 @@ void VG_(mash_colon_env)(Char *varp, const Char *remove_pattern) *output++ = '\0'; } -/* RUNS ON THE CLIENT'S STACK, but on the real CPU. Start GDB and get - it to attach to this process. Called if the user requests this - service after an error has been shown, so she can poke around and - look at parameters, memory, etc. You can't meaningfully get GDB to - continue the program, though; to continue, quit GDB. */ -void VG_(start_GDB_whilst_on_client_stack) ( void ) +/* Start GDB and get it to attach to this process. Called if the user + requests this service after an error has been shown, so she can + poke around and look at parameters, memory, etc. You can't + meaningfully get GDB to continue the program, though; to continue, + quit GDB. */ +void VG_(start_GDB) ( Int tid ) { - Int res; - UChar buf[100]; + Int pid; - VG_(sprintf)(buf, "%s -nw /proc/%d/fd/%d %d", - VG_(clo_GDB_path), VG_(getpid)(), VG_(clexecfd), VG_(getpid)()); - VG_(message)(Vg_UserMsg, "starting GDB with cmd: %s", buf); - res = VG_(system)(buf); - if (res == 0) { - VG_(message)(Vg_UserMsg, ""); - VG_(message)(Vg_UserMsg, - "GDB has detached. Valgrind regains control. We continue."); - } else { - VG_(message)(Vg_UserMsg, "Apparently failed!"); - VG_(message)(Vg_UserMsg, ""); + if ((pid = fork()) == 0) + { + ptrace(PTRACE_TRACEME, 0, NULL, NULL); + VG_(kkill)(VG_(getpid)(), VKI_SIGSTOP); + } + else if (pid > 0) + { + struct user_regs_struct regs; + Int status; + Int res; + + if (VG_(is_running_thread)( tid )) { + regs.xcs = VG_(baseBlock)[VGOFF_(m_cs)]; + regs.xss = VG_(baseBlock)[VGOFF_(m_ss)]; + regs.xds = VG_(baseBlock)[VGOFF_(m_ds)]; + regs.xes = VG_(baseBlock)[VGOFF_(m_es)]; + regs.xfs = VG_(baseBlock)[VGOFF_(m_fs)]; + regs.xgs = VG_(baseBlock)[VGOFF_(m_gs)]; + regs.eax = VG_(baseBlock)[VGOFF_(m_eax)]; + regs.ebx = VG_(baseBlock)[VGOFF_(m_ebx)]; + regs.ecx = VG_(baseBlock)[VGOFF_(m_ecx)]; + regs.edx = VG_(baseBlock)[VGOFF_(m_edx)]; + regs.esi = VG_(baseBlock)[VGOFF_(m_esi)]; + regs.edi = VG_(baseBlock)[VGOFF_(m_edi)]; + regs.ebp = VG_(baseBlock)[VGOFF_(m_ebp)]; + regs.esp = VG_(baseBlock)[VGOFF_(m_esp)]; + regs.eflags = VG_(baseBlock)[VGOFF_(m_eflags)]; + regs.eip = VG_(baseBlock)[VGOFF_(m_eip)]; + } else { + ThreadState* tst = & VG_(threads)[ tid ]; + + regs.xcs = tst->m_cs; + regs.xss = tst->m_ss; + regs.xds = tst->m_ds; + regs.xes = tst->m_es; + regs.xfs = tst->m_fs; + regs.xgs = tst->m_gs; + regs.eax = tst->m_eax; + regs.ebx = tst->m_ebx; + regs.ecx = tst->m_ecx; + regs.edx = tst->m_edx; + regs.esi = tst->m_esi; + regs.edi = tst->m_edi; + regs.ebp = tst->m_ebp; + regs.esp = tst->m_esp; + regs.eflags = tst->m_eflags; + regs.eip = tst->m_eip; + } + + if ((res = VG_(waitpid)(pid, &status, 0)) == pid && + WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP && + ptrace(PTRACE_SETREGS, pid, NULL, ®s) == 0 && + ptrace(PTRACE_DETACH, pid, NULL, SIGSTOP) == 0) { + UChar buf[VG_(strlen)(VG_(clo_GDB_path)) + 100]; + + VG_(sprintf)(buf, "%s -nw /proc/%d/fd/%d %d", + VG_(clo_GDB_path), VG_(main_pid), VG_(clexecfd), pid); + VG_(message)(Vg_UserMsg, "starting GDB with cmd: %s", buf); + res = VG_(system)(buf); + if (res == 0) { + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, + "GDB has detached. Valgrind regains control. We continue."); + } else { + VG_(message)(Vg_UserMsg, "Apparently failed!"); + VG_(message)(Vg_UserMsg, ""); + } + } + + VG_(kkill)(pid, VKI_SIGKILL); + VG_(waitpid)(pid, &status, 0); } } diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c index f8b510c3e..204ebeabc 100644 --- a/coregrind/vg_signals.c +++ b/coregrind/vg_signals.c @@ -1392,8 +1392,7 @@ static void vg_default_action(const vki_ksiginfo_t *info, ThreadId tid) } if (VG_(is_action_requested)( "Attach to GDB", & VG_(clo_GDB_attach) )) { - ThreadState* tst = & VG_(threads)[ tid ]; - VG_(swizzle_esp_then_start_GDB)( tst->m_eip, tst->m_esp, tst->m_ebp ); + VG_(start_GDB)( tid ); } if (VG_(fatal_signal_set)) { diff --git a/coregrind/vg_startup.S b/coregrind/vg_startup.S index b96c9151d..c2d60f631 100644 --- a/coregrind/vg_startup.S +++ b/coregrind/vg_startup.S @@ -80,88 +80,6 @@ qq4merge: -/*------------------------------------------------------------*/ -/*--- A function to temporarily copy %ESP/%EBP into ---*/ -/*--- %esp/%ebp and then start up GDB. ---*/ -/*------------------------------------------------------------*/ - -/* -extern void VG_(swizzle_esp_then_start_GDB) ( Addr m_eip_at_error, - Addr m_esp_at_error, - Addr m_ebp_at_error ); -*/ - -/*--- This is clearly not re-entrant! ---*/ -.data -vg_ebp_saved_over_GDB_start: - .long 0 -vg_esp_saved_over_GDB_start: - .long 0 -.text - -.type VG_(swizzle_esp_then_start_GDB),@function -.global VG_(swizzle_esp_then_start_GDB) -VG_(swizzle_esp_then_start_GDB): -#ifdef HAVE_GAS_CFI - .cfi_startproc -#endif - pushal - - # remember the simulators current stack/frame pointers - movl %ebp, vg_ebp_saved_over_GDB_start - movl %esp, vg_esp_saved_over_GDB_start - - # get args into regs - movl 44(%esp), %eax # client %EBP - movl 40(%esp), %ebx # client %ESP - movl 36(%esp), %ecx # client %EIP - - # Now that we dont need to refer to simulators stack any more, - # put %ESP into %esp - movl %ebx, %esp - - ### %esp now refers to clients stack - ### mess with the clients stack to make it look as if it - ### called this procedure, since otherwise it will look to gdb - ### as if the top (currently executing) stack frame of the - ### client is missing. - - # push %EIP. This is a faked-up return address. - pushl %ecx - - # push %EBP. This is a faked %ebp-chain pointer. - pushl %eax -#ifdef HAVE_GAS_CFI - .cfi_adjust_cfa_offset 0x4 -#endif - - movl %esp, %ebp -#ifdef HAVE_GAS_CFI - .cfi_def_cfa_register ebp -#endif - - call VG_(start_GDB_whilst_on_client_stack) - - # restore the simulators stack/frame pointer - movl vg_ebp_saved_over_GDB_start, %ebp - movl vg_esp_saved_over_GDB_start, %esp -#ifdef HAVE_GAS_CFI - .cfi_adjust_cfa_offset -0x4 -#endif - - popal - ret -#ifdef HAVE_GAS_CFI - .cfi_endproc -#endif - -# gcc puts this construction at the end of every function. I think it -# allows the linker to figure out the size of the function. So we do -# the same, in the vague hope that it might help GDBs navigation. -.Lend_of_swizzle: - .size VG_(swizzle_esp_then_start_GDB), .Lend_of_swizzle-VG_(swizzle_esp_then_start_GDB) - - ##--------------------------------------------------------------------## ##--- end vg_startup.S ---## ##--------------------------------------------------------------------##