trace.c revision e276cf41371cd5c5a722043658ccc15321aa15ac
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#ifdef __powerpc64__
92		if (proc->mask_32bit)
93			return ptrace (PTRACE_PEEKDATA, proc->pid,
94				       proc->stack_pointer + 8 +
95				       sizeof (int) * (arg_num - 8), 0) >> 32;
96		else
97			return ptrace (PTRACE_PEEKDATA, proc->pid,
98				       proc->stack_pointer + 112 +
99				       sizeof (long) * (arg_num - 8), 0);
100#else
101		return ptrace (PTRACE_PEEKDATA, proc->pid,
102			       proc->stack_pointer + 8 +
103			       sizeof (long) * (arg_num - 8), 0);
104#endif
105	}
106
107	return 0;
108}
109
110static long
111gimme_retval(Process *proc, int arg_num, arg_type_info *info,
112	     gregset_t *regs, fpregset_t *fpregs)
113{
114	union { long val; float fval; double dval; } cvt;
115	if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
116		double val = GET_FPREG(*fpregs, 1);
117
118		if (info->type == ARGTYPE_FLOAT)
119			cvt.fval = val;
120		else
121			cvt.dval = val;
122
123		return cvt.val;
124	}
125	else
126		return (*regs)[3];
127}
128
129/* Grab functions arguments based on the PPC64 ABI.  */
130long
131gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info)
132{
133	proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
134	if (arch == NULL || !arch->valid)
135		return -1;
136
137	/* Check if we're entering a new function call to list parameters.  If
138	   so, initialize the register control variables to keep track of where
139	   the parameters were stored.  */
140	if ((type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR)
141	    && arg_num == 0) {
142		/* Initialize the set of registrers for parameter passing.  */
143		greg = 3;
144		freg = 1;
145	}
146
147
148	if (type == LT_TOF_FUNCTIONR) {
149		if (arg_num == -1)
150			return gimme_retval(proc, arg_num, info,
151					    &arch->regs, &arch->fpregs);
152		else
153			return gimme_arg_regset(type, proc, arg_num, info,
154						&arch->regs_copy,
155						&arch->fpregs_copy);
156	}
157	else
158		return gimme_arg_regset(type, proc, arg_num, info,
159					&arch->regs, &arch->fpregs);
160}
161
162void
163save_register_args(enum tof type, Process *proc) {
164	proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
165	if (arch == NULL || !arch->valid)
166		return;
167
168	memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs));
169	memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs));
170}
171
172/* Read a single long from the process's memory address 'addr'.  */
173int
174arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
175	long pointed_to;
176
177	errno = 0;
178
179	pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
180
181	if (pointed_to == -1 && errno)
182		return -errno;
183
184	/* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we
185	   need to shift the long values returned by ptrace to end up with
186	   the correct value.  */
187
188	if (info) {
189		if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER
190		    || info->type == ARGTYPE_STRING))) {
191			pointed_to = pointed_to >> 32;
192
193			/* Make sure we have nothing in the upper word so we can
194			   do a explicit cast from long to int later in the code.  */
195			pointed_to &= 0x00000000ffffffff;
196		}
197	}
198
199	*result = pointed_to;
200	return 0;
201}
202