blob: 8f6bc528214da1b43a123268e4d2b0c87cb5e451 [file] [log] [blame]
njn75b65aa2005-06-19 19:25:44 +00001
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"
33#include "pub_core_debugger.h"
34#include "pub_core_libcbase.h"
njn7e7d0062005-07-02 02:56:02 +000035#include "pub_core_libcassert.h" // For I_die_here
njn75b65aa2005-06-19 19:25:44 +000036#include "pub_core_libcprint.h"
37#include "pub_core_libcproc.h"
38#include "pub_core_libcsignal.h"
39#include "pub_core_options.h"
40
41// We can remove these easily by implementing our own VG_(ptrace)() and
42// VG_(fork)().
43#include <sys/ptrace.h>
44#include <sys/wait.h>
45#include <unistd.h>
46
47static Int ptrace_setregs(Int pid, VexGuestArchState* vex)
48{
49 struct vki_user_regs_struct regs;
50#if defined(VGA_x86)
51 regs.cs = vex->guest_CS;
52 regs.ss = vex->guest_SS;
53 regs.ds = vex->guest_DS;
54 regs.es = vex->guest_ES;
55 regs.fs = vex->guest_FS;
56 regs.gs = vex->guest_GS;
57 regs.eax = vex->guest_EAX;
58 regs.ebx = vex->guest_EBX;
59 regs.ecx = vex->guest_ECX;
60 regs.edx = vex->guest_EDX;
61 regs.esi = vex->guest_ESI;
62 regs.edi = vex->guest_EDI;
63 regs.ebp = vex->guest_EBP;
64 regs.esp = vex->guest_ESP;
65 regs.eflags = LibVEX_GuestX86_get_eflags(vex);
66 regs.eip = vex->guest_EIP;
67
68 return ptrace(PTRACE_SETREGS, pid, NULL, &regs);
69#elif defined(VGA_amd64)
tome4fed1c2005-07-19 18:19:48 +000070 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;
88
89 return ptrace(PTRACE_SETREGS, pid, NULL, &regs);
cerion85665ca2005-06-20 15:51:07 +000090#elif defined(VGA_ppc32)
91 I_die_here;
92 regs.gpr[0] = 0; // stop compiler complaints
njn75b65aa2005-06-19 19:25:44 +000093#else
94# error Unknown arch
95#endif
96}
97
98/* Start debugger and get it to attach to this process. Called if the
99 user requests this service after an error has been shown, so she can
100 poke around and look at parameters, memory, etc. You can't
101 meaningfully get the debugger to continue the program, though; to
102 continue, quit the debugger. */
103void VG_(start_debugger) ( ThreadId tid )
104{
105 Int pid;
106
107 if ((pid = fork()) == 0) {
108 ptrace(PTRACE_TRACEME, 0, NULL, NULL);
109 VG_(kill)(VG_(getpid)(), VKI_SIGSTOP);
110
111 } else if (pid > 0) {
112 Int status;
113 Int res;
114
115 if ((res = VG_(waitpid)(pid, &status, 0)) == pid &&
116 WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP &&
117 ptrace_setregs(pid, &(VG_(threads)[tid].arch.vex)) == 0 &&
118 VG_(kill)(pid, SIGSTOP) == 0 &&
119 ptrace(PTRACE_DETACH, pid, NULL, 0) == 0)
120 {
121 Char pidbuf[15];
122 Char file[30];
123 Char buf[100];
124 Char *bufptr;
125 Char *cmdptr;
126
127 VG_(sprintf)(pidbuf, "%d", pid);
128 VG_(sprintf)(file, "/proc/%d/fd/%d", pid, VG_(clexecfd));
129
130 bufptr = buf;
131 cmdptr = VG_(clo_db_command);
132
133 while (*cmdptr) {
134 switch (*cmdptr) {
135 case '%':
136 switch (*++cmdptr) {
137 case 'f':
138 VG_(memcpy)(bufptr, file, VG_(strlen)(file));
139 bufptr += VG_(strlen)(file);
140 cmdptr++;
141 break;
142 case 'p':
143 VG_(memcpy)(bufptr, pidbuf, VG_(strlen)(pidbuf));
144 bufptr += VG_(strlen)(pidbuf);
145 cmdptr++;
146 break;
147 default:
148 *bufptr++ = *cmdptr++;
149 break;
150 }
151 break;
152 default:
153 *bufptr++ = *cmdptr++;
154 break;
155 }
156 }
157
158 *bufptr++ = '\0';
159
160 VG_(message)(Vg_UserMsg, "starting debugger with cmd: %s", buf);
161 res = VG_(system)(buf);
162 if (res == 0) {
163 VG_(message)(Vg_UserMsg, "");
164 VG_(message)(Vg_UserMsg,
165 "Debugger has detached. Valgrind regains control. We continue.");
166 } else {
167 VG_(message)(Vg_UserMsg, "Apparently failed!");
168 VG_(message)(Vg_UserMsg, "");
169 }
170 }
171
172 VG_(kill)(pid, VKI_SIGKILL);
173 VG_(waitpid)(pid, &status, 0);
174 }
175}
176
177
178
179/*--------------------------------------------------------------------*/
180/*--- end ---*/
181/*--------------------------------------------------------------------*/