blob: 742785a1cc641b1c583e9b26ea90ecb33b76824d [file] [log] [blame]
Juan Cespedesf1bfe202002-03-27 00:22:23 +01001#include "config.h"
Juan Cespedesf1bfe202002-03-27 00:22:23 +01002
3#include <sys/types.h>
4#include <sys/wait.h>
5#include <signal.h>
6#include <sys/ptrace.h>
7#include <asm/ptrace.h>
Ian Wienand9a2ad352006-02-20 22:44:45 +01008#include <elf.h>
Luis Machado55c5feb2008-03-12 15:56:01 +01009#include <errno.h>
Petr Machatafac99be2010-10-25 13:39:28 +020010#include <string.h>
Juan Cespedesf1bfe202002-03-27 00:22:23 +010011
Petr Machata366c2f42012-02-09 19:34:36 +010012#include "proc.h"
Juan Cespedesf7281232009-06-25 16:11:21 +020013#include "common.h"
Petr Machatafac99be2010-10-25 13:39:28 +020014#include "ptrace.h"
Petr Machata9e1e9692012-04-19 02:29:38 +020015#include "breakpoint.h"
Juan Cespedesf1bfe202002-03-27 00:22:23 +010016
17#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
18# define PTRACE_PEEKUSER PTRACE_PEEKUSR
19#endif
20
21#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
22# define PTRACE_POKEUSER PTRACE_POKEUSR
23#endif
24
Juan Cespedesf1350522008-12-16 18:19:58 +010025void
Juan Cespedesa8909f72009-04-28 20:02:41 +020026get_arch_dep(Process *proc) {
Petr Machatafac99be2010-10-25 13:39:28 +020027 if (proc->arch_ptr == NULL) {
28 proc->arch_ptr = malloc(sizeof(proc_archdep));
Ian Wienand9a2ad352006-02-20 22:44:45 +010029#ifdef __powerpc64__
Petr Machatafac99be2010-10-25 13:39:28 +020030 proc->mask_32bit = (proc->e_machine == EM_PPC);
Ian Wienand9a2ad352006-02-20 22:44:45 +010031#endif
Petr Machatafac99be2010-10-25 13:39:28 +020032 }
33
34 proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
35 a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0)
36 && (ptrace(PTRACE_GETFPREGS, proc->pid, 0, &a->fpregs) >= 0);
Juan Cespedes5c3fe062004-06-14 18:08:37 +020037}
38
Juan Cespedesf1bfe202002-03-27 00:22:23 +010039#define SYSCALL_INSN 0x44000002
Luis Machado55c5feb2008-03-12 15:56:01 +010040
41unsigned int greg = 3;
42unsigned int freg = 1;
Luis Machado55c5feb2008-03-12 15:56:01 +010043
Petr Machatafac99be2010-10-25 13:39:28 +020044/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */
Juan Cespedesf1350522008-12-16 18:19:58 +010045int
Juan Cespedesa8909f72009-04-28 20:02:41 +020046syscall_p(Process *proc, int status, int *sysnum) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010047 if (WIFSTOPPED(status)
48 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
Ian Wienand9a2ad352006-02-20 22:44:45 +010049 long pc = (long)get_instruction_pointer(proc);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010050 int insn =
51 (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long),
52 0);
Juan Cespedesf1bfe202002-03-27 00:22:23 +010053
54 if (insn == SYSCALL_INSN) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010055 *sysnum =
56 (int)ptrace(PTRACE_PEEKUSER, proc->pid,
57 sizeof(long) * PT_R0, 0);
Juan Cespedes3e94cbf2009-05-22 19:12:07 +020058 if (proc->callstack_depth > 0 &&
59 proc->callstack[proc->callstack_depth - 1].is_syscall &&
60 proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) {
Juan Cespedesf1bfe202002-03-27 00:22:23 +010061 return 2;
62 }
Juan Cespedes5bfb0612002-03-31 20:01:28 +020063 return 1;
Juan Cespedesf1bfe202002-03-27 00:22:23 +010064 }
65 }
66 return 0;
67}
68
Petr Machatafac99be2010-10-25 13:39:28 +020069static long
70gimme_arg_regset(enum tof type, Process *proc, int arg_num, arg_type_info *info,
71 gregset_t *regs, fpregset_t *fpregs)
72{
73 union { long val; float fval; double dval; } cvt;
Luis Machado55c5feb2008-03-12 15:56:01 +010074
75 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
76 if (freg <= 13 || (proc->mask_32bit && freg <= 8)) {
Petr Machata87e1a5c2010-11-18 11:19:09 +010077 double val = GET_FPREG(*fpregs, freg);
Luis Machado55c5feb2008-03-12 15:56:01 +010078
Petr Machatafac99be2010-10-25 13:39:28 +020079 if (info->type == ARGTYPE_FLOAT)
80 cvt.fval = val;
81 else
82 cvt.dval = val;
Luis Machado55c5feb2008-03-12 15:56:01 +010083
84 freg++;
85 greg++;
86
Petr Machatafac99be2010-10-25 13:39:28 +020087 return cvt.val;
Luis Machado55c5feb2008-03-12 15:56:01 +010088 }
89 }
Petr Machatafac99be2010-10-25 13:39:28 +020090 else if (greg <= 10)
91 return (*regs)[greg++];
Andreas Schwabe276cf42011-05-08 16:25:41 +020092 else {
93#ifdef __powerpc64__
94 if (proc->mask_32bit)
95 return ptrace (PTRACE_PEEKDATA, proc->pid,
96 proc->stack_pointer + 8 +
97 sizeof (int) * (arg_num - 8), 0) >> 32;
98 else
99 return ptrace (PTRACE_PEEKDATA, proc->pid,
100 proc->stack_pointer + 112 +
101 sizeof (long) * (arg_num - 8), 0);
102#else
Luis Machado55c5feb2008-03-12 15:56:01 +0100103 return ptrace (PTRACE_PEEKDATA, proc->pid,
Andreas Schwabe276cf42011-05-08 16:25:41 +0200104 proc->stack_pointer + 8 +
105 sizeof (long) * (arg_num - 8), 0);
106#endif
107 }
Luis Machado55c5feb2008-03-12 15:56:01 +0100108
Juan Cespedesf1bfe202002-03-27 00:22:23 +0100109 return 0;
110}
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200111
Petr Machatafac99be2010-10-25 13:39:28 +0200112static long
113gimme_retval(Process *proc, int arg_num, arg_type_info *info,
114 gregset_t *regs, fpregset_t *fpregs)
115{
116 union { long val; float fval; double dval; } cvt;
117 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
Petr Machata87e1a5c2010-11-18 11:19:09 +0100118 double val = GET_FPREG(*fpregs, 1);
Petr Machatafac99be2010-10-25 13:39:28 +0200119
120 if (info->type == ARGTYPE_FLOAT)
121 cvt.fval = val;
122 else
123 cvt.dval = val;
124
125 return cvt.val;
126 }
127 else
128 return (*regs)[3];
129}
130
131/* Grab functions arguments based on the PPC64 ABI. */
132long
133gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info)
134{
135 proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
136 if (arch == NULL || !arch->valid)
137 return -1;
138
139 /* Check if we're entering a new function call to list parameters. If
140 so, initialize the register control variables to keep track of where
141 the parameters were stored. */
142 if ((type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR)
143 && arg_num == 0) {
144 /* Initialize the set of registrers for parameter passing. */
145 greg = 3;
146 freg = 1;
147 }
148
149
150 if (type == LT_TOF_FUNCTIONR) {
151 if (arg_num == -1)
152 return gimme_retval(proc, arg_num, info,
153 &arch->regs, &arch->fpregs);
154 else
155 return gimme_arg_regset(type, proc, arg_num, info,
156 &arch->regs_copy,
157 &arch->fpregs_copy);
158 }
159 else
160 return gimme_arg_regset(type, proc, arg_num, info,
161 &arch->regs, &arch->fpregs);
162}
163
Juan Cespedesf1350522008-12-16 18:19:58 +0100164void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200165save_register_args(enum tof type, Process *proc) {
Petr Machatafac99be2010-10-25 13:39:28 +0200166 proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
167 if (arch == NULL || !arch->valid)
168 return;
169
170 memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs));
171 memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs));
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200172}
Luis Machado55c5feb2008-03-12 15:56:01 +0100173
174/* Read a single long from the process's memory address 'addr'. */
Juan Cespedesf1350522008-12-16 18:19:58 +0100175int
Juan Cespedesa8909f72009-04-28 20:02:41 +0200176arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
Luis Machado55c5feb2008-03-12 15:56:01 +0100177 long pointed_to;
178
179 errno = 0;
180
181 pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
182
183 if (pointed_to == -1 && errno)
184 return -errno;
185
Michael K. Edwards9bc4a9b2011-03-06 17:20:11 +0000186#if SIZEOF_LONG == 8
Luis Machado55c5feb2008-03-12 15:56:01 +0100187 /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we
188 need to shift the long values returned by ptrace to end up with
189 the correct value. */
190
191 if (info) {
192 if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER
193 || info->type == ARGTYPE_STRING))) {
Michael K. Edwards9bc4a9b2011-03-06 17:20:11 +0000194 pointed_to = (long) (((unsigned long) pointed_to) >> 32);
Luis Machado55c5feb2008-03-12 15:56:01 +0100195 }
196 }
Michael K. Edwards9bc4a9b2011-03-06 17:20:11 +0000197#endif
Luis Machado55c5feb2008-03-12 15:56:01 +0100198
199 *result = pointed_to;
200 return 0;
201}
Petr Machataa266acb2012-04-12 23:50:23 +0200202
203/* The atomic skip code is mostly taken from GDB. */
204
205/* Instruction masks used during single-stepping of atomic
206 * sequences. This was lifted from GDB. */
207#define LWARX_MASK 0xfc0007fe
208#define LWARX_INSTRUCTION 0x7c000028
209#define LDARX_INSTRUCTION 0x7c0000A8
210#define STWCX_MASK 0xfc0007ff
211#define STWCX_INSTRUCTION 0x7c00012d
212#define STDCX_INSTRUCTION 0x7c0001ad
213#define BC_MASK 0xfc000000
Petr Machata42748ac2012-04-19 04:24:25 +0200214#define BC_INSN 0x40000000
215#define BRANCH_MASK 0xfc000000
216
217/* In plt.h. XXX make this official interface. */
218int read_target_4(struct Process *proc, target_address_t addr, uint32_t *lp);
Petr Machataa266acb2012-04-12 23:50:23 +0200219
220int
Petr Machata9e1e9692012-04-19 02:29:38 +0200221arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
Petr Machataa266acb2012-04-12 23:50:23 +0200222 int (*add_cb)(void *addr, void *data),
223 void *add_cb_data)
224{
Petr Machata42748ac2012-04-19 04:24:25 +0200225 target_address_t ip = get_instruction_pointer(proc);
226 struct breakpoint *other = address2bpstruct(proc->leader, ip);
227
228 debug(1, "arch_atomic_singlestep pid=%d addr=%p %s(%p)",
229 proc->pid, ip, breakpoint_name(sbp), sbp->addr);
Petr Machataa266acb2012-04-12 23:50:23 +0200230
231 /* If the original instruction was lwarx/ldarx, we can't
232 * single-step over it, instead we have to execute the whole
233 * atomic block at once. */
234 union {
235 uint32_t insn;
Petr Machata42748ac2012-04-19 04:24:25 +0200236 char buf[BREAKPOINT_LENGTH];
Petr Machataa266acb2012-04-12 23:50:23 +0200237 } u;
Petr Machata42748ac2012-04-19 04:24:25 +0200238 if (other != NULL) {
239 memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH);
240 } else if (read_target_4(proc, ip, &u.insn) < 0) {
241 fprintf(stderr, "couldn't read instruction at IP %p\n", ip);
242 /* Do the normal singlestep. */
243 return 1;
244 }
Petr Machataa266acb2012-04-12 23:50:23 +0200245
246 if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION
247 && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION)
248 return 1;
249
Petr Machata42748ac2012-04-19 04:24:25 +0200250 debug(1, "singlestep over atomic block at %p", ip);
251
Petr Machataa266acb2012-04-12 23:50:23 +0200252 int insn_count;
Petr Machata42748ac2012-04-19 04:24:25 +0200253 target_address_t addr = ip;
Petr Machataa266acb2012-04-12 23:50:23 +0200254 for (insn_count = 0; ; ++insn_count) {
255 addr += 4;
256 unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
257 if (l == (unsigned long)-1 && errno)
258 return -1;
259 uint32_t insn;
260#ifdef __powerpc64__
261 insn = l >> 32;
262#else
263 insn = l;
264#endif
265
Petr Machata42748ac2012-04-19 04:24:25 +0200266 /* If a conditional branch is found, put a breakpoint
267 * in its destination address. */
268 if ((insn & BRANCH_MASK) == BC_INSN) {
269 int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
270 int absolute = insn & 2;
271
272 /* XXX drop the following casts. */
273 target_address_t branch_addr;
274 if (absolute)
275 branch_addr = (void *)(uintptr_t)immediate;
276 else
277 branch_addr = addr + (uintptr_t)immediate;
278
279 debug(1, "pid=%d, branch in atomic block from %p to %p",
280 proc->pid, addr, branch_addr);
281 if (add_cb(branch_addr, add_cb_data) < 0)
282 return -1;
Petr Machataa266acb2012-04-12 23:50:23 +0200283 }
284
Petr Machata42748ac2012-04-19 04:24:25 +0200285 /* Assume that the atomic sequence ends with a
286 * stwcx/stdcx instruction. */
Petr Machataa266acb2012-04-12 23:50:23 +0200287 if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
288 || (insn & STWCX_MASK) == STDCX_INSTRUCTION) {
Petr Machata42748ac2012-04-19 04:24:25 +0200289 debug(1, "pid=%d, found end of atomic block %p at %p",
290 proc->pid, ip, addr);
Petr Machataa266acb2012-04-12 23:50:23 +0200291 break;
292 }
293
294 /* Arbitrary cut-off. If we didn't find the
295 * terminating instruction by now, just give up. */
296 if (insn_count > 16) {
Petr Machata42748ac2012-04-19 04:24:25 +0200297 fprintf(stderr, "[%d] couldn't find end of atomic block"
298 " at %p\n", proc->pid, ip);
Petr Machataa266acb2012-04-12 23:50:23 +0200299 return -1;
300 }
301 }
302
303 /* Put the breakpoint to the next instruction. */
304 addr += 4;
305 if (add_cb(addr, add_cb_data) < 0)
306 return -1;
307
308 debug(1, "PTRACE_CONT");
309 ptrace(PTRACE_CONT, proc->pid, 0, 0);
310 return 0;
311}