blob: 7fa3ed403f4ef1524bbd29dca9a7bd7bab8e52f8 [file] [log] [blame]
Petr Machatae99af272012-10-26 00:29:52 +02001/*
2 * This file is part of ltrace.
3 * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications
4 * Copyright (C) 2010 Arnaud Patard, Mandriva SA
5 * Copyright (C) 2008,2009 Juan Cespedes
6 * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 */
23
Eric Vaitl1228a912006-12-28 16:16:56 +010024#include "config.h"
Eric Vaitl1228a912006-12-28 16:16:56 +010025
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <signal.h>
29#include <sys/ptrace.h>
30#include <asm/ptrace.h>
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +020031#include <assert.h>
Petr Machata3b3b0d32012-09-01 00:28:54 +020032
33#include "backend.h"
Juan Cespedesf7281232009-06-25 16:11:21 +020034#include "common.h"
Petr Machata3b3b0d32012-09-01 00:28:54 +020035#include "debug.h"
Eric Vaitl1228a912006-12-28 16:16:56 +010036#include "mipsel.h"
Petr Machata3b3b0d32012-09-01 00:28:54 +020037#include "proc.h"
Petr Machata000e3112012-01-03 17:03:39 +010038#include "type.h"
Petr Machata3b3b0d32012-09-01 00:28:54 +020039
Eric Vaitl1228a912006-12-28 16:16:56 +010040#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
41# define PTRACE_PEEKUSER PTRACE_PEEKUSR
42#endif
43
44#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
45# define PTRACE_POKEUSER PTRACE_POKEUSR
46#endif
47
48
49/**
50 \addtogroup mipsel Mipsel specific functions.
51
52 These are the functions that it looks like I need to implement in
Juan Cespedesfea4a122009-05-28 16:53:43 +020053 order to get ltrace to work on our target.
Eric Vaitl1228a912006-12-28 16:16:56 +010054
55 @{
56 */
57
58/**
Juan Cespedesfea4a122009-05-28 16:53:43 +020059 \param proc The process that had an event.
Eric Vaitl1228a912006-12-28 16:16:56 +010060
Juan Cespedese2023f72009-04-07 12:12:08 +020061 Called by \c next_event() right after the return from wait.
Eric Vaitl1228a912006-12-28 16:16:56 +010062
63 Most targets just return here. A couple use proc->arch_ptr for a
64 private data area.
65 */
Juan Cespedesf1350522008-12-16 18:19:58 +010066void
Petr Machata929bd572012-12-17 03:20:34 +010067get_arch_dep(struct process *proc)
68{
Eric Vaitl1228a912006-12-28 16:16:56 +010069}
70
71/**
Juan Cespedesfea4a122009-05-28 16:53:43 +020072 \param proc Process that had event.
Eric Vaitl1228a912006-12-28 16:16:56 +010073 \param status From \c wait()
Juan Cespedesfea4a122009-05-28 16:53:43 +020074 \param sysnum 0-based syscall number.
Eric Vaitl1228a912006-12-28 16:16:56 +010075 \return 1 if syscall, 2 if sysret, 0 otherwise.
76
Juan Cespedese2023f72009-04-07 12:12:08 +020077 Called by \c next_event() after the call to get_arch_dep()
Eric Vaitl1228a912006-12-28 16:16:56 +010078
79 It seems that the ptrace call trips twice on a system call, once
80 just before the system call and once when it returns. Both times,
81 the pc points at the instruction just after the mipsel "syscall"
82 instruction.
83
84 There are several possiblities for system call sets, each is offset
85 by a base from the others. On our system, it looks like the base
86 for the system calls is 4000.
87 */
Juan Cespedesf1350522008-12-16 18:19:58 +010088int
Petr Machata929bd572012-12-17 03:20:34 +010089syscall_p(struct process *proc, int status, int *sysnum)
90{
Eric Vaitl1228a912006-12-28 16:16:56 +010091 if (WIFSTOPPED(status)
Juan Cespedes3e94cbf2009-05-22 19:12:07 +020092 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
93 /* get the user's pc (plus 8) */
94 long pc = (long)get_instruction_pointer(proc);
95 /* fetch the SWI instruction */
96 int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0);
97 int num = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 8, 0);
Eric Vaitl1228a912006-12-28 16:16:56 +010098
Juan Cespedes3e94cbf2009-05-22 19:12:07 +020099 /*
100 On a mipsel, syscall looks like:
101 24040fa1 li v0, 0x0fa1 # 4001 --> _exit syscall
102 0000000c syscall
103 */
104 if(insn!=0x0000000c){
105 return 0;
106 }
107
108 *sysnum = (num & 0xFFFF) - 4000;
109 /* if it is a syscall, return 1 or 2 */
110 if (proc->callstack_depth > 0 &&
111 proc->callstack[proc->callstack_depth - 1].is_syscall &&
112 proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) {
113 return 2;
114 }
115
116 if (*sysnum >= 0) {
117 return 1;
118 }
119 }
Eric Vaitl1228a912006-12-28 16:16:56 +0100120 return 0;
121}
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200122
123/* Based on GDB code. */
124#define mips32_op(x) (x >> 26)
125#define itype_op(x) (x >> 26)
126#define itype_rs(x) ((x >> 21) & 0x1f)
127#define itype_rt(x) ((x >> 16) & 0x1f)
128#define itype_immediate(x) (x & 0xffff)
129
130#define jtype_op(x) (x >> 26)
131#define jtype_target(x) (x & 0x03ffffff)
132
133#define rtype_op(x) (x >> 26)
134#define rtype_rs(x) ((x >> 21) & 0x1f)
135#define rtype_rt(x) ((x >> 16) & 0x1f)
136#define rtype_rd(x) ((x >> 11) & 0x1f)
137#define rtype_shamt(x) ((x >> 6) & 0x1f)
138#define rtype_funct(x) (x & 0x3f)
139
140static int32_t
141mips32_relative_offset (uint32_t inst)
142{
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200143 return ((itype_immediate(inst) ^ 0x8000) - 0x8000) << 2;
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200144}
145
Petr Machata929bd572012-12-17 03:20:34 +0100146int mips_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc)
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200147{
148 uint32_t inst, rx;
149 int op;
150 int rn;
151 int nr = 0;
152
153 inst = ptrace(PTRACE_PEEKTEXT, proc->pid, pc, 0);
154
155 if ((inst & 0xe0000000) != 0) {
156 /* Check for branches. */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200157 if (itype_op(inst) >> 2 == 5) {
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200158 /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200159 op = (itype_op(inst) & 0x03);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200160 switch (op)
161 {
162 case 0: /* BEQL */
163 case 1: /* BNEL */
164 case 2: /* BLEZL */
165 case 3: /* BGTZL */
166 newpc[nr++] = pc + 8;
167 newpc[nr++] = pc + 4 +
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200168 mips32_relative_offset(inst);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200169 break;
170 default:
171 newpc[nr++] = pc + 4;
172 break;
173 }
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200174 } else if (itype_op(inst) == 17 && itype_rs(inst) == 8) {
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200175 /* Step over the branch. */
176 newpc[nr++] = pc + 8;
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200177 newpc[nr++] = pc + mips32_relative_offset(inst) + 4;
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200178 } else {
179 newpc[nr++] = pc + 4;
180 }
181 } else {
182 /* Further subdivide into SPECIAL, REGIMM and other. */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200183 switch (op = itype_op(inst) & 0x07)
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200184 {
185 case 0:
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200186 op = rtype_funct(inst);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200187 switch (op)
188 {
189 case 8: /* JR */
190 case 9: /* JALR */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200191 rn = rtype_rs(inst);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200192
193 rx = ptrace(PTRACE_PEEKUSER,proc->pid, rn, 0);
194 newpc[nr++] = rx;
195 break;
196 default:
197 case 12: /* SYSCALL */
198 newpc[nr++] = pc + 4;
199 break;
200 }
201 break;
202 case 1:
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200203 op = itype_rt(inst);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200204 switch (op)
205 {
206 case 0:
207 case 1:
208 case 2:
209 case 3:
210 case 16:
211 case 17:
212 case 18:
213 case 19:
214 newpc[nr++] = pc + 8;
215 newpc[nr++] = pc + 4 +
216 mips32_relative_offset(inst);
217 break;
218 default:
219 newpc[nr++] = pc + 4;
220 break;
221 }
222 break;
223 case 2: /* J */
224 case 3: /* JAL */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200225 rx = jtype_target(inst) << 2;
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200226 /* Upper four bits get never changed... */
227 newpc[nr++] = rx + ((pc + 4) & ~0x0fffffff);
228 break;
Edgar E. Iglesiasc44ef1e2012-10-01 12:06:44 +0200229 case 4: /* BEQ */
230 if (itype_rs(inst) == itype_rt(inst)) {
231 /* Compare the same reg for equality, always
232 * follow the branch. */
233 newpc[nr++] = pc + 4 +
234 mips32_relative_offset(inst);
235 break;
236 }
237 /* Fall through. */
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200238 default:
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200239 case 5:
240 case 6:
241 case 7:
242 /* Step over the branch. */
243 newpc[nr++] = pc + 8;
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200244 newpc[nr++] = pc + mips32_relative_offset(inst) + 4;
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200245 break;
246 }
247 }
248 if (nr <= 0 || nr > 2)
249 goto fail;
250 if (nr == 2) {
251 if (newpc[1] == 0)
252 goto fail;
253 }
254 if (newpc[0] == 0)
255 goto fail;
256
257 assert(nr == 1 || nr == 2);
258 return nr;
259
260fail:
261 printf("nr=%d pc=%x\n", nr, pc);
262 printf("pc=%x %x\n", newpc[0], newpc[1]);
263 return 0;
264}
265
266int
Petr Machata929bd572012-12-17 03:20:34 +0100267arch_atomic_singlestep(struct process *proc, struct breakpoint *sbp,
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200268 int (*add_cb)(void *addr, void *data),
269 void *add_cb_data)
270{
271 uint32_t pc = (uint32_t) get_instruction_pointer(proc);
272 uint32_t newpcs[2];
273 int nr;
274
275 nr = mips_next_pcs(proc, pc, newpcs);
276
277 while (nr-- > 0) {
278 arch_addr_t baddr = (arch_addr_t) newpcs[nr];
279 /* Not sure what to do here. We've already got a bp? */
Edgar E. Iglesiasa35cc7a2012-10-01 12:06:45 +0200280 if (dict_find_entry(proc->leader->breakpoints, baddr) != NULL) {
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200281 fprintf(stderr, "skip %p %p\n", baddr, add_cb_data);
282 continue;
283 }
284
285 if (add_cb(baddr, add_cb_data) < 0)
286 return -1;
287 }
288
289 ptrace(PTRACE_SYSCALL, proc->pid, 0, 0);
290 return 0;
291}
292
Eric Vaitl1228a912006-12-28 16:16:56 +0100293/**
294 \param type Function/syscall call or return.
295 \param proc The process that had an event.
Juan Cespedesfea4a122009-05-28 16:53:43 +0200296 \param arg_num -1 for return value,
297 \return The argument to fetch.
Eric Vaitl1228a912006-12-28 16:16:56 +0100298
Juan Cespedesfea4a122009-05-28 16:53:43 +0200299 A couple of assumptions.
Eric Vaitl1228a912006-12-28 16:16:56 +0100300
301- Type is LT_TOF_FUNCTIONR or LT_TOF_SYSCALLR if arg_num==-1. These
302 types are only used in calls for output_right(), which only uses -1
303 for arg_num.
Juan Cespedesfea4a122009-05-28 16:53:43 +0200304- Type is LT_TOF_FUNCTION or LT_TOF_SYSCALL for args 0...4.
Eric Vaitl1228a912006-12-28 16:16:56 +0100305- I'm only displaying the first 4 args (Registers a0..a3). Good
306 enough for now.
307
308 Mipsel conventions seem to be:
309- syscall parameters: r4...r9
310- syscall return: if(!a3){ return v0;} else{ errno=v0;return -1;}
Juan Cespedesfea4a122009-05-28 16:53:43 +0200311- function call: r4..r7. Not sure how to get arg number 5.
Eric Vaitl1228a912006-12-28 16:16:56 +0100312- function return: v0
313
314The argument registers are wiped by a call, so it is a mistake to ask
315for arguments on a return. If ltrace does this, we will need to cache
316arguments somewhere on the call.
317
Juan Cespedesfea4a122009-05-28 16:53:43 +0200318I'm not doing any floating point support here.
Eric Vaitl1228a912006-12-28 16:16:56 +0100319
320*/
Juan Cespedesf1350522008-12-16 18:19:58 +0100321long
Petr Machata929bd572012-12-17 03:20:34 +0100322gimme_arg(enum tof type, struct process *proc, int arg_num,
323 struct arg_type_info *info)
Petr Machata000e3112012-01-03 17:03:39 +0100324{
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200325 long ret;
Arnaud Patard8a115b62010-01-08 08:40:10 -0500326 long addr;
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200327 debug(2,"type %d arg %d",type,arg_num);
Arnaud Patard8a115b62010-01-08 08:40:10 -0500328 if (arg_num == -1) {
329 if(type == LT_TOF_FUNCTIONR) {
330 return ptrace(PTRACE_PEEKUSER,proc->pid,off_v0,0);
331 }
332 if (type == LT_TOF_SYSCALLR) {
333 unsigned a3=ptrace(PTRACE_PEEKUSER, proc->pid,off_a3,0);
334 unsigned v0=ptrace(PTRACE_PEEKUSER, proc->pid,off_v0,0);
335 if(!a3){
336 return v0;
337 }
338 return -1;
339 }
340 }
341 if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL) {
342 /* o32: float args are in f12 and f14 */
343 if ((info->type == ARGTYPE_FLOAT) && (arg_num < 2)) {
344 ret=ptrace(PTRACE_PEEKUSER,proc->pid,off_fpr0+12+arg_num*2,0);
345 debug(2,"ret = %#lx",ret);
346 return ret;
347 }
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200348 if(arg_num <4){
349 ret=ptrace(PTRACE_PEEKUSER,proc->pid,off_a0+arg_num,0);
350 debug(2,"ret = %#lx",ret);
351 return ret;
352 } else {
Arnaud Patard8a115b62010-01-08 08:40:10 -0500353 /* not sure it's going to work for something else than syscall */
354 addr=ptrace(PTRACE_PEEKUSER,proc->pid,off_sp,0);
355 if (addr == -1) {
356 debug(2,"ret = %#lx",addr);
357 return addr;
358 }
359 ret = addr + 4*arg_num;
360 ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0);
361 debug(2,"ret = %#lx",ret);
362 return ret;
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200363 }
Juan Cespedesfea4a122009-05-28 16:53:43 +0200364 }
Arnaud Patard8a115b62010-01-08 08:40:10 -0500365 if (type == LT_TOF_FUNCTIONR || type == LT_TOF_SYSCALLR){
366 addr=ptrace(PTRACE_PEEKUSER,proc->pid,off_sp,0);
367 if (addr == -1) {
368 debug(2,"ret = %#lx",addr);
369 return addr;
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200370 }
Arnaud Patard8a115b62010-01-08 08:40:10 -0500371 ret = addr + 4*arg_num;
372 ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0);
373 debug(2,"ret = %#lx",ret);
374 return ret;
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200375 }
376 fprintf(stderr, "gimme_arg called with wrong arguments\n");
Eric Vaitl1228a912006-12-28 16:16:56 +0100377 return 0;
378}
379
Eric Vaitl1228a912006-12-28 16:16:56 +0100380/**@}*/