blob: db9ec21ab87971091dd745321495a03b6b73aee5 [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
Juan Cespedesa8909f72009-04-28 20:02:41 +020067get_arch_dep(Process *proc) {
Eric Vaitl1228a912006-12-28 16:16:56 +010068}
69
70/**
Juan Cespedesfea4a122009-05-28 16:53:43 +020071 \param proc Process that had event.
Eric Vaitl1228a912006-12-28 16:16:56 +010072 \param status From \c wait()
Juan Cespedesfea4a122009-05-28 16:53:43 +020073 \param sysnum 0-based syscall number.
Eric Vaitl1228a912006-12-28 16:16:56 +010074 \return 1 if syscall, 2 if sysret, 0 otherwise.
75
Juan Cespedese2023f72009-04-07 12:12:08 +020076 Called by \c next_event() after the call to get_arch_dep()
Eric Vaitl1228a912006-12-28 16:16:56 +010077
78 It seems that the ptrace call trips twice on a system call, once
79 just before the system call and once when it returns. Both times,
80 the pc points at the instruction just after the mipsel "syscall"
81 instruction.
82
83 There are several possiblities for system call sets, each is offset
84 by a base from the others. On our system, it looks like the base
85 for the system calls is 4000.
86 */
Juan Cespedesf1350522008-12-16 18:19:58 +010087int
Juan Cespedesa8909f72009-04-28 20:02:41 +020088syscall_p(Process *proc, int status, int *sysnum) {
Eric Vaitl1228a912006-12-28 16:16:56 +010089 if (WIFSTOPPED(status)
Juan Cespedes3e94cbf2009-05-22 19:12:07 +020090 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
91 /* get the user's pc (plus 8) */
92 long pc = (long)get_instruction_pointer(proc);
93 /* fetch the SWI instruction */
94 int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0);
95 int num = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 8, 0);
Eric Vaitl1228a912006-12-28 16:16:56 +010096
Juan Cespedes3e94cbf2009-05-22 19:12:07 +020097 /*
98 On a mipsel, syscall looks like:
99 24040fa1 li v0, 0x0fa1 # 4001 --> _exit syscall
100 0000000c syscall
101 */
102 if(insn!=0x0000000c){
103 return 0;
104 }
105
106 *sysnum = (num & 0xFFFF) - 4000;
107 /* if it is a syscall, return 1 or 2 */
108 if (proc->callstack_depth > 0 &&
109 proc->callstack[proc->callstack_depth - 1].is_syscall &&
110 proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) {
111 return 2;
112 }
113
114 if (*sysnum >= 0) {
115 return 1;
116 }
117 }
Eric Vaitl1228a912006-12-28 16:16:56 +0100118 return 0;
119}
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200120
121/* Based on GDB code. */
122#define mips32_op(x) (x >> 26)
123#define itype_op(x) (x >> 26)
124#define itype_rs(x) ((x >> 21) & 0x1f)
125#define itype_rt(x) ((x >> 16) & 0x1f)
126#define itype_immediate(x) (x & 0xffff)
127
128#define jtype_op(x) (x >> 26)
129#define jtype_target(x) (x & 0x03ffffff)
130
131#define rtype_op(x) (x >> 26)
132#define rtype_rs(x) ((x >> 21) & 0x1f)
133#define rtype_rt(x) ((x >> 16) & 0x1f)
134#define rtype_rd(x) ((x >> 11) & 0x1f)
135#define rtype_shamt(x) ((x >> 6) & 0x1f)
136#define rtype_funct(x) (x & 0x3f)
137
138static int32_t
139mips32_relative_offset (uint32_t inst)
140{
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200141 return ((itype_immediate(inst) ^ 0x8000) - 0x8000) << 2;
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200142}
143
144int mips_next_pcs(struct Process *proc, uint32_t pc, uint32_t *newpc)
145{
146 uint32_t inst, rx;
147 int op;
148 int rn;
149 int nr = 0;
150
151 inst = ptrace(PTRACE_PEEKTEXT, proc->pid, pc, 0);
152
153 if ((inst & 0xe0000000) != 0) {
154 /* Check for branches. */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200155 if (itype_op(inst) >> 2 == 5) {
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200156 /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200157 op = (itype_op(inst) & 0x03);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200158 switch (op)
159 {
160 case 0: /* BEQL */
161 case 1: /* BNEL */
162 case 2: /* BLEZL */
163 case 3: /* BGTZL */
164 newpc[nr++] = pc + 8;
165 newpc[nr++] = pc + 4 +
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200166 mips32_relative_offset(inst);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200167 break;
168 default:
169 newpc[nr++] = pc + 4;
170 break;
171 }
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200172 } else if (itype_op(inst) == 17 && itype_rs(inst) == 8) {
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200173 /* Step over the branch. */
174 newpc[nr++] = pc + 8;
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200175 newpc[nr++] = pc + mips32_relative_offset(inst) + 4;
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200176 } else {
177 newpc[nr++] = pc + 4;
178 }
179 } else {
180 /* Further subdivide into SPECIAL, REGIMM and other. */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200181 switch (op = itype_op(inst) & 0x07)
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200182 {
183 case 0:
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200184 op = rtype_funct(inst);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200185 switch (op)
186 {
187 case 8: /* JR */
188 case 9: /* JALR */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200189 rn = rtype_rs(inst);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200190
191 rx = ptrace(PTRACE_PEEKUSER,proc->pid, rn, 0);
192 newpc[nr++] = rx;
193 break;
194 default:
195 case 12: /* SYSCALL */
196 newpc[nr++] = pc + 4;
197 break;
198 }
199 break;
200 case 1:
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200201 op = itype_rt(inst);
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200202 switch (op)
203 {
204 case 0:
205 case 1:
206 case 2:
207 case 3:
208 case 16:
209 case 17:
210 case 18:
211 case 19:
212 newpc[nr++] = pc + 8;
213 newpc[nr++] = pc + 4 +
214 mips32_relative_offset(inst);
215 break;
216 default:
217 newpc[nr++] = pc + 4;
218 break;
219 }
220 break;
221 case 2: /* J */
222 case 3: /* JAL */
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200223 rx = jtype_target(inst) << 2;
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200224 /* Upper four bits get never changed... */
225 newpc[nr++] = rx + ((pc + 4) & ~0x0fffffff);
226 break;
Edgar E. Iglesiasc44ef1e2012-10-01 12:06:44 +0200227 case 4: /* BEQ */
228 if (itype_rs(inst) == itype_rt(inst)) {
229 /* Compare the same reg for equality, always
230 * follow the branch. */
231 newpc[nr++] = pc + 4 +
232 mips32_relative_offset(inst);
233 break;
234 }
235 /* Fall through. */
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200236 default:
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200237 case 5:
238 case 6:
239 case 7:
240 /* Step over the branch. */
241 newpc[nr++] = pc + 8;
Edgar E. Iglesias0b02a932012-10-01 12:06:46 +0200242 newpc[nr++] = pc + mips32_relative_offset(inst) + 4;
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200243 break;
244 }
245 }
246 if (nr <= 0 || nr > 2)
247 goto fail;
248 if (nr == 2) {
249 if (newpc[1] == 0)
250 goto fail;
251 }
252 if (newpc[0] == 0)
253 goto fail;
254
255 assert(nr == 1 || nr == 2);
256 return nr;
257
258fail:
259 printf("nr=%d pc=%x\n", nr, pc);
260 printf("pc=%x %x\n", newpc[0], newpc[1]);
261 return 0;
262}
263
264int
265arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
266 int (*add_cb)(void *addr, void *data),
267 void *add_cb_data)
268{
269 uint32_t pc = (uint32_t) get_instruction_pointer(proc);
270 uint32_t newpcs[2];
271 int nr;
272
273 nr = mips_next_pcs(proc, pc, newpcs);
274
275 while (nr-- > 0) {
276 arch_addr_t baddr = (arch_addr_t) newpcs[nr];
277 /* Not sure what to do here. We've already got a bp? */
Edgar E. Iglesiasa35cc7a2012-10-01 12:06:45 +0200278 if (dict_find_entry(proc->leader->breakpoints, baddr) != NULL) {
Edgar E. Iglesiasaddae052012-09-27 17:02:39 +0200279 fprintf(stderr, "skip %p %p\n", baddr, add_cb_data);
280 continue;
281 }
282
283 if (add_cb(baddr, add_cb_data) < 0)
284 return -1;
285 }
286
287 ptrace(PTRACE_SYSCALL, proc->pid, 0, 0);
288 return 0;
289}
290
Eric Vaitl1228a912006-12-28 16:16:56 +0100291/**
292 \param type Function/syscall call or return.
293 \param proc The process that had an event.
Juan Cespedesfea4a122009-05-28 16:53:43 +0200294 \param arg_num -1 for return value,
295 \return The argument to fetch.
Eric Vaitl1228a912006-12-28 16:16:56 +0100296
Juan Cespedesfea4a122009-05-28 16:53:43 +0200297 A couple of assumptions.
Eric Vaitl1228a912006-12-28 16:16:56 +0100298
299- Type is LT_TOF_FUNCTIONR or LT_TOF_SYSCALLR if arg_num==-1. These
300 types are only used in calls for output_right(), which only uses -1
301 for arg_num.
Juan Cespedesfea4a122009-05-28 16:53:43 +0200302- Type is LT_TOF_FUNCTION or LT_TOF_SYSCALL for args 0...4.
Eric Vaitl1228a912006-12-28 16:16:56 +0100303- I'm only displaying the first 4 args (Registers a0..a3). Good
304 enough for now.
305
306 Mipsel conventions seem to be:
307- syscall parameters: r4...r9
308- syscall return: if(!a3){ return v0;} else{ errno=v0;return -1;}
Juan Cespedesfea4a122009-05-28 16:53:43 +0200309- function call: r4..r7. Not sure how to get arg number 5.
Eric Vaitl1228a912006-12-28 16:16:56 +0100310- function return: v0
311
312The argument registers are wiped by a call, so it is a mistake to ask
313for arguments on a return. If ltrace does this, we will need to cache
314arguments somewhere on the call.
315
Juan Cespedesfea4a122009-05-28 16:53:43 +0200316I'm not doing any floating point support here.
Eric Vaitl1228a912006-12-28 16:16:56 +0100317
318*/
Juan Cespedesf1350522008-12-16 18:19:58 +0100319long
Petr Machata000e3112012-01-03 17:03:39 +0100320gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
321{
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200322 long ret;
Arnaud Patard8a115b62010-01-08 08:40:10 -0500323 long addr;
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200324 debug(2,"type %d arg %d",type,arg_num);
Arnaud Patard8a115b62010-01-08 08:40:10 -0500325 if (arg_num == -1) {
326 if(type == LT_TOF_FUNCTIONR) {
327 return ptrace(PTRACE_PEEKUSER,proc->pid,off_v0,0);
328 }
329 if (type == LT_TOF_SYSCALLR) {
330 unsigned a3=ptrace(PTRACE_PEEKUSER, proc->pid,off_a3,0);
331 unsigned v0=ptrace(PTRACE_PEEKUSER, proc->pid,off_v0,0);
332 if(!a3){
333 return v0;
334 }
335 return -1;
336 }
337 }
338 if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL) {
339 /* o32: float args are in f12 and f14 */
340 if ((info->type == ARGTYPE_FLOAT) && (arg_num < 2)) {
341 ret=ptrace(PTRACE_PEEKUSER,proc->pid,off_fpr0+12+arg_num*2,0);
342 debug(2,"ret = %#lx",ret);
343 return ret;
344 }
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200345 if(arg_num <4){
346 ret=ptrace(PTRACE_PEEKUSER,proc->pid,off_a0+arg_num,0);
347 debug(2,"ret = %#lx",ret);
348 return ret;
349 } else {
Arnaud Patard8a115b62010-01-08 08:40:10 -0500350 /* not sure it's going to work for something else than syscall */
351 addr=ptrace(PTRACE_PEEKUSER,proc->pid,off_sp,0);
352 if (addr == -1) {
353 debug(2,"ret = %#lx",addr);
354 return addr;
355 }
356 ret = addr + 4*arg_num;
357 ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0);
358 debug(2,"ret = %#lx",ret);
359 return ret;
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200360 }
Juan Cespedesfea4a122009-05-28 16:53:43 +0200361 }
Arnaud Patard8a115b62010-01-08 08:40:10 -0500362 if (type == LT_TOF_FUNCTIONR || type == LT_TOF_SYSCALLR){
363 addr=ptrace(PTRACE_PEEKUSER,proc->pid,off_sp,0);
364 if (addr == -1) {
365 debug(2,"ret = %#lx",addr);
366 return addr;
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200367 }
Arnaud Patard8a115b62010-01-08 08:40:10 -0500368 ret = addr + 4*arg_num;
369 ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0);
370 debug(2,"ret = %#lx",ret);
371 return ret;
Juan Cespedes3e94cbf2009-05-22 19:12:07 +0200372 }
373 fprintf(stderr, "gimme_arg called with wrong arguments\n");
Eric Vaitl1228a912006-12-28 16:16:56 +0100374 return 0;
375}
376
Eric Vaitl1228a912006-12-28 16:16:56 +0100377/**@}*/