trace.c revision f670eea50e959eeb9da53d70cad8d43c19494ef0
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
11#include "common.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
21void
22get_arch_dep(Process *proc) {
23#ifdef __powerpc64__
24	if (proc->arch_ptr)
25		return;
26	proc->mask_32bit = (proc->e_machine == EM_PPC);
27	proc->arch_ptr = (void *)1;
28#endif
29}
30
31/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */
32#define SYSCALL_INSN   0x44000002
33
34unsigned int greg = 3;
35unsigned int freg = 1;
36unsigned int vreg = 2;
37
38int
39syscall_p(Process *proc, int status, int *sysnum) {
40	if (WIFSTOPPED(status)
41	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
42		long pc = (long)get_instruction_pointer(proc);
43		int insn =
44		    (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long),
45				0);
46
47		if (insn == SYSCALL_INSN) {
48			*sysnum =
49			    (int)ptrace(PTRACE_PEEKUSER, proc->pid,
50					sizeof(long) * PT_R0, 0);
51			if (proc->callstack_depth > 0 &&
52					proc->callstack[proc->callstack_depth - 1].is_syscall &&
53					proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) {
54				return 2;
55			}
56			return 1;
57		}
58	}
59	return 0;
60}
61
62/* Grab functions arguments based on the PPC64 ABI.  */
63long
64gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
65	long data;
66
67	if (type == LT_TOF_FUNCTIONR) {
68		if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE)
69			return ptrace (PTRACE_PEEKUSER, proc->pid,
70					sizeof (long) * (PT_FPR0 + 1), 0);
71		else
72			return ptrace (PTRACE_PEEKUSER, proc->pid,
73					sizeof (long) * PT_R3, 0);
74	}
75
76	/* Check if we're entering a new function call to list parameters.  If
77	   so, initialize the register control variables to keep track of where
78	   the parameters were stored.  */
79	if (type == LT_TOF_FUNCTION && arg_num == 0) {
80	  /* Initialize the set of registrers for parameter passing.  */
81		greg = 3;
82		freg = 1;
83		vreg = 2;
84	}
85
86	if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
87		if (freg <= 13 || (proc->mask_32bit && freg <= 8)) {
88			data = ptrace (PTRACE_PEEKUSER, proc->pid,
89					sizeof (long) * (PT_FPR0 + freg), 0);
90
91			if (info->type == ARGTYPE_FLOAT) {
92			/* float values passed in FP registers are automatically
93			promoted to double. We need to convert it back to float
94			before printing.  */
95				union { long val; float fval; double dval; } cvt;
96				cvt.val = data;
97				cvt.fval = (float) cvt.dval;
98				data = cvt.val;
99			}
100
101			freg++;
102			greg++;
103
104			return data;
105		}
106	}
107	else if (greg <= 10) {
108		data = ptrace (PTRACE_PEEKUSER, proc->pid,
109				sizeof (long) * greg, 0);
110		greg++;
111
112		return data;
113	}
114	else
115		return ptrace (PTRACE_PEEKDATA, proc->pid,
116				proc->stack_pointer + sizeof (long) *
117				(arg_num - 8), 0);
118
119	return 0;
120}
121
122void
123save_register_args(enum tof type, Process *proc) {
124}
125
126/* Read a single long from the process's memory address 'addr'.  */
127int
128arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
129	long pointed_to;
130
131	errno = 0;
132
133	pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
134
135	if (pointed_to == -1 && errno)
136		return -errno;
137
138	/* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we
139	   need to shift the long values returned by ptrace to end up with
140	   the correct value.  */
141
142	if (info) {
143		if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER
144		    || info->type == ARGTYPE_STRING))) {
145			pointed_to = pointed_to >> 32;
146
147			/* Make sure we have nothing in the upper word so we can
148			   do a explicit cast from long to int later in the code.  */
149			pointed_to &= 0x00000000ffffffff;
150		}
151	}
152
153	*result = pointed_to;
154	return 0;
155}
156