ia64-fbsd.c revision 111176
174462Salfred/* 274462Salfred * Copryight 1997 Sean Eric Fagan 3258578Shrs * 4258578Shrs * Redistribution and use in source and binary forms, with or without 5258578Shrs * modification, are permitted provided that the following conditions 6258578Shrs * are met: 7258578Shrs * 1. Redistributions of source code must retain the above copyright 8258578Shrs * notice, this list of conditions and the following disclaimer. 9258578Shrs * 2. Redistributions in binary form must reproduce the above copyright 10258578Shrs * notice, this list of conditions and the following disclaimer in the 11258578Shrs * documentation and/or other materials provided with the distribution. 12258578Shrs * 3. All advertising materials mentioning features or use of this software 13258578Shrs * must display the following acknowledgement: 14258578Shrs * This product includes software developed by Sean Eric Fagan 15258578Shrs * 4. Neither the name of the author may be used to endorse or promote 16258578Shrs * products derived from this software without specific prior written 1774462Salfred * permission. 18258578Shrs * 19258578Shrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20258578Shrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21258578Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22258578Shrs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23258578Shrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24258578Shrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25258578Shrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26258578Shrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27258578Shrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28258578Shrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2974462Salfred * SUCH DAMAGE. 3074462Salfred */ 3174462Salfred 3274462Salfred#ifndef lint 3374462Salfredstatic const char rcsid[] = 34136581Sobrien "$FreeBSD: head/usr.bin/truss/ia64-fbsd.c 111176 2003-02-20 15:05:39Z ru $"; 35136581Sobrien#endif /* not lint */ 3674462Salfred 3774462Salfred/* 3892990Sobrien * FreeBSD/ia64-specific system call handling. This is probably the most 3992990Sobrien * complex part of the entire truss program, although I've got lots of 4074462Salfred * it handled relatively cleanly now. The system call names are generated 4174462Salfred * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 4274462Salfred * names used for the various structures are confusing, I sadly admit. 4374462Salfred */ 4474462Salfred 4575094Siedowse#include <sys/types.h> 4674462Salfred#include <sys/ioctl.h> 4774462Salfred#include <sys/pioctl.h> 48105189Siedowse#include <sys/syscall.h> 4974462Salfred 5074462Salfred#include <machine/reg.h> 5174462Salfred 5290868Smike#include <errno.h> 5374462Salfred#include <fcntl.h> 54181344Sdfr#include <signal.h> 5574462Salfred#include <stdio.h> 5674462Salfred#include <stdlib.h> 5774462Salfred#include <string.h> 5874462Salfred#include <time.h> 5974462Salfred#include <unistd.h> 6074462Salfred 6174462Salfred#include "truss.h" 6274462Salfred#include "syscall.h" 63156090Sdeischen#include "extern.h" 6474462Salfred 6574462Salfredstatic int fd = -1; 66167199Ssimonstatic int cpid = -1; 67167199Ssimonextern int Procfd; 68167199Ssimon 69167199Ssimon#include "syscalls.h" 70167199Ssimon 71167199Ssimonstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 7274462Salfred 73167199Ssimon/* 7474462Salfred * This is what this particular file uses to keep track of a system call. 7574462Salfred * It is probably not quite sufficient -- I can probably use the same 7692905Sobrien * structure for the various syscall personalities, and I also probably 7792905Sobrien * need to nest system calls (for signal handlers). 7895658Sdes * 7995658Sdes * 'struct syscall' describes the system call; it may be NULL, however, 8092905Sobrien * if we don't know about this particular system call yet. 8195658Sdes */ 8292905Sobrienstatic struct freebsd_syscall { 8399996Salfred struct syscall *sc; 8492905Sobrien const char *name; 8574462Salfred int number; 8674462Salfred unsigned long *args; 8774462Salfred int nargs; /* number of arguments -- *not* number of words! */ 8874462Salfred char **s_args; /* the printable arguments */ 8974462Salfred} fsc; 9074462Salfred 9174462Salfred/* Clear up and free parts of the fsc structure. */ 9274462Salfredstatic __inline void 9374462Salfredclear_fsc(void) { 9474462Salfred if (fsc.args) { 9574462Salfred free(fsc.args); 9674462Salfred } 9774462Salfred if (fsc.s_args) { 9874462Salfred int i; 9974462Salfred for (i = 0; i < fsc.nargs; i++) 10074462Salfred if (fsc.s_args[i]) 10174462Salfred free(fsc.s_args[i]); 10274462Salfred free(fsc.s_args); 10374462Salfred } 10474462Salfred memset(&fsc, 0, sizeof(fsc)); 10574462Salfred} 10675144Siedowse 10774462Salfred/* 108105189Siedowse * Called when a process has entered a system call. nargs is the 10974462Salfred * number of words, not number of arguments (a necessary distinction 11074462Salfred * in some cases). Note that if the STOPEVENT() code in ia64/ia64/trap.c 11174462Salfred * is ever changed these functions need to keep up. 11274462Salfred */ 11374462Salfred 11474462Salfredvoid 11574462Salfredia64_syscall_entry(struct trussinfo *trussinfo, int nargs) { 116181344Sdfr char buf[32]; 117181344Sdfr struct reg regs; 11874462Salfred int syscall_num; 11974462Salfred int i; 12074462Salfred unsigned int parm_offset; 12174462Salfred struct syscall *sc; 12274462Salfred 12374462Salfred if (fd == -1 || trussinfo->pid != cpid) { 12474462Salfred sprintf(buf, "/proc/%d/regs", trussinfo->pid); 12574462Salfred fd = open(buf, O_RDWR); 12674462Salfred if (fd == -1) { 12774462Salfred fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n"); 12874462Salfred return; 12974462Salfred } 13074462Salfred cpid = trussinfo->pid; 13174462Salfred } 132181344Sdfr 13374462Salfred clear_fsc(); 13474462Salfred lseek(fd, 0L, 0); 13574879Swpaul if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 13678678Siedowse fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 13778678Siedowse return; 138105189Siedowse } 139105189Siedowse parm_offset = regs.r_gr[12] + 16; 14074462Salfred 14174462Salfred /* 14274462Salfred * FreeBSD has two special kinds of system call redirctions -- 14374462Salfred * SYS_syscall, and SYS___syscall. The former is the old syscall() 14474462Salfred * routine, basicly; the latter is for quad-aligned arguments. 14574462Salfred */ 14674462Salfred syscall_num = regs.r_gr[15]; 14774462Salfred switch (syscall_num) { 14874462Salfred case SYS_syscall: 14974462Salfred lseek(Procfd, parm_offset, SEEK_SET); 15074462Salfred read(Procfd, &syscall_num, sizeof(int)); 15174462Salfred parm_offset += sizeof(int); 15274462Salfred break; 15374462Salfred case SYS___syscall: 15474462Salfred lseek(Procfd, parm_offset, SEEK_SET); 15574462Salfred read(Procfd, &syscall_num, sizeof(int)); 156287341Srodrigc parm_offset += sizeof(quad_t); 157287341Srodrigc break; 158287341Srodrigc } 159287341Srodrigc 160287341Srodrigc fsc.number = syscall_num; 161287341Srodrigc fsc.name = (syscall_num < 0 || syscall_num > nsyscalls) 162287341Srodrigc ? NULL : syscallnames[syscall_num]; 16374462Salfred if (!fsc.name) { 16474462Salfred fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num); 165287341Srodrigc } 166287341Srodrigc 16774462Salfred if (fsc.name && (trussinfo->flags & FOLLOWFORKS) 16874462Salfred && ((!strcmp(fsc.name, "fork") 16974462Salfred || !strcmp(fsc.name, "rfork") 17074462Salfred || !strcmp(fsc.name, "vfork")))) 17174462Salfred { 17274462Salfred trussinfo->in_fork = 1; 17374462Salfred } 17474462Salfred 17574462Salfred if (nargs == 0) 17674462Salfred return; 17774462Salfred 17874462Salfred fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 17974462Salfred lseek(Procfd, parm_offset, SEEK_SET); 18074462Salfred if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 18174462Salfred return; 18274462Salfred 18374462Salfred sc = get_syscall(fsc.name); 18474462Salfred if (sc) { 18574462Salfred fsc.nargs = sc->nargs; 18674462Salfred } else { 18774462Salfred#if DEBUG 18874462Salfred fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", 18974462Salfred fsc.name, nargs); 19074462Salfred#endif 19174462Salfred fsc.nargs = nargs; 19274462Salfred } 19374462Salfred 19474462Salfred fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 19574462Salfred memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 19674462Salfred fsc.sc = sc; 19774462Salfred 19874462Salfred /* 19974462Salfred * At this point, we set up the system call arguments. 20074462Salfred * We ignore any OUT ones, however -- those are arguments that 20174462Salfred * are set by the system call, and so are probably meaningless 20274462Salfred * now. This doesn't currently support arguments that are 20374462Salfred * passed in *and* out, however. 20474462Salfred */ 20574462Salfred 20674462Salfred if (fsc.name) { 20774462Salfred 20874462Salfred#if DEBUG 20974462Salfred fprintf(stderr, "syscall %s(", fsc.name); 21074462Salfred#endif 21174462Salfred for (i = 0; i < fsc.nargs; i++) { 21274462Salfred#if DEBUG 21374462Salfred fprintf(stderr, "0x%x%s", 21474462Salfred sc 21574462Salfred ? fsc.args[sc->args[i].offset] 21674462Salfred : fsc.args[i], 21774462Salfred i < (fsc.nargs - 1) ? "," : ""); 21874462Salfred#endif 21974462Salfred if (sc && !(sc->args[i].type & OUT)) { 22074462Salfred fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 22174462Salfred } 22274462Salfred } 22374462Salfred#if DEBUG 22474462Salfred fprintf(stderr, ")\n"); 22574462Salfred#endif 22674462Salfred } 22774462Salfred 22874462Salfred#if DEBUG 22974462Salfred fprintf(trussinfo->outfile, "\n"); 23074462Salfred#endif 23174462Salfred 23274462Salfred /* 23374462Salfred * Some system calls should be printed out before they are done -- 23474462Salfred * execve() and exit(), for example, never return. Possibly change 23574462Salfred * this to work for any system call that doesn't have an OUT 23674462Salfred * parameter? 23774462Salfred */ 23874462Salfred 23974462Salfred if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 24074462Salfred 24174462Salfred /* XXX 24274462Salfred * This could be done in a more general 24374462Salfred * manner but it still wouldn't be very pretty. 24474462Salfred */ 24574462Salfred if (!strcmp(fsc.name, "execve")) { 24674462Salfred if ((trussinfo->flags & EXECVEARGS) == 0) 24774462Salfred if (fsc.s_args[1]) { 24874462Salfred free(fsc.s_args[1]); 24974462Salfred fsc.s_args[1] = NULL; 25074462Salfred } 25174462Salfred if ((trussinfo->flags & EXECVEENVS) == 0) 25274462Salfred if (fsc.s_args[2]) { 25374462Salfred free(fsc.s_args[2]); 25474879Swpaul fsc.s_args[2] = NULL; 25578678Siedowse } 25678678Siedowse } 25774462Salfred 25874462Salfred print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); 25974462Salfred fprintf(trussinfo->outfile, "\n"); 26074462Salfred } 261181344Sdfr 262181344Sdfr return; 263181344Sdfr} 26474462Salfred 26574462Salfred/* 26674462Salfred * And when the system call is done, we handle it here. 26774462Salfred * Currently, no attempt is made to ensure that the system calls 26874462Salfred * match -- this needs to be fixed (and is, in fact, why S_SCX includes 269181344Sdfr * the sytem call number instead of, say, an error status). 270181344Sdfr */ 27174462Salfred 27274462Salfredint 27374462Salfredia64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) { 27474462Salfred char buf[32]; 27574462Salfred struct reg regs; 27674462Salfred int retval; 27774462Salfred int i; 27874462Salfred int errorp; 27974462Salfred struct syscall *sc; 28074462Salfred 28174462Salfred if (fd == -1 || trussinfo->pid != cpid) { 28274462Salfred sprintf(buf, "/proc/%d/regs", trussinfo->pid); 28374462Salfred fd = open(buf, O_RDONLY); 28474462Salfred if (fd == -1) { 28574462Salfred fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n"); 28674462Salfred return (-1); 28774462Salfred } 28874462Salfred cpid = trussinfo->pid; 28974462Salfred } 290105189Siedowse 291105189Siedowse lseek(fd, 0L, 0); 29274462Salfred if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 29374462Salfred fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 29474462Salfred return (-1); 29574462Salfred } 29674462Salfred retval = regs.r_gr[8]; 29774462Salfred errorp = (regs.r_gr[10] != 0) ? 1 : 0; 29874462Salfred 29974462Salfred /* 30074462Salfred * This code, while simpler than the initial versions I used, could 30174462Salfred * stand some significant cleaning. 30274462Salfred */ 30374462Salfred 30474462Salfred sc = fsc.sc; 30574462Salfred if (!sc) { 306287341Srodrigc for (i = 0; i < fsc.nargs; i++) { 307287341Srodrigc fsc.s_args[i] = malloc(12); 308287341Srodrigc sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 309287341Srodrigc } 310287341Srodrigc } else { 311287341Srodrigc /* 312287341Srodrigc * Here, we only look for arguments that have OUT masked in -- 313287341Srodrigc * otherwise, they were handled in the syscall_entry function. 314287341Srodrigc */ 31574462Salfred for (i = 0; i < sc->nargs; i++) { 316287341Srodrigc char *temp; 317287341Srodrigc if (sc->args[i].type & OUT) { 31874462Salfred /* 31974462Salfred * If an error occurred, than don't bothe getting the data; 32074462Salfred * it may not be valid. 321105189Siedowse */ 32274462Salfred if (errorp) { 32374462Salfred temp = malloc(12); 32474462Salfred sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 32574462Salfred } else { 326181344Sdfr temp = print_arg(Procfd, &sc->args[i], fsc.args); 32774462Salfred } 32874462Salfred fsc.s_args[i] = temp; 329105189Siedowse } 330105189Siedowse } 331105189Siedowse } 33278678Siedowse 33374462Salfred /* 33474462Salfred * It would probably be a good idea to merge the error handling, 335278932Spfg * but that complicates things considerably. 33674462Salfred */ 337105189Siedowse 33874879Swpaul print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); 33974462Salfred clear_fsc(); 34090271Salfred 34174462Salfred return (retval); 34274462Salfred} 34374462Salfred