trace.c revision a193452188e51f233677e3f2607d9a61a789a1df
1/*
2 * This file is part of ltrace.
3 *
4 * Copyright (C) 2013 Imagination Technologies Ltd.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 */
20
21#include "config.h"
22
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <signal.h>
26#include <sys/ptrace.h>
27#include <linux/uio.h>
28#include <asm/ptrace.h>
29#include <assert.h>
30
31#include "proc.h"
32#include "common.h"
33
34#define METAG_INSN_SIZE	4
35#define N_UNITS 2
36#define REG_SIZE 4
37
38/* unit codes  */
39enum metag_unitnum {
40	METAG_UNIT_CT,       /* 0x0 */
41	METAG_UNIT_D0,
42	METAG_UNIT_D1,
43	METAG_UNIT_A0,
44	METAG_UNIT_A1,       /* 0x4 */
45	METAG_UNIT_PC,
46	METAG_UNIT_RA,
47	METAG_UNIT_TR,
48	METAG_UNIT_TT,       /* 0x8 */
49	METAG_UNIT_FX,
50	METAG_UNIT_MAX,
51};
52
53/**
54    \param proc The process that had an event.
55
56    Called by \c next_event() right after the return from wait.
57 */
58void
59get_arch_dep(struct process *proc)
60{
61
62}
63
64/**
65    \param proc Process that had event.
66    \param status From \c\ waitpid().
67    \param sysnum 0-based syscall number.
68    \return 1 if syscall, 2 if sysret, 0 otherwise.
69
70    Called by \c next_event() after the call to get_arch_dep().
71
72 */
73int
74syscall_p(struct process *proc, int status, int *sysnum)
75{
76	if (WIFSTOPPED(status)
77	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
78		struct user_gp_regs regs;
79		struct iovec iov;
80
81		/* Get GP registers.  */
82		iov.iov_base = &regs;
83		iov.iov_len = sizeof(regs);
84		if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS,
85			   (long)&iov))
86			return -1;
87
88		/* Fetch the SWITCH instruction.  */
89		unsigned int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, regs.pc,
90					   0);
91		*sysnum = regs.dx[0][1];
92
93		if (insn != 0xaf440001) {
94			/* Check if we're returning from the system call.  */
95			insn = ptrace(PTRACE_PEEKTEXT, proc->pid, regs.pc - 4,
96				      0);
97			if (insn == 0xaf440001)
98				return 2;
99
100			return 0;
101		}
102
103		if (*sysnum >= 0)
104			return 1;
105	}
106	return 0;
107}
108
109/* 2-bit base unit (BU) mapping.  */
110static enum metag_unitnum metag_bu_map[4] = {
111	METAG_UNIT_A1,
112	METAG_UNIT_D0,
113	METAG_UNIT_D1,
114	METAG_UNIT_A0,
115};
116
117static int
118get_regval_from_unit(enum metag_unitnum unit, unsigned int reg,
119		     struct user_gp_regs *regs)
120{
121	/*
122	 * Check if reg has a sane value.
123	 * We do have N_UNITS, each one having X registers
124	 * and each register is REG_SIZE bytes.
125	 */
126	if ((unit == METAG_UNIT_A0) || (unit == METAG_UNIT_A1)) {
127		if (reg >= ((sizeof(regs->ax)/N_UNITS/REG_SIZE)))
128			goto bad_reg;
129	} else if ((unit == METAG_UNIT_D0) || (unit == METAG_UNIT_D1)) {
130		if (reg >= ((sizeof(regs->dx)/N_UNITS/REG_SIZE)))
131			goto bad_reg;
132	}
133
134	switch(unit) {
135	case METAG_UNIT_A1:
136		return regs->ax[reg][1];
137	case METAG_UNIT_D0:
138		return regs->dx[reg][0];
139	case METAG_UNIT_D1:
140		return regs->dx[reg][1];
141	case METAG_UNIT_A0:
142		return regs->ax[reg][0];
143	/* We really shouldn't be here.  */
144	default:
145		assert(unit != unit);
146		abort();
147	}
148	return 0;
149
150bad_reg:
151	fprintf(stderr,
152		"Reading from register %d of unit %d is not implemented.",
153		reg, unit);
154	return 0;
155
156}
157
158static int
159metag_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc)
160{
161	uint32_t inst;
162	int nr = 0, imm, reg_val;
163	unsigned int unit = 0, reg;
164	struct user_gp_regs regs;
165	struct iovec iov;
166
167	inst = ptrace(PTRACE_PEEKTEXT, proc->pid, pc, 0);
168
169	if (inst == 0xa0fffffe) { /* NOP (Special branch instruction) */
170		newpc[nr++] = pc + 4;
171	} else if ((inst & 0xff000000) == 0xa0000000) {
172		/* Matching 0xA 0x0 for opcode for B #S19 or B<cc> #S19.
173		 *
174		 * Potential Targets:
175		 * - pc + #S19 * METAG_INSN_SIZE if R=1 or <CC> true
176		 * - pc + 4  */
177		imm = ((inst << 8) >> 13) * METAG_INSN_SIZE;
178		newpc[nr++] = pc + imm;
179		newpc[nr++] = pc + 4;
180	} else if ((inst & 0xff000000) == 0xac000000) {
181		/* Matching 0xA 0xC for opcode.
182		 * JUMP BBx.r,#X16 or CALL BBx.r,#X16
183		 *
184		 * pc = reg + #x16 (aligned)  */
185		imm = (inst >> 3) & 0xffff;
186		reg = (inst >> 19) & 0x1f;
187		unit = metag_bu_map[inst & 0x3];
188		iov.iov_base = &regs;
189		iov.iov_len = sizeof(regs);
190		if (ptrace(PTRACE_GETREGSET, proc->pid,
191			   NT_PRSTATUS, (long)&iov))
192			goto ptrace_fail;
193
194		reg_val = get_regval_from_unit(unit, reg, &regs);
195		newpc[nr++] = (reg_val + imm) & -METAG_INSN_SIZE;
196	} else if ((inst & 0xff000000) == 0xab000000) {
197		/* Matching 0xA 0xB for opcode.
198		 *
199		 * CALLR BBx.r,#S19  */
200		imm = ((inst << 8) >> 13) * METAG_INSN_SIZE;
201		newpc[nr++] = pc + imm;
202	} else if ((inst & 0xff0001e0) == 0xa30000a0) {
203		/*
204		 * Matching 0xA 0x3 for opcode and then
205		 * Ud (bit 8-5) = 0x5 = METAG_UNIT_PC
206		 *
207		 * Potential MOV PC,.. or SWAP<cc> PC,.. or SWAP<cc> ..,PC
208		 */
209
210		iov.iov_base = &regs;
211		iov.iov_len = sizeof(regs);
212		if (ptrace(PTRACE_GETREGSET, proc->pid,
213			   NT_PRSTATUS, (long)&iov))
214			goto ptrace_fail;
215
216		/*
217		 * Maybe PC is the source register for a SWAP?
218		 * bit9 = 1 and bit13-10(Us) == METAG_UNIT_PC
219		 */
220		if (((inst >> 9 ) & 0x1) &&
221		    (((inst >> 10) & 0xf) == METAG_UNIT_PC)) {
222			/* PC will get its value from the
223			 * destination register.  */
224			reg = (inst >> 14) & 0x1f;
225			unit = (inst >> 5) & 0xf;
226		} else { /* PC is the destination register.
227			  * Find the source register.  */
228			reg = (inst >> 19) & 0x1f;
229			unit = (inst >> 10) & 0xf;
230		}
231
232		switch(unit) {
233		case METAG_UNIT_D0:
234		case METAG_UNIT_D1:
235		case METAG_UNIT_A0:
236		case METAG_UNIT_A1:
237			reg_val = get_regval_from_unit(unit, reg, &regs);
238			break;
239		case METAG_UNIT_PC:
240			reg_val = regs.pc;
241			break;
242		default:
243			goto unhandled;
244		}
245		newpc[nr++] = reg_val;
246		/* In case it is a conditional instruction.  */
247		newpc[nr++] = pc + 4;
248	} else if ((inst & 0xff00001f) == 0xc600000a){
249		/* Matching 0xC 0x{4,6} for opcode
250		 * and UD == 0x5 == METAG_UNIT_PC
251		 *
252		 * GETD PC, [A0.r + #S6] or
253		 * GETD PC, [A0.r + A0.r]  */
254		unit = metag_bu_map[(inst >> 5) & 0x3];
255		iov.iov_base = &regs;
256		iov.iov_len = sizeof(regs);
257		reg = (inst >> 14) & 0x1f;
258		imm = (inst << 18) >> 5; /* sign-extend it */
259		if (ptrace(PTRACE_GETREGSET, proc->pid,
260			   NT_PRSTATUS, (long)&iov))
261			goto ptrace_fail;
262		reg_val = get_regval_from_unit(unit, reg, &regs) + imm;
263		/* See where reg_val actually points to.  */
264		newpc[nr++] = ptrace(PTRACE_PEEKTEXT, proc->pid, reg_val, 0);
265	} else if (((inst & 0xfe0001e0) == 0x840000a0) || /* ADDcc R, A, R */
266		   ((inst & 0xfe00003f) == 0x8600002a) || /* ADD R, A, #X8 */
267		   ((inst & 0xfe0001e0) == 0x8c0000a0) || /* SUBcc R, A, R */
268		   ((inst & 0xfe00003f) == 0x8e00002a) || /* SUB R, A, #X8 */
269		   ((inst & 0xf40001e0) == 0x040000a0) || /* ADDcc R, D, D */
270		   ((inst & 0xfe00003f) == 0x0600002a) || /* ADD R, D, #X8 */
271		   ((inst & 0xf40001e0) == 0x140000a0) || /* SUBcc R, D, D */
272		   ((inst & 0xf600003f) == 0x1600002a)) { /* SUB R, D, #X8 */
273
274		/* bits4-1(Ud) == METAG_UNIT_PC */
275
276		int src1, src2, pc_src1 = 0, pc_src2 = 0, is_aunit = 0;
277		int umask = 0, optype = 0;
278
279		/* Look for O2R bit */
280		if ((((inst >> 24) & 0x6) == 0x4) && (inst & 0x1))
281			goto unhandled;
282
283		iov.iov_base = &regs;
284		iov.iov_len = sizeof(regs);
285		if (ptrace(PTRACE_GETREGSET, proc->pid,
286			   NT_PRSTATUS, (long)&iov))
287			goto ptrace_fail;
288
289		/* Figure out unit for source registers based on the opcode.  */
290		switch((inst >> 28) & 0xf) {
291		case 0: /* ADD<cc> Rx.r, Dx.r, De.r|#X8 */
292		case 1: /* SUB<cc> Rx.r, Dx.r, De.r|#X8 */
293			unit = METAG_UNIT_D0 + ((inst >> 24) & 0x1);
294			is_aunit = 0;
295			umask = 0x1f;
296			optype = (inst >> 28) & 0x1;
297			break;
298		case 8:
299			unit = METAG_UNIT_A0 + ((inst >> 24) & 0x1);
300			is_aunit = 1;
301			umask = 0xf;
302			optype = (inst >> 27) & 0x1;
303			break;
304		}
305
306		/* Get pc bits (if any).  */
307		if (is_aunit) {
308			pc_src1 = (inst >> 18) & 0x1;
309			pc_src2 = (inst >> 13) & 0x1;
310		}
311
312		/* Determine ADD|SUB format. Immediate or register ?  */
313		if ((inst >> 25) & 0x1) { /* ADD|SUB cc PC, X, #imm8 */
314			src2 = (inst >> 6) & 0xff; /* so we can share code.  */
315			reg = (inst >> 14) & umask;
316			if (pc_src1)	/* This can only be true for AU ops.  */
317				src1 = regs.pc;
318			else		/* This covers both AU an DU ops.  */
319				src1 = get_regval_from_unit(unit, reg, &regs);
320		} else { /* ADD|SUB cc PC, X, X */
321			if (pc_src1)
322				src1 = regs.pc;
323			else
324				src1 = get_regval_from_unit(unit, (inst >> 14)
325							    & umask, &regs);
326			if (pc_src2)
327				src2 = regs.pc;
328			else
329				src2 = get_regval_from_unit(unit, (inst >> 9)
330							    & umask, &regs);
331		}
332
333		/* Construct the new PC.  */
334		if (optype)
335			/* SUB */
336			newpc[nr++] = src1 - src2;
337		else 	/* ADD */
338			newpc[nr++] = src1 + src2;
339		/* Conditional instruction so PC may not change.  */
340		newpc[nr++] = pc + 4;
341	} else {
342		newpc[nr++] = pc + 4;
343	}
344
345	if (nr <= 0 || nr > 2)
346		goto fail;
347	if (nr == 2 && newpc[1] == 0)
348		goto fail;
349
350	return nr;
351
352ptrace_fail:
353	fprintf(stderr, "Failed to read the registers pid=%d @ pc=0x%08x\n",
354		proc->pid, pc);
355	return 0;
356unhandled:
357	fprintf(stderr, "Unhandled instruction: pc=0x%08x, inst=0x%08x\n",
358		pc, inst);
359	return 0;
360fail:
361	fprintf(stderr, "nr=%d pc=0x%08x\n", nr, pc);
362	fprintf(stderr, "newpc=0x%08x 0x%08x\n", newpc[0], newpc[1]);
363	return 0;
364
365}
366
367enum sw_singlestep_status
368arch_sw_singlestep(struct process *proc, struct breakpoint *bp,
369		   int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
370		   struct sw_singlestep_data *add_cb_data)
371{
372	arch_addr_t pc = get_instruction_pointer(proc);
373	uint32_t newpcs[2];
374	int nr;
375
376	nr = metag_next_pcs(proc, (uint32_t)pc, newpcs);
377
378	while (nr-- > 0) {
379		arch_addr_t baddr = (arch_addr_t) newpcs[nr];
380		if (dict_find(proc->leader->breakpoints, &baddr) != NULL) {
381			fprintf(stderr, "skip %p %p\n", baddr, add_cb_data);
382			continue;
383		}
384
385		if (add_cb(baddr, add_cb_data) < 0)
386			return SWS_FAIL;
387	}
388
389	ptrace(PTRACE_SYSCALL, proc->pid, 0, 0);
390	return SWS_OK;
391}
392
393long
394gimme_arg(enum tof type, struct process *proc, int arg_num,
395	  struct arg_type_info *info)
396{
397	long ret;
398	struct user_gp_regs regs;
399	struct iovec iov;
400
401	/* get GP registers */
402	iov.iov_base = &regs;
403	iov.iov_len = sizeof(regs);
404	if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
405		return 0;
406
407	debug(2, "type %d arg %d arg",type, arg_num);
408	if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL) {
409		if (arg_num < 6) {
410			/* Args go backwards starting from D1Ar1 (D1.3) */
411			ret = ((unsigned long *)&regs.dx[3][1])[-arg_num];
412			debug(2,"ret = %#lx",ret);
413			return ret;
414		} else {
415			return 0;
416		}
417	}
418	if (arg_num >= 0) {
419		fprintf(stderr,"args on return?");
420	}
421	if (type == LT_TOF_FUNCTIONR || type == LT_TOF_SYSCALLR) {
422		return regs.dx[0][0]; /* D0Re0 (D0.0) */
423	}
424
425	fprintf(stderr, "gimme_arg called with wrong arguments\n");
426
427	return 0;
428}
429