trace.c revision 5b3ffdf2e696273d38434ff7b3c26349fff5a0ea
1#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <sys/types.h>
6#include <sys/wait.h>
7#include <signal.h>
8#include <sys/ptrace.h>
9#include <asm/ptrace.h>
10
11#include "ltrace.h"
12
13#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
14# define PTRACE_PEEKUSER PTRACE_PEEKUSR
15#endif
16
17#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
18# define PTRACE_POKEUSER PTRACE_POKEUSR
19#endif
20
21/* syscall tracing protocol: ArmLinux
22 on the way in, ip is 0
23 on the way out, ip is non-zero
24*/
25#define off_r0 0
26#define off_ip 48
27#define off_pc 60
28
29/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
30 */
31int syscall_p(struct process * proc, int status, int * sysnum)
32{
33	if (WIFSTOPPED(status) && WSTOPSIG(status)==SIGTRAP) {
34		/* get the user's pc (plus 8) */
35		int pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
36		/* fetch the SWI instruction */
37		int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc-4, 0) ;
38
39		*sysnum = insn & 0xFFFF;
40		/* if it is a syscall, return 1 or 2 */
41		if ((insn & 0xFFFF0000) == 0xef900000) {
42			return ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0) ? 2 : 1;
43		}
44	}
45	return 0;
46}
47
48
49void continue_after_breakpoint(struct process *proc, struct breakpoint * sbp)
50{
51	if (sbp->enabled) disable_breakpoint(proc->pid, sbp);
52	ptrace(PTRACE_POKEUSER, proc->pid, off_pc, sbp->addr);
53	if (sbp->enabled == 0) {
54		continue_process(proc->pid);
55	} else {
56		proc->breakpoint_being_enabled = sbp;
57		ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
58	}
59}
60
61long gimme_arg(enum tof type, struct process * proc, int arg_num)
62{
63	if (arg_num==-1) {		/* return value */
64		return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0);
65	}
66
67	/* deal with the ARM calling conventions */
68	if (type==LT_TOF_FUNCTION) {
69		if (arg_num<4) {
70			return ptrace(PTRACE_PEEKUSER, proc->pid, 4*arg_num, 0);
71		} else {
72			return ptrace(PTRACE_PEEKDATA, proc->pid, proc->stack_pointer+4*(arg_num-4), 0);
73		}
74	} else if (type==LT_TOF_SYSCALL) {
75		if (arg_num<5) {
76			return ptrace(PTRACE_PEEKUSER, proc->pid, 4*arg_num, 0);
77		} else {
78			return ptrace(PTRACE_PEEKDATA, proc->pid, proc->stack_pointer+4*(arg_num-5), 0);
79		}
80	} else {
81		fprintf(stderr, "gimme_arg called with wrong arguments\n");
82		exit(1);
83	}
84
85	return 0;
86}
87
88int umovestr(struct process * proc, void * addr, int len, void * laddr)
89{
90	long a;
91	int i;
92	int offset=0;
93
94	while(offset<len) {
95		a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr+offset, 0);
96		for(i=0; i<sizeof(long); i++) {
97			if (((char*)&a)[i] && offset+i < len) {
98				*(char *)(laddr+offset+i) = ((char*)&a)[i];
99			} else {
100				*(char *)(laddr+offset+i) = '\0';
101				return 0;
102			}
103		}
104		offset += sizeof(long);
105	}
106	*(char *)(laddr+offset) = '\0';
107	return 0;
108}
109