blob: 4a7a03dd747211b4e27079704295a082456123d4 [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
214#define BC_INSTRUCTION 0x40000000
215
216int
Petr Machata9e1e9692012-04-19 02:29:38 +0200217arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
Petr Machataa266acb2012-04-12 23:50:23 +0200218 int (*add_cb)(void *addr, void *data),
219 void *add_cb_data)
220{
221 void *addr = sbp->addr;
222 debug(1, "pid=%d addr=%p", proc->pid, addr);
223
224 /* If the original instruction was lwarx/ldarx, we can't
225 * single-step over it, instead we have to execute the whole
226 * atomic block at once. */
227 union {
228 uint32_t insn;
229 char buf[4];
230 } u;
231 memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH);
232
233 if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION
234 && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION)
235 return 1;
236
237 int insn_count;
238 for (insn_count = 0; ; ++insn_count) {
239 addr += 4;
240 unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
241 if (l == (unsigned long)-1 && errno)
242 return -1;
243 uint32_t insn;
244#ifdef __powerpc64__
245 insn = l >> 32;
246#else
247 insn = l;
248#endif
249
250 /* If we hit a branch instruction, give up. The
251 * computation could escape that way and we'd have to
252 * treat that case specially. */
253 if ((insn & BC_MASK) == BC_INSTRUCTION) {
254 debug(1, "pid=%d, found branch at %p, giving up",
255 proc->pid, addr);
256 return -1;
257 }
258
259 if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
260 || (insn & STWCX_MASK) == STDCX_INSTRUCTION) {
261 debug(1, "pid=%d, found end of atomic block at %p",
262 proc->pid, addr);
263 break;
264 }
265
266 /* Arbitrary cut-off. If we didn't find the
267 * terminating instruction by now, just give up. */
268 if (insn_count > 16) {
269 debug(1, "pid=%d, couldn't find end of atomic block",
270 proc->pid);
271 return -1;
272 }
273 }
274
275 /* Put the breakpoint to the next instruction. */
276 addr += 4;
277 if (add_cb(addr, add_cb_data) < 0)
278 return -1;
279
280 debug(1, "PTRACE_CONT");
281 ptrace(PTRACE_CONT, proc->pid, 0, 0);
282 return 0;
283}