trace.c revision 87e1a5cc080cdab488a6c7076aa5c86dfe1c26f0
1#include "config.h"
2
3#include <sys/types.h>
4#include <sys/wait.h>
5#include <signal.h>
6#include <sys/ptrace.h>
7#include <asm/ptrace.h>
8#include <elf.h>
9#include <errno.h>
10#include <string.h>
11
12#include "common.h"
13#include "ptrace.h"
14
15#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
16# define PTRACE_PEEKUSER PTRACE_PEEKUSR
17#endif
18
19#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
20# define PTRACE_POKEUSER PTRACE_POKEUSR
21#endif
22
23void
24get_arch_dep(Process *proc) {
25	if (proc->arch_ptr == NULL) {
26		proc->arch_ptr = malloc(sizeof(proc_archdep));
27#ifdef __powerpc64__
28		proc->mask_32bit = (proc->e_machine == EM_PPC);
29#endif
30	}
31
32	proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
33	a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0)
34		&& (ptrace(PTRACE_GETFPREGS, proc->pid, 0, &a->fpregs) >= 0);
35}
36
37#define SYSCALL_INSN   0x44000002
38
39unsigned int greg = 3;
40unsigned int freg = 1;
41
42/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */
43int
44syscall_p(Process *proc, int status, int *sysnum) {
45	if (WIFSTOPPED(status)
46	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
47		long pc = (long)get_instruction_pointer(proc);
48		int insn =
49		    (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long),
50				0);
51
52		if (insn == SYSCALL_INSN) {
53			*sysnum =
54			    (int)ptrace(PTRACE_PEEKUSER, proc->pid,
55					sizeof(long) * PT_R0, 0);
56			if (proc->callstack_depth > 0 &&
57					proc->callstack[proc->callstack_depth - 1].is_syscall &&
58					proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) {
59				return 2;
60			}
61			return 1;
62		}
63	}
64	return 0;
65}
66
67static long
68gimme_arg_regset(enum tof type, Process *proc, int arg_num, arg_type_info *info,
69		 gregset_t *regs, fpregset_t *fpregs)
70{
71	union { long val; float fval; double dval; } cvt;
72
73	if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
74		if (freg <= 13 || (proc->mask_32bit && freg <= 8)) {
75			double val = GET_FPREG(*fpregs, freg);
76
77			if (info->type == ARGTYPE_FLOAT)
78				cvt.fval = val;
79			else
80				cvt.dval = val;
81
82			freg++;
83			greg++;
84
85			return cvt.val;
86		}
87	}
88	else if (greg <= 10)
89		return (*regs)[greg++];
90	else
91		return ptrace (PTRACE_PEEKDATA, proc->pid,
92				proc->stack_pointer + sizeof (long) *
93				(arg_num - 8), 0);
94
95	return 0;
96}
97
98static long
99gimme_retval(Process *proc, int arg_num, arg_type_info *info,
100	     gregset_t *regs, fpregset_t *fpregs)
101{
102	union { long val; float fval; double dval; } cvt;
103	if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
104		double val = GET_FPREG(*fpregs, 1);
105
106		if (info->type == ARGTYPE_FLOAT)
107			cvt.fval = val;
108		else
109			cvt.dval = val;
110
111		return cvt.val;
112	}
113	else
114		return (*regs)[3];
115}
116
117/* Grab functions arguments based on the PPC64 ABI.  */
118long
119gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info)
120{
121	proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
122	if (arch == NULL || !arch->valid)
123		return -1;
124
125	/* Check if we're entering a new function call to list parameters.  If
126	   so, initialize the register control variables to keep track of where
127	   the parameters were stored.  */
128	if ((type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR)
129	    && arg_num == 0) {
130		/* Initialize the set of registrers for parameter passing.  */
131		greg = 3;
132		freg = 1;
133	}
134
135
136	if (type == LT_TOF_FUNCTIONR) {
137		if (arg_num == -1)
138			return gimme_retval(proc, arg_num, info,
139					    &arch->regs, &arch->fpregs);
140		else
141			return gimme_arg_regset(type, proc, arg_num, info,
142						&arch->regs_copy,
143						&arch->fpregs_copy);
144	}
145	else
146		return gimme_arg_regset(type, proc, arg_num, info,
147					&arch->regs, &arch->fpregs);
148}
149
150void
151save_register_args(enum tof type, Process *proc) {
152	proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
153	if (arch == NULL || !arch->valid)
154		return;
155
156	memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs));
157	memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs));
158}
159
160/* Read a single long from the process's memory address 'addr'.  */
161int
162arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
163	long pointed_to;
164
165	errno = 0;
166
167	pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
168
169	if (pointed_to == -1 && errno)
170		return -errno;
171
172	/* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we
173	   need to shift the long values returned by ptrace to end up with
174	   the correct value.  */
175
176	if (info) {
177		if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER
178		    || info->type == ARGTYPE_STRING))) {
179			pointed_to = pointed_to >> 32;
180
181			/* Make sure we have nothing in the upper word so we can
182			   do a explicit cast from long to int later in the code.  */
183			pointed_to &= 0x00000000ffffffff;
184		}
185	}
186
187	*result = pointed_to;
188	return 0;
189}
190