i386-fbsd.c revision 241162
1271294Sngie/* 2271294Sngie * Copyright 1997 Sean Eric Fagan 3271294Sngie * 4271294Sngie * Redistribution and use in source and binary forms, with or without 5271294Sngie * modification, are permitted provided that the following conditions 6271294Sngie * are met: 7271294Sngie * 1. Redistributions of source code must retain the above copyright 8271294Sngie * notice, this list of conditions and the following disclaimer. 9271294Sngie * 2. Redistributions in binary form must reproduce the above copyright 10271294Sngie * notice, this list of conditions and the following disclaimer in the 11271294Sngie * documentation and/or other materials provided with the distribution. 12271294Sngie * 3. All advertising materials mentioning features or use of this software 13271294Sngie * must display the following acknowledgement: 14271294Sngie * This product includes software developed by Sean Eric Fagan 15271294Sngie * 4. Neither the name of the author may be used to endorse or promote 16271294Sngie * products derived from this software without specific prior written 17271294Sngie * permission. 18275504Sngie * 19275504Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20275504Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21271294Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22271294Sngie * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23271294Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24271294Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25271294Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26271294Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27271294Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28271294Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29271294Sngie * SUCH DAMAGE. 30271294Sngie */ 31271294Sngie 32271294Sngie#ifndef lint 33275504Sngiestatic const char rcsid[] = 34271294Sngie "$FreeBSD: stable/9/usr.bin/truss/i386-fbsd.c 241162 2012-10-03 14:28:55Z zont $"; 35#endif /* not lint */ 36 37/* 38 * FreeBSD/i386-specific system call handling. This is probably the most 39 * complex part of the entire truss program, although I've got lots of 40 * it handled relatively cleanly now. The system call names are generated 41 * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 42 * names used for the various structures are confusing, I sadly admit. 43 */ 44 45#include <sys/types.h> 46#include <sys/ptrace.h> 47#include <sys/syscall.h> 48 49#include <machine/reg.h> 50#include <machine/psl.h> 51 52#include <errno.h> 53#include <fcntl.h> 54#include <signal.h> 55#include <stdio.h> 56#include <stdlib.h> 57#include <string.h> 58#include <time.h> 59#include <unistd.h> 60 61#include "truss.h" 62#include "syscall.h" 63#include "extern.h" 64 65#include "syscalls.h" 66 67static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 68 69/* 70 * This is what this particular file uses to keep track of a system call. 71 * It is probably not quite sufficient -- I can probably use the same 72 * structure for the various syscall personalities, and I also probably 73 * need to nest system calls (for signal handlers). 74 * 75 * 'struct syscall' describes the system call; it may be NULL, however, 76 * if we don't know about this particular system call yet. 77 */ 78struct freebsd_syscall { 79 struct syscall *sc; 80 const char *name; 81 int number; 82 unsigned long *args; 83 int nargs; /* number of arguments -- *not* number of words! */ 84 char **s_args; /* the printable arguments */ 85}; 86 87static struct freebsd_syscall * 88alloc_fsc(void) 89{ 90 91 return (malloc(sizeof(struct freebsd_syscall))); 92} 93 94/* Clear up and free parts of the fsc structure. */ 95static void 96free_fsc(struct freebsd_syscall *fsc) 97{ 98 int i; 99 100 free(fsc->args); 101 if (fsc->s_args) { 102 for (i = 0; i < fsc->nargs; i++) 103 free(fsc->s_args[i]); 104 free(fsc->s_args); 105 } 106 free(fsc); 107} 108 109/* 110 * Called when a process has entered a system call. nargs is the 111 * number of words, not number of arguments (a necessary distinction 112 * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 113 * is ever changed these functions need to keep up. 114 */ 115 116void 117i386_syscall_entry(struct trussinfo *trussinfo, int nargs) 118{ 119 struct ptrace_io_desc iorequest; 120 struct reg regs; 121 struct freebsd_syscall *fsc; 122 struct syscall *sc; 123 lwpid_t tid; 124 unsigned int parm_offset; 125 int i, syscall_num; 126 127 tid = trussinfo->curthread->tid; 128 129 if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 130 fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 131 return; 132 } 133 parm_offset = regs.r_esp + sizeof(int); 134 135 /* 136 * FreeBSD has two special kinds of system call redirctions -- 137 * SYS_syscall, and SYS___syscall. The former is the old syscall() 138 * routine, basically; the latter is for quad-aligned arguments. 139 */ 140 syscall_num = regs.r_eax; 141 switch (syscall_num) { 142 case SYS_syscall: 143 syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); 144 parm_offset += sizeof(int); 145 break; 146 case SYS___syscall: 147 syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); 148 parm_offset += sizeof(quad_t); 149 break; 150 } 151 152 fsc = alloc_fsc(); 153 if (fsc == NULL) 154 return; 155 fsc->number = syscall_num; 156 fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? 157 NULL : syscallnames[syscall_num]; 158 if (!fsc->name) { 159 fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", 160 syscall_num); 161 } 162 163 if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && 164 (strcmp(fsc->name, "fork") == 0 || 165 strcmp(fsc->name, "rfork") == 0 || 166 strcmp(fsc->name, "vfork") == 0)) 167 trussinfo->curthread->in_fork = 1; 168 169 if (nargs == 0) 170 return; 171 172 fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); 173 iorequest.piod_op = PIOD_READ_D; 174 iorequest.piod_offs = (void *)parm_offset; 175 iorequest.piod_addr = fsc->args; 176 iorequest.piod_len = (1 + nargs) * sizeof(unsigned long); 177 ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); 178 if (iorequest.piod_len == 0) 179 return; 180 181 sc = NULL; 182 if (fsc->name) 183 sc = get_syscall(fsc->name); 184 if (sc) 185 fsc->nargs = sc->nargs; 186 else { 187#if DEBUG 188 fprintf(trussinfo->outfile, "unknown syscall %s -- setting " 189 "args to %d\n", fsc->name, nargs); 190#endif 191 fsc->nargs = nargs; 192 } 193 194 fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); 195 fsc->sc = sc; 196 197 /* 198 * At this point, we set up the system call arguments. 199 * We ignore any OUT ones, however -- those are arguments that 200 * are set by the system call, and so are probably meaningless 201 * now. This doesn't currently support arguments that are 202 * passed in *and* out, however. 203 */ 204 205 if (fsc->name) { 206#if DEBUG 207 fprintf(stderr, "syscall %s(", fsc->name); 208#endif 209 for (i = 0; i < fsc->nargs; i++) { 210#if DEBUG 211 fprintf(stderr, "0x%x%s", sc ? 212 fsc->args[sc->args[i].offset] : fsc->args[i], 213 i < (fsc->nargs - 1) ? "," : ""); 214#endif 215 if (sc && !(sc->args[i].type & OUT)) { 216 fsc->s_args[i] = print_arg(&sc->args[i], 217 fsc->args, 0, trussinfo); 218 } 219 } 220#if DEBUG 221 fprintf(stderr, ")\n"); 222#endif 223 } 224 225#if DEBUG 226 fprintf(trussinfo->outfile, "\n"); 227#endif 228 229 if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || 230 strcmp(fsc->name, "exit") == 0)) { 231 /* 232 * XXX 233 * This could be done in a more general 234 * manner but it still wouldn't be very pretty. 235 */ 236 if (strcmp(fsc->name, "execve") == 0) { 237 if ((trussinfo->flags & EXECVEARGS) == 0) { 238 if (fsc->s_args[1]) { 239 free(fsc->s_args[1]); 240 fsc->s_args[1] = NULL; 241 } 242 } 243 if ((trussinfo->flags & EXECVEENVS) == 0) { 244 if (fsc->s_args[2]) { 245 free(fsc->s_args[2]); 246 fsc->s_args[2] = NULL; 247 } 248 } 249 } 250 } 251 trussinfo->curthread->fsc = fsc; 252} 253 254/* 255 * And when the system call is done, we handle it here. 256 * Currently, no attempt is made to ensure that the system calls 257 * match -- this needs to be fixed (and is, in fact, why S_SCX includes 258 * the system call number instead of, say, an error status). 259 */ 260 261long 262i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 263{ 264 struct reg regs; 265 struct freebsd_syscall *fsc; 266 struct syscall *sc; 267 lwpid_t tid; 268 long retval; 269 int errorp, i; 270 271 if (trussinfo->curthread->fsc == NULL) 272 return (-1); 273 274 tid = trussinfo->curthread->tid; 275 276 if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 277 fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 278 return (-1); 279 } 280 281 retval = regs.r_eax; 282 errorp = !!(regs.r_eflags & PSL_C); 283 284 /* 285 * This code, while simpler than the initial versions I used, could 286 * stand some significant cleaning. 287 */ 288 289 fsc = trussinfo->curthread->fsc; 290 sc = fsc->sc; 291 if (!sc) { 292 for (i = 0; i < fsc->nargs; i++) 293 asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); 294 } else { 295 /* 296 * Here, we only look for arguments that have OUT masked in -- 297 * otherwise, they were handled in the syscall_entry function. 298 */ 299 for (i = 0; i < sc->nargs; i++) { 300 char *temp; 301 if (sc->args[i].type & OUT) { 302 /* 303 * If an error occurred, then don't bother 304 * getting the data; it may not be valid. 305 */ 306 if (errorp) { 307 asprintf(&temp, "0x%lx", 308 fsc->args[sc->args[i].offset]); 309 } else { 310 temp = print_arg(&sc->args[i], 311 fsc->args, retval, trussinfo); 312 } 313 fsc->s_args[i] = temp; 314 } 315 } 316 } 317 318 if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || 319 strcmp(fsc->name, "exit") == 0)) 320 trussinfo->curthread->in_syscall = 1; 321 322 /* 323 * It would probably be a good idea to merge the error handling, 324 * but that complicates things considerably. 325 */ 326 327 print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, 328 retval, fsc->sc); 329 free_fsc(fsc); 330 331 return (retval); 332} 333