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" |
sewardj | 2c48c7b | 2005-11-29 13:05:56 +0000 | [diff] [blame] | 39 | #include "pub_core_libcassert.h" |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 40 | #include "pub_core_options.h" |
| 41 | |
sewardj | ccc89d9 | 2005-11-09 14:43:03 +0000 | [diff] [blame] | 42 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 43 | #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f) |
| 44 | #define WSTOPSIG(status) (((status) & 0xff00) >> 8) |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 45 | |
| 46 | static Int ptrace_setregs(Int pid, VexGuestArchState* vex) |
| 47 | { |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 48 | #if defined(VGA_x86) |
sewardj | c9e73dc | 2005-11-09 15:14:16 +0000 | [diff] [blame] | 49 | struct vki_user_regs_struct regs; |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 50 | regs.cs = vex->guest_CS; |
| 51 | regs.ss = vex->guest_SS; |
| 52 | regs.ds = vex->guest_DS; |
| 53 | regs.es = vex->guest_ES; |
| 54 | regs.fs = vex->guest_FS; |
| 55 | regs.gs = vex->guest_GS; |
| 56 | regs.eax = vex->guest_EAX; |
| 57 | regs.ebx = vex->guest_EBX; |
| 58 | regs.ecx = vex->guest_ECX; |
| 59 | regs.edx = vex->guest_EDX; |
| 60 | regs.esi = vex->guest_ESI; |
| 61 | regs.edi = vex->guest_EDI; |
| 62 | regs.ebp = vex->guest_EBP; |
| 63 | regs.esp = vex->guest_ESP; |
| 64 | regs.eflags = LibVEX_GuestX86_get_eflags(vex); |
| 65 | regs.eip = vex->guest_EIP; |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 66 | return VG_(ptrace)(VKI_PTRACE_SETREGS, pid, NULL, ®s); |
sewardj | c9e73dc | 2005-11-09 15:14:16 +0000 | [diff] [blame] | 67 | |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 68 | #elif defined(VGA_amd64) |
sewardj | c9e73dc | 2005-11-09 15:14:16 +0000 | [diff] [blame] | 69 | struct vki_user_regs_struct regs; |
tom | e4fed1c | 2005-07-19 18:19:48 +0000 | [diff] [blame] | 70 | regs.rax = vex->guest_RAX; |
| 71 | regs.rbx = vex->guest_RBX; |
| 72 | regs.rcx = vex->guest_RCX; |
| 73 | regs.rdx = vex->guest_RDX; |
| 74 | regs.rsi = vex->guest_RSI; |
| 75 | regs.rdi = vex->guest_RDI; |
| 76 | regs.rbp = vex->guest_RBP; |
| 77 | regs.rsp = vex->guest_RSP; |
| 78 | regs.r8 = vex->guest_R8; |
| 79 | regs.r9 = vex->guest_R9; |
| 80 | regs.r10 = vex->guest_R10; |
| 81 | regs.r11 = vex->guest_R11; |
| 82 | regs.r12 = vex->guest_R12; |
| 83 | regs.r13 = vex->guest_R13; |
| 84 | regs.r14 = vex->guest_R14; |
| 85 | regs.r15 = vex->guest_R15; |
| 86 | regs.eflags = LibVEX_GuestAMD64_get_rflags(vex); |
| 87 | regs.rip = vex->guest_RIP; |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 88 | return VG_(ptrace)(VKI_PTRACE_SETREGS, pid, NULL, ®s); |
sewardj | c9e73dc | 2005-11-09 15:14:16 +0000 | [diff] [blame] | 89 | |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 90 | #elif defined(VGA_ppc32) |
tom | 0109322 | 2005-11-09 08:52:56 +0000 | [diff] [blame] | 91 | Int rc = 0; |
sewardj | c9e73dc | 2005-11-09 15:14:16 +0000 | [diff] [blame] | 92 | /* apparently the casting to void* is the Right Thing To Do */ |
| 93 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R0 * 4), (void*)vex->guest_GPR0); |
| 94 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R1 * 4), (void*)vex->guest_GPR1); |
| 95 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R2 * 4), (void*)vex->guest_GPR2); |
| 96 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R3 * 4), (void*)vex->guest_GPR3); |
| 97 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R4 * 4), (void*)vex->guest_GPR4); |
| 98 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R5 * 4), (void*)vex->guest_GPR5); |
| 99 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R6 * 4), (void*)vex->guest_GPR6); |
| 100 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R7 * 4), (void*)vex->guest_GPR7); |
| 101 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R8 * 4), (void*)vex->guest_GPR8); |
| 102 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R9 * 4), (void*)vex->guest_GPR9); |
| 103 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R10 * 4), (void*)vex->guest_GPR10); |
| 104 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R11 * 4), (void*)vex->guest_GPR11); |
| 105 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R12 * 4), (void*)vex->guest_GPR12); |
| 106 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R13 * 4), (void*)vex->guest_GPR13); |
| 107 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R14 * 4), (void*)vex->guest_GPR14); |
| 108 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R15 * 4), (void*)vex->guest_GPR15); |
| 109 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R16 * 4), (void*)vex->guest_GPR16); |
| 110 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R17 * 4), (void*)vex->guest_GPR17); |
| 111 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R18 * 4), (void*)vex->guest_GPR18); |
| 112 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R19 * 4), (void*)vex->guest_GPR19); |
| 113 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R20 * 4), (void*)vex->guest_GPR20); |
| 114 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R21 * 4), (void*)vex->guest_GPR21); |
| 115 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R22 * 4), (void*)vex->guest_GPR22); |
| 116 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R23 * 4), (void*)vex->guest_GPR23); |
| 117 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R24 * 4), (void*)vex->guest_GPR24); |
| 118 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R25 * 4), (void*)vex->guest_GPR25); |
| 119 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R26 * 4), (void*)vex->guest_GPR26); |
| 120 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R27 * 4), (void*)vex->guest_GPR27); |
| 121 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R28 * 4), (void*)vex->guest_GPR28); |
| 122 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R29 * 4), (void*)vex->guest_GPR29); |
| 123 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R30 * 4), (void*)vex->guest_GPR30); |
| 124 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_R31 * 4), (void*)vex->guest_GPR31); |
| 125 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_NIP * 4), (void*)vex->guest_CIA); |
| 126 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_CCR * 4), |
| 127 | (void*)LibVEX_GuestPPC32_get_CR(vex)); |
| 128 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_LNK * 4), (void*)vex->guest_LR); |
| 129 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_CTR * 4), (void*)vex->guest_CTR); |
| 130 | rc |= VG_(ptrace)(VKI_PTRACE_POKEUSR, pid, (void*)(VKI_PT_XER * 4), |
| 131 | (void*)LibVEX_GuestPPC32_get_XER(vex)); |
tom | 0109322 | 2005-11-09 08:52:56 +0000 | [diff] [blame] | 132 | return rc; |
sewardj | c9e73dc | 2005-11-09 15:14:16 +0000 | [diff] [blame] | 133 | |
sewardj | 2c48c7b | 2005-11-29 13:05:56 +0000 | [diff] [blame] | 134 | #elif defined(VGA_ppc64) |
| 135 | I_die_here; |
| 136 | |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 137 | #else |
| 138 | # error Unknown arch |
| 139 | #endif |
| 140 | } |
| 141 | |
| 142 | /* Start debugger and get it to attach to this process. Called if the |
| 143 | user requests this service after an error has been shown, so she can |
| 144 | poke around and look at parameters, memory, etc. You can't |
| 145 | meaningfully get the debugger to continue the program, though; to |
| 146 | continue, quit the debugger. */ |
| 147 | void VG_(start_debugger) ( ThreadId tid ) |
| 148 | { |
sewardj | 7289274 | 2005-12-18 03:22:50 +0000 | [diff] [blame] | 149 | # define N_BUF 4096 |
| 150 | Int pid; |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 151 | |
sewardj | 7289274 | 2005-12-18 03:22:50 +0000 | [diff] [blame] | 152 | if ((pid = VG_(fork)()) == 0) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 153 | VG_(ptrace)(VKI_PTRACE_TRACEME, 0, NULL, NULL); |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 154 | VG_(kill)(VG_(getpid)(), VKI_SIGSTOP); |
| 155 | |
| 156 | } else if (pid > 0) { |
| 157 | Int status; |
| 158 | Int res; |
| 159 | |
| 160 | if ((res = VG_(waitpid)(pid, &status, 0)) == pid && |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 161 | WIFSTOPPED(status) && WSTOPSIG(status) == VKI_SIGSTOP && |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 162 | ptrace_setregs(pid, &(VG_(threads)[tid].arch.vex)) == 0 && |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 163 | VG_(kill)(pid, VKI_SIGSTOP) == 0 && |
| 164 | VG_(ptrace)(VKI_PTRACE_DETACH, pid, NULL, 0) == 0) |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 165 | { |
| 166 | Char pidbuf[15]; |
sewardj | 7289274 | 2005-12-18 03:22:50 +0000 | [diff] [blame] | 167 | Char file[50]; |
| 168 | Char buf[N_BUF]; |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 169 | Char *bufptr; |
| 170 | Char *cmdptr; |
| 171 | |
| 172 | VG_(sprintf)(pidbuf, "%d", pid); |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 173 | VG_(sprintf)(file, "/proc/%d/fd/%d", pid, VG_(cl_exec_fd)); |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 174 | |
| 175 | bufptr = buf; |
| 176 | cmdptr = VG_(clo_db_command); |
| 177 | |
| 178 | while (*cmdptr) { |
sewardj | 7289274 | 2005-12-18 03:22:50 +0000 | [diff] [blame] | 179 | /* each iteration can advance bufptr by at most the length |
| 180 | of file[], so the following assertion is generously |
| 181 | over-paranoid. */ |
| 182 | vg_assert(bufptr - buf < N_BUF-15-50-10/*paranoia*/); |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 183 | switch (*cmdptr) { |
| 184 | case '%': |
| 185 | switch (*++cmdptr) { |
| 186 | case 'f': |
| 187 | VG_(memcpy)(bufptr, file, VG_(strlen)(file)); |
| 188 | bufptr += VG_(strlen)(file); |
| 189 | cmdptr++; |
| 190 | break; |
sewardj | 7289274 | 2005-12-18 03:22:50 +0000 | [diff] [blame] | 191 | case 'p': |
| 192 | VG_(memcpy)(bufptr, pidbuf, VG_(strlen)(pidbuf)); |
| 193 | bufptr += VG_(strlen)(pidbuf); |
| 194 | cmdptr++; |
| 195 | break; |
| 196 | default: |
| 197 | *bufptr++ = *cmdptr++; |
| 198 | break; |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 199 | } |
| 200 | break; |
| 201 | default: |
| 202 | *bufptr++ = *cmdptr++; |
| 203 | break; |
| 204 | } |
sewardj | 7289274 | 2005-12-18 03:22:50 +0000 | [diff] [blame] | 205 | vg_assert(bufptr - buf < N_BUF-15-50-10/*paranoia*/); |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 206 | } |
| 207 | |
| 208 | *bufptr++ = '\0'; |
| 209 | |
| 210 | VG_(message)(Vg_UserMsg, "starting debugger with cmd: %s", buf); |
| 211 | res = VG_(system)(buf); |
| 212 | if (res == 0) { |
| 213 | VG_(message)(Vg_UserMsg, ""); |
| 214 | VG_(message)(Vg_UserMsg, |
| 215 | "Debugger has detached. Valgrind regains control. We continue."); |
| 216 | } else { |
| 217 | VG_(message)(Vg_UserMsg, "Apparently failed!"); |
| 218 | VG_(message)(Vg_UserMsg, ""); |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | VG_(kill)(pid, VKI_SIGKILL); |
| 223 | VG_(waitpid)(pid, &status, 0); |
| 224 | } |
sewardj | 7289274 | 2005-12-18 03:22:50 +0000 | [diff] [blame] | 225 | # undef N_BUF |
njn | 75b65aa | 2005-06-19 19:25:44 +0000 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | |
| 229 | |
| 230 | /*--------------------------------------------------------------------*/ |
| 231 | /*--- end ---*/ |
| 232 | /*--------------------------------------------------------------------*/ |