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