njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- Attaching a debugger. m_debugger.c ---*/ |
| 4 | /*--------------------------------------------------------------------*/ |
| 5 | |
| 6 | /* |
| 7 | This file is part of Valgrind, a dynamic binary instrumentation |
| 8 | framework. |
| 9 | |
| 10 | Copyright (C) 2000-2005 Julian Seward |
| 11 | jseward@acm.org |
| 12 | |
| 13 | This program is free software; you can redistribute it and/or |
| 14 | modify it under the terms of the GNU General Public License as |
| 15 | published by the Free Software Foundation; either version 2 of the |
| 16 | License, or (at your option) any later version. |
| 17 | |
| 18 | This program is distributed in the hope that it will be useful, but |
| 19 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 21 | General Public License for more details. |
| 22 | |
| 23 | You should have received a copy of the GNU General Public License |
| 24 | along with this program; if not, write to the Free Software |
| 25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 26 | 02111-1307, USA. |
| 27 | |
| 28 | The GNU General Public License is contained in the file COPYING. |
| 29 | */ |
| 30 | |
| 31 | #include "pub_core_basics.h" |
| 32 | #include "pub_core_threadstate.h" |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 33 | #include "pub_core_clientstate.h" |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 34 | #include "pub_core_debugger.h" |
| 35 | #include "pub_core_libcbase.h" |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 36 | #include "pub_core_libcprint.h" |
| 37 | #include "pub_core_libcproc.h" |
| 38 | #include "pub_core_libcsignal.h" |
| 39 | #include "pub_core_options.h" |
| 40 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 41 | #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f) |
| 42 | #define WSTOPSIG(status) (((status) & 0xff00) >> 8) |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 43 | |
| 44 | static Int ptrace_setregs(Int pid, VexGuestArchState* vex) |
| 45 | { |
| 46 | struct vki_user_regs_struct regs; |
| 47 | #if defined(VGA_x86) |
| 48 | regs.cs = vex->guest_CS; |
| 49 | regs.ss = vex->guest_SS; |
| 50 | regs.ds = vex->guest_DS; |
| 51 | regs.es = vex->guest_ES; |
| 52 | regs.fs = vex->guest_FS; |
| 53 | regs.gs = vex->guest_GS; |
| 54 | regs.eax = vex->guest_EAX; |
| 55 | regs.ebx = vex->guest_EBX; |
| 56 | regs.ecx = vex->guest_ECX; |
| 57 | regs.edx = vex->guest_EDX; |
| 58 | regs.esi = vex->guest_ESI; |
| 59 | regs.edi = vex->guest_EDI; |
| 60 | regs.ebp = vex->guest_EBP; |
| 61 | regs.esp = vex->guest_ESP; |
| 62 | regs.eflags = LibVEX_GuestX86_get_eflags(vex); |
| 63 | regs.eip = vex->guest_EIP; |
| 64 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 65 | return VG_(ptrace)(VKI_PTRACE_SETREGS, pid, NULL, ®s); |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 66 | #elif defined(VGA_amd64) |
tom | e4fed1c | 2005-07-19 18:19:48 +0000 | [diff] [blame] | 67 | regs.rax = vex->guest_RAX; |
| 68 | regs.rbx = vex->guest_RBX; |
| 69 | regs.rcx = vex->guest_RCX; |
| 70 | regs.rdx = vex->guest_RDX; |
| 71 | regs.rsi = vex->guest_RSI; |
| 72 | regs.rdi = vex->guest_RDI; |
| 73 | regs.rbp = vex->guest_RBP; |
| 74 | regs.rsp = vex->guest_RSP; |
| 75 | regs.r8 = vex->guest_R8; |
| 76 | regs.r9 = vex->guest_R9; |
| 77 | regs.r10 = vex->guest_R10; |
| 78 | regs.r11 = vex->guest_R11; |
| 79 | regs.r12 = vex->guest_R12; |
| 80 | regs.r13 = vex->guest_R13; |
| 81 | regs.r14 = vex->guest_R14; |
| 82 | regs.r15 = vex->guest_R15; |
| 83 | regs.eflags = LibVEX_GuestAMD64_get_rflags(vex); |
| 84 | regs.rip = vex->guest_RIP; |
| 85 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 86 | return VG_(ptrace)(VKI_PTRACE_SETREGS, pid, NULL, ®s); |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 87 | #elif defined(VGA_ppc32) |
| 88 | I_die_here; |
| 89 | regs.gpr[0] = 0; // stop compiler complaints |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 90 | #else |
| 91 | # error Unknown arch |
| 92 | #endif |
| 93 | } |
| 94 | |
| 95 | /* Start debugger and get it to attach to this process. Called if the |
| 96 | user requests this service after an error has been shown, so she can |
| 97 | poke around and look at parameters, memory, etc. You can't |
| 98 | meaningfully get the debugger to continue the program, though; to |
| 99 | continue, quit the debugger. */ |
| 100 | void VG_(start_debugger) ( ThreadId tid ) |
| 101 | { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 102 | Int pid; |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 103 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 104 | if ((pid = VG_(fork)()) == 0) { |
| 105 | VG_(ptrace)(VKI_PTRACE_TRACEME, 0, NULL, NULL); |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 106 | VG_(kill)(VG_(getpid)(), VKI_SIGSTOP); |
| 107 | |
| 108 | } else if (pid > 0) { |
| 109 | Int status; |
| 110 | Int res; |
| 111 | |
| 112 | if ((res = VG_(waitpid)(pid, &status, 0)) == pid && |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 113 | WIFSTOPPED(status) && WSTOPSIG(status) == VKI_SIGSTOP && |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 114 | ptrace_setregs(pid, &(VG_(threads)[tid].arch.vex)) == 0 && |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 115 | VG_(kill)(pid, VKI_SIGSTOP) == 0 && |
| 116 | VG_(ptrace)(VKI_PTRACE_DETACH, pid, NULL, 0) == 0) |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 117 | { |
| 118 | Char pidbuf[15]; |
| 119 | Char file[30]; |
| 120 | Char buf[100]; |
| 121 | Char *bufptr; |
| 122 | Char *cmdptr; |
| 123 | |
| 124 | VG_(sprintf)(pidbuf, "%d", pid); |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame^] | 125 | VG_(sprintf)(file, "/proc/%d/fd/%d", pid, VG_(cl_exec_fd)); |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 126 | |
| 127 | bufptr = buf; |
| 128 | cmdptr = VG_(clo_db_command); |
| 129 | |
| 130 | while (*cmdptr) { |
| 131 | switch (*cmdptr) { |
| 132 | case '%': |
| 133 | switch (*++cmdptr) { |
| 134 | case 'f': |
| 135 | VG_(memcpy)(bufptr, file, VG_(strlen)(file)); |
| 136 | bufptr += VG_(strlen)(file); |
| 137 | cmdptr++; |
| 138 | break; |
| 139 | case 'p': |
| 140 | VG_(memcpy)(bufptr, pidbuf, VG_(strlen)(pidbuf)); |
| 141 | bufptr += VG_(strlen)(pidbuf); |
| 142 | cmdptr++; |
| 143 | break; |
| 144 | default: |
| 145 | *bufptr++ = *cmdptr++; |
| 146 | break; |
| 147 | } |
| 148 | break; |
| 149 | default: |
| 150 | *bufptr++ = *cmdptr++; |
| 151 | break; |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | *bufptr++ = '\0'; |
| 156 | |
| 157 | VG_(message)(Vg_UserMsg, "starting debugger with cmd: %s", buf); |
| 158 | res = VG_(system)(buf); |
| 159 | if (res == 0) { |
| 160 | VG_(message)(Vg_UserMsg, ""); |
| 161 | VG_(message)(Vg_UserMsg, |
| 162 | "Debugger has detached. Valgrind regains control. We continue."); |
| 163 | } else { |
| 164 | VG_(message)(Vg_UserMsg, "Apparently failed!"); |
| 165 | VG_(message)(Vg_UserMsg, ""); |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | VG_(kill)(pid, VKI_SIGKILL); |
| 170 | VG_(waitpid)(pid, &status, 0); |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | |
| 175 | |
| 176 | /*--------------------------------------------------------------------*/ |
| 177 | /*--- end ---*/ |
| 178 | /*--------------------------------------------------------------------*/ |