1 |
+ |
/* $MidnightBSD$ */ |
2 |
|
/* |
3 |
|
* Copyright 2006 Peter Grehan <grehan@freebsd.org> |
4 |
|
* Copyright 2005 Orlando Bassotto <orlando@break.net> |
26 |
|
* SUCH DAMAGE. |
27 |
|
*/ |
28 |
|
|
29 |
< |
#ifndef lint |
30 |
< |
static const char rcsid[] = |
30 |
< |
"$MidnightBSD$"; |
31 |
< |
#endif /* not lint */ |
29 |
> |
#include <sys/cdefs.h> |
30 |
> |
__FBSDID("$FreeBSD: stable/10/usr.bin/truss/powerpc64-fbsd.c 290052 2015-10-27 17:00:04Z jhb $"); |
31 |
|
|
32 |
< |
/* |
34 |
< |
* FreeBSD/powerpc-specific system call handling. This is probably the most |
35 |
< |
* complex part of the entire truss program, although I've got lots of |
36 |
< |
* it handled relatively cleanly now. The system call names are generated |
37 |
< |
* automatically, thanks to /usr/src/sys/kern/syscalls.master. The |
38 |
< |
* names used for the various structures are confusing, I sadly admit. |
39 |
< |
* |
40 |
< |
* This file is almost nothing more than a slightly-edited i386-fbsd.c. |
41 |
< |
*/ |
32 |
> |
/* FreeBSD/powerpc64-specific system call handling. */ |
33 |
|
|
43 |
– |
#include <sys/types.h> |
34 |
|
#include <sys/ptrace.h> |
35 |
|
#include <sys/syscall.h> |
36 |
|
|
37 |
|
#include <machine/reg.h> |
38 |
|
#include <machine/frame.h> |
39 |
|
|
50 |
– |
#include <err.h> |
51 |
– |
#include <errno.h> |
52 |
– |
#include <fcntl.h> |
53 |
– |
#include <signal.h> |
40 |
|
#include <stdio.h> |
55 |
– |
#include <stdlib.h> |
56 |
– |
#include <string.h> |
57 |
– |
#include <time.h> |
58 |
– |
#include <unistd.h> |
41 |
|
|
42 |
|
#include "truss.h" |
61 |
– |
#include "syscall.h" |
62 |
– |
#include "extern.h" |
43 |
|
|
44 |
|
#include "syscalls.h" |
45 |
|
|
46 |
< |
static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); |
47 |
< |
|
68 |
< |
/* |
69 |
< |
* This is what this particular file uses to keep track of a system call. |
70 |
< |
* It is probably not quite sufficient -- I can probably use the same |
71 |
< |
* structure for the various syscall personalities, and I also probably |
72 |
< |
* need to nest system calls (for signal handlers). |
73 |
< |
* |
74 |
< |
* 'struct syscall' describes the system call; it may be NULL, however, |
75 |
< |
* if we don't know about this particular system call yet. |
76 |
< |
*/ |
77 |
< |
struct freebsd_syscall { |
78 |
< |
struct syscall *sc; |
79 |
< |
const char *name; |
80 |
< |
int number; |
81 |
< |
unsigned long *args; |
82 |
< |
int nargs; /* number of arguments -- *not* number of words! */ |
83 |
< |
char **s_args; /* the printable arguments */ |
84 |
< |
}; |
85 |
< |
|
86 |
< |
static struct freebsd_syscall * |
87 |
< |
alloc_fsc(void) |
46 |
> |
static int |
47 |
> |
powerpc64_fetch_args(struct trussinfo *trussinfo, u_int narg) |
48 |
|
{ |
89 |
– |
|
90 |
– |
return (malloc(sizeof(struct freebsd_syscall))); |
91 |
– |
} |
92 |
– |
|
93 |
– |
/* Clear up and free parts of the fsc structure. */ |
94 |
– |
static void |
95 |
– |
free_fsc(struct freebsd_syscall *fsc) |
96 |
– |
{ |
97 |
– |
int i; |
98 |
– |
|
99 |
– |
free(fsc->args); |
100 |
– |
if (fsc->s_args) { |
101 |
– |
for (i = 0; i < fsc->nargs; i++) |
102 |
– |
free(fsc->s_args[i]); |
103 |
– |
free(fsc->s_args); |
104 |
– |
} |
105 |
– |
free(fsc); |
106 |
– |
} |
107 |
– |
|
108 |
– |
/* |
109 |
– |
* Called when a process has entered a system call. nargs is the |
110 |
– |
* number of words, not number of arguments (a necessary distinction |
111 |
– |
* in some cases). Note that if the STOPEVENT() code in powerpc/powerpc/trap.c |
112 |
– |
* is ever changed these functions need to keep up. |
113 |
– |
*/ |
114 |
– |
|
115 |
– |
void |
116 |
– |
powerpc64_syscall_entry(struct trussinfo *trussinfo, int nargs) |
117 |
– |
{ |
49 |
|
struct ptrace_io_desc iorequest; |
50 |
|
struct reg regs; |
51 |
< |
struct freebsd_syscall *fsc; |
121 |
< |
struct syscall *sc; |
122 |
< |
void *args; |
51 |
> |
struct current_syscall *cs; |
52 |
|
lwpid_t tid; |
53 |
< |
int i, regargs, syscall_num; |
53 |
> |
u_int i, reg; |
54 |
|
|
55 |
|
tid = trussinfo->curthread->tid; |
56 |
< |
|
56 |
> |
cs = &trussinfo->curthread->cs; |
57 |
|
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { |
58 |
|
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); |
59 |
< |
return; |
59 |
> |
return (-1); |
60 |
|
} |
61 |
|
|
62 |
|
/* |
63 |
< |
* FreeBSD has two special kinds of system call redirctions -- |
63 |
> |
* FreeBSD has two special kinds of system call redirections -- |
64 |
|
* SYS_syscall, and SYS___syscall. The former is the old syscall() |
65 |
|
* routine, basically; the latter is for quad-aligned arguments. |
66 |
+ |
* |
67 |
+ |
* The system call argument count and code from ptrace() already |
68 |
+ |
* account for these, but we need to skip over the first argument. |
69 |
|
*/ |
70 |
< |
regargs = NARGREG; |
71 |
< |
syscall_num = regs.fixreg[0]; |
72 |
< |
args = ®s.fixreg[3]; |
73 |
< |
if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) { |
74 |
< |
args = ®s.fixreg[4]; |
75 |
< |
regargs -= 1; |
144 |
< |
syscall_num = regs.fixreg[3]; |
70 |
> |
reg = 0; |
71 |
> |
switch (regs.fixreg[0]) { |
72 |
> |
case SYS_syscall: |
73 |
> |
case SYS___syscall: |
74 |
> |
reg += 1; |
75 |
> |
break; |
76 |
|
} |
77 |
|
|
78 |
< |
fsc = alloc_fsc(); |
79 |
< |
if (fsc == NULL) |
80 |
< |
return; |
150 |
< |
fsc->number = syscall_num; |
151 |
< |
fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? |
152 |
< |
NULL : syscallnames[syscall_num]; |
153 |
< |
if (!fsc->name) { |
154 |
< |
fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", |
155 |
< |
syscall_num); |
156 |
< |
} |
157 |
< |
|
158 |
< |
if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && |
159 |
< |
(strcmp(fsc->name, "fork") == 0 || |
160 |
< |
strcmp(fsc->name, "rfork") == 0 || |
161 |
< |
strcmp(fsc->name, "vfork") == 0)) |
162 |
< |
trussinfo->curthread->in_fork = 1; |
163 |
< |
|
164 |
< |
if (nargs == 0) |
165 |
< |
return; |
166 |
< |
|
167 |
< |
fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); |
168 |
< |
|
169 |
< |
if (nargs > regargs) { |
170 |
< |
memmove(&fsc->args[0], args, regargs * sizeof(fsc->args[0])); |
171 |
< |
|
78 |
> |
for (i = 0; i < narg && reg < NARGREG; i++, reg++) |
79 |
> |
cs->args[i] = regs.fixreg[FIRSTARG + reg]; |
80 |
> |
if (narg > i) { |
81 |
|
iorequest.piod_op = PIOD_READ_D; |
82 |
|
iorequest.piod_offs = (void *)(regs.fixreg[1] + 48); |
83 |
< |
iorequest.piod_addr = &fsc->args[regargs]; |
84 |
< |
iorequest.piod_len = (nargs - regargs) * sizeof(fsc->args[0]); |
83 |
> |
iorequest.piod_addr = &cs->args[i]; |
84 |
> |
iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); |
85 |
|
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); |
86 |
|
if (iorequest.piod_len == 0) |
87 |
< |
return; |
179 |
< |
} else |
180 |
< |
memmove(&fsc->args[0], args, nargs * sizeof(fsc->args[0])); |
181 |
< |
|
182 |
< |
sc = get_syscall(fsc->name); |
183 |
< |
if (sc) |
184 |
< |
fsc->nargs = sc->nargs; |
185 |
< |
else { |
186 |
< |
#if DEBUG |
187 |
< |
fprintf(trussinfo->outfile, "unknown syscall %s -- setting " |
188 |
< |
"args to %d\n", fsc->name, nargs); |
189 |
< |
#endif |
190 |
< |
fsc->nargs = nargs; |
87 |
> |
return (-1); |
88 |
|
} |
89 |
|
|
90 |
< |
fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); |
194 |
< |
fsc->sc = sc; |
195 |
< |
|
196 |
< |
/* |
197 |
< |
* At this point, we set up the system call arguments. |
198 |
< |
* We ignore any OUT ones, however -- those are arguments that |
199 |
< |
* are set by the system call, and so are probably meaningless |
200 |
< |
* now. This doesn't currently support arguments that are |
201 |
< |
* passed in *and* out, however. |
202 |
< |
*/ |
203 |
< |
|
204 |
< |
if (fsc->name) { |
205 |
< |
#if DEBUG |
206 |
< |
fprintf(stderr, "syscall %s(", fsc->name); |
207 |
< |
#endif |
208 |
< |
for (i = 0; i < fsc->nargs; i++) { |
209 |
< |
#if DEBUG |
210 |
< |
fprintf(stderr, "0x%x%s", sc ? |
211 |
< |
fsc->args[sc->args[i].offset] : fsc->args[i], |
212 |
< |
i < (fsc->nargs - 1) ? "," : ""); |
213 |
< |
#endif |
214 |
< |
if (sc && !(sc->args[i].type & OUT)) { |
215 |
< |
fsc->s_args[i] = print_arg(&sc->args[i], |
216 |
< |
fsc->args, 0, trussinfo); |
217 |
< |
} |
218 |
< |
} |
219 |
< |
#if DEBUG |
220 |
< |
fprintf(stderr, ")\n"); |
221 |
< |
#endif |
222 |
< |
} |
223 |
< |
|
224 |
< |
#if DEBUG |
225 |
< |
fprintf(trussinfo->outfile, "\n"); |
226 |
< |
#endif |
227 |
< |
|
228 |
< |
if (fsc->name && (strcmp(fsc->name, "execve") == 0 || |
229 |
< |
strcmp(fsc->name, "exit") == 0)) { |
230 |
< |
/* |
231 |
< |
* XXX |
232 |
< |
* This could be done in a more general |
233 |
< |
* manner but it still wouldn't be very pretty. |
234 |
< |
*/ |
235 |
< |
if (strcmp(fsc->name, "execve") == 0) { |
236 |
< |
if ((trussinfo->flags & EXECVEARGS) == 0) { |
237 |
< |
if (fsc->s_args[1]) { |
238 |
< |
free(fsc->s_args[1]); |
239 |
< |
fsc->s_args[1] = NULL; |
240 |
< |
} |
241 |
< |
} |
242 |
< |
if ((trussinfo->flags & EXECVEENVS) == 0) { |
243 |
< |
if (fsc->s_args[2]) { |
244 |
< |
free(fsc->s_args[2]); |
245 |
< |
fsc->s_args[2] = NULL; |
246 |
< |
} |
247 |
< |
} |
248 |
< |
} |
249 |
< |
} |
250 |
< |
trussinfo->curthread->fsc = fsc; |
90 |
> |
return (0); |
91 |
|
} |
92 |
|
|
93 |
< |
/* |
94 |
< |
* And when the system call is done, we handle it here. |
255 |
< |
* Currently, no attempt is made to ensure that the system calls |
256 |
< |
* match -- this needs to be fixed (and is, in fact, why S_SCX includes |
257 |
< |
* the system call number instead of, say, an error status). |
258 |
< |
*/ |
259 |
< |
|
260 |
< |
long |
261 |
< |
powerpc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) |
93 |
> |
static int |
94 |
> |
powerpc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) |
95 |
|
{ |
96 |
|
struct reg regs; |
264 |
– |
struct freebsd_syscall *fsc; |
265 |
– |
struct syscall *sc; |
97 |
|
lwpid_t tid; |
267 |
– |
long retval; |
268 |
– |
int errorp, i; |
98 |
|
|
270 |
– |
if (trussinfo->curthread->fsc == NULL) |
271 |
– |
return (-1); |
272 |
– |
|
99 |
|
tid = trussinfo->curthread->tid; |
274 |
– |
|
100 |
|
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { |
101 |
< |
fprintf(trussinfo->outfile, "\n"); |
101 |
> |
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); |
102 |
|
return (-1); |
103 |
|
} |
104 |
|
|
105 |
< |
retval = regs.fixreg[3]; |
106 |
< |
errorp = !!(regs.cr & 0x10000000); |
105 |
> |
retval[0] = regs.fixreg[3]; |
106 |
> |
retval[1] = regs.fixreg[4]; |
107 |
> |
*errorp = !!(regs.cr & 0x10000000); |
108 |
> |
return (0); |
109 |
> |
} |
110 |
|
|
111 |
< |
/* |
112 |
< |
* This code, while simpler than the initial versions I used, could |
113 |
< |
* stand some significant cleaning. |
114 |
< |
*/ |
111 |
> |
static struct procabi powerpc64_fbsd = { |
112 |
> |
"FreeBSD ELF64", |
113 |
> |
syscallnames, |
114 |
> |
nitems(syscallnames), |
115 |
> |
powerpc64_fetch_args, |
116 |
> |
powerpc64_fetch_retval |
117 |
> |
}; |
118 |
|
|
119 |
< |
fsc = trussinfo->curthread->fsc; |
289 |
< |
sc = fsc->sc; |
290 |
< |
if (!sc) { |
291 |
< |
for (i = 0; i < fsc->nargs; i++) |
292 |
< |
asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); |
293 |
< |
} else { |
294 |
< |
/* |
295 |
< |
* Here, we only look for arguments that have OUT masked in -- |
296 |
< |
* otherwise, they were handled in the syscall_entry function. |
297 |
< |
*/ |
298 |
< |
for (i = 0; i < sc->nargs; i++) { |
299 |
< |
char *temp; |
300 |
< |
if (sc->args[i].type & OUT) { |
301 |
< |
/* |
302 |
< |
* If an error occurred, then don't bother |
303 |
< |
* getting the data; it may not be valid. |
304 |
< |
*/ |
305 |
< |
if (errorp) { |
306 |
< |
asprintf(&temp, "0x%lx", |
307 |
< |
fsc->args[sc->args[i].offset]); |
308 |
< |
} else { |
309 |
< |
temp = print_arg(&sc->args[i], |
310 |
< |
fsc->args, retval, trussinfo); |
311 |
< |
} |
312 |
< |
fsc->s_args[i] = temp; |
313 |
< |
} |
314 |
< |
} |
315 |
< |
} |
316 |
< |
|
317 |
< |
if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || |
318 |
< |
strcmp(fsc->name, "exit") == 0)) |
319 |
< |
trussinfo->curthread->in_syscall = 1; |
320 |
< |
|
321 |
< |
/* |
322 |
< |
* It would probably be a good idea to merge the error handling, |
323 |
< |
* but that complicates things considerably. |
324 |
< |
*/ |
325 |
< |
|
326 |
< |
print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, |
327 |
< |
retval, fsc->sc); |
328 |
< |
free_fsc(fsc); |
329 |
< |
|
330 |
< |
return (retval); |
331 |
< |
} |
119 |
> |
PROCABI(powerpc64_fbsd); |