syscalls.c revision 122348
131567Ssef/* 231899Ssef * Copryight 1997 Sean Eric Fagan 331899Ssef * 431899Ssef * Redistribution and use in source and binary forms, with or without 531899Ssef * modification, are permitted provided that the following conditions 631899Ssef * are met: 731899Ssef * 1. Redistributions of source code must retain the above copyright 831899Ssef * notice, this list of conditions and the following disclaimer. 931899Ssef * 2. Redistributions in binary form must reproduce the above copyright 1031899Ssef * notice, this list of conditions and the following disclaimer in the 1131899Ssef * documentation and/or other materials provided with the distribution. 1231899Ssef * 3. All advertising materials mentioning features or use of this software 1331899Ssef * must display the following acknowledgement: 1431899Ssef * This product includes software developed by Sean Eric Fagan 1531899Ssef * 4. Neither the name of the author may be used to endorse or promote 1631899Ssef * products derived from this software without specific prior written 1731899Ssef * permission. 1831899Ssef * 1931899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2031899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2131899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2231899Ssef * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2331899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2431899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2531899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2631899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2731899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2831899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2931899Ssef * SUCH DAMAGE. 3031899Ssef */ 3131899Ssef 3232275Scharnier#ifndef lint 3332275Scharnierstatic const char rcsid[] = 3450477Speter "$FreeBSD: head/usr.bin/truss/syscalls.c 122348 2003-11-09 03:48:13Z marcel $"; 3532275Scharnier#endif /* not lint */ 3632275Scharnier 3731899Ssef/* 3831567Ssef * This file has routines used to print out system calls and their 3931567Ssef * arguments. 4031567Ssef */ 4131567Ssef 4285292Sdes#include <sys/types.h> 4385292Sdes#include <sys/socket.h> 44104581Smike#include <sys/time.h> 4585292Sdes#include <sys/un.h> 4685292Sdes#include <netinet/in.h> 4785292Sdes#include <arpa/inet.h> 4885292Sdes 4986138Sgreen#include <ctype.h> 5032275Scharnier#include <err.h> 5185292Sdes#include <signal.h> 5231567Ssef#include <stdio.h> 5331567Ssef#include <stdlib.h> 5431567Ssef#include <string.h> 55101423Smdodd#include <time.h> 5631567Ssef#include <unistd.h> 5785292Sdes 58101282Smdodd#include "truss.h" 5987703Smarkm#include "extern.h" 6031567Ssef#include "syscall.h" 6131567Ssef 6231567Ssef/* 6331567Ssef * This should probably be in its own file. 6431567Ssef */ 6531567Ssef 6631567Ssefstruct syscall syscalls[] = { 6731567Ssef { "readlink", 1, 3, 6831567Ssef { { String, 0 } , { String | OUT, 1 }, { Int, 2 }}}, 6931567Ssef { "lseek", 2, 3, 7031567Ssef { { Int, 0 }, {Quad, 2 }, { Int, 4 }}}, 7131567Ssef { "mmap", 2, 6, 7231567Ssef { { Hex, 0 }, {Int, 1}, {Hex, 2}, {Hex, 3}, {Int, 4}, {Quad, 6}}}, 7331567Ssef { "open", 1, 3, 7488726Salfred { { String | IN, 0} , { Hex, 1}, {Octal, 2}}}, 7531567Ssef { "linux_open", 1, 3, 7688726Salfred { { String, 0 }, { Hex, 1}, { Octal, 2 }}}, 77113501Smdodd { "close", 1, 1, 78113501Smdodd { { Int, 0 } } }, 79113501Smdodd { "link", 0, 2, 80113501Smdodd { { String, 0 }, { String, 1 }}}, 81113501Smdodd { "unlink", 0, 1, 82113501Smdodd { { String, 0 }}}, 83113501Smdodd { "chdir", 0, 1, 84113501Smdodd { { String, 0 }}}, 85113501Smdodd { "mknod", 0, 3, 86113501Smdodd { { String, 0 }, { Octal, 1 }, { Int, 3 }}}, 87113501Smdodd { "chmod", 0, 2, 88113501Smdodd { { String, 0 }, { Octal, 1 }}}, 89113501Smdodd { "chown", 0, 3, 90113501Smdodd { { String, 0 }, { Int, 1 }, { Int, 2 }}}, 91113501Smdodd { "mount", 0, 4, 92113501Smdodd { { String, 0 }, { String, 1 }, { Int, 2 }, { Ptr, 3 }}}, 93113501Smdodd { "umount", 0, 2, 94113501Smdodd { { String, 0 }, { Int, 2 }}}, 9531567Ssef { "fstat", 1, 2, 9631567Ssef { { Int, 0}, {Ptr | OUT , 1 }}}, 9731567Ssef { "stat", 1, 2, 9831567Ssef { { String | IN, 0 }, { Ptr | OUT, 1 }}}, 9940370Ssef { "lstat", 1, 2, 10040370Ssef { { String | IN, 0 }, { Ptr | OUT, 1 }}}, 10131567Ssef { "linux_newstat", 1, 2, 10231567Ssef { { String | IN, 0 }, { Ptr | OUT, 1 }}}, 10331567Ssef { "linux_newfstat", 1, 2, 10431567Ssef { { Int, 0 }, { Ptr | OUT, 1 }}}, 10531567Ssef { "write", 1, 3, 106118483Sdes { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 }}}, 10731571Ssef { "ioctl", 1, 3, 108118483Sdes { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 }}}, 10931567Ssef { "break", 1, 1, { { Hex, 0 }}}, 11031567Ssef { "exit", 0, 1, { { Hex, 0 }}}, 11149436Sdes { "access", 1, 2, { { String | IN, 0 }, { Int, 1 }}}, 11249609Sdes { "sigaction", 1, 3, 11349609Sdes { { Signal, 0 }, { Ptr | IN, 1 }, { Ptr | OUT, 2 }}}, 11485292Sdes { "accept", 1, 3, 11585292Sdes { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 11685292Sdes { "bind", 1, 3, 11785292Sdes { { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 11885292Sdes { "connect", 1, 3, 11985292Sdes { { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 12085292Sdes { "getpeername", 1, 3, 12185292Sdes { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 12285292Sdes { "getsockname", 1, 3, 12385292Sdes { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 124118483Sdes { "recvfrom", 1, 6, 125118483Sdes { { Hex, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, 126118483Sdes { "sendto", 1, 6, 127118483Sdes { { Hex, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } }, 128101289Smdodd { "execve", 1, 3, 129101289Smdodd { { String | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 130101289Smdodd { "linux_execve", 1, 3, 131101289Smdodd { { String | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 132113501Smdodd { "kldload", 0, 1, { { String | IN, 0 }}}, 133113501Smdodd { "kldunload", 0, 1, { { Int, 0 }}}, 134113501Smdodd { "kldfind", 0, 1, { { String | IN, 0 }}}, 135113501Smdodd { "kldnext", 0, 1, { { Int, 0 }}}, 136113501Smdodd { "kldstat", 0, 2, { { Int, 0 }, { Ptr, 1 }}}, 137113501Smdodd { "kldfirstmod", 0, 1, { { Int, 0 }}}, 13832275Scharnier { 0, 0, 0, { { 0, 0 }}}, 13931567Ssef}; 14031567Ssef 14131567Ssef/* 14231567Ssef * If/when the list gets big, it might be desirable to do it 14331567Ssef * as a hash table or binary search. 14431567Ssef */ 14531567Ssef 14631567Ssefstruct syscall * 14731567Ssefget_syscall(const char *name) { 14831567Ssef struct syscall *sc = syscalls; 14931567Ssef 15031567Ssef while (sc->name) { 15131567Ssef if (!strcmp(name, sc->name)) 15231567Ssef return sc; 15331567Ssef sc++; 15431567Ssef } 15531567Ssef return NULL; 15631567Ssef} 15731567Ssef 15831567Ssef/* 15985292Sdes * get_struct 16085292Sdes * 16185292Sdes * Copy a fixed amount of bytes from the process. 16285292Sdes */ 16385292Sdes 16487703Smarkmstatic int 16585292Sdesget_struct(int procfd, void *offset, void *buf, int len) { 16685292Sdes char *pos; 16785292Sdes FILE *p; 16885292Sdes int c, fd; 16985292Sdes 17085292Sdes if ((fd = dup(procfd)) == -1) 17185292Sdes err(1, "dup"); 17285292Sdes if ((p = fdopen(fd, "r")) == NULL) 17385292Sdes err(1, "fdopen"); 17495225Sdwmalone fseeko(p, (uintptr_t)offset, SEEK_SET); 17585292Sdes for (pos = (char *)buf; len--; pos++) { 17685292Sdes if ((c = fgetc(p)) == EOF) 17785292Sdes return -1; 17885292Sdes *pos = c; 17985292Sdes } 18085292Sdes fclose(p); 18185292Sdes return 0; 18285292Sdes} 18385292Sdes 18485292Sdes/* 18531567Ssef * get_string 18631567Ssef * Copy a string from the process. Note that it is 18731567Ssef * expected to be a C string, but if max is set, it will 18831567Ssef * only get that much. 18931567Ssef */ 19031567Ssef 19131567Ssefchar * 19231567Ssefget_string(int procfd, void *offset, int max) { 19332275Scharnier char *buf; 19457245Ssef int size, len, c, fd; 19531567Ssef FILE *p; 19631567Ssef 19757245Ssef if ((fd = dup(procfd)) == -1) 19857245Ssef err(1, "dup"); 19957245Ssef if ((p = fdopen(fd, "r")) == NULL) 20032275Scharnier err(1, "fdopen"); 20131567Ssef buf = malloc( size = (max ? max : 64 ) ); 20231567Ssef len = 0; 20382471Sjoerg buf[0] = 0; 20495225Sdwmalone fseeko(p, (uintptr_t)offset, SEEK_SET); 20531567Ssef while ((c = fgetc(p)) != EOF) { 20631567Ssef buf[len++] = c; 20731567Ssef if (c == 0 || len == max) { 20831567Ssef buf[len] = 0; 20931567Ssef break; 21031567Ssef } 21131567Ssef if (len == size) { 21257245Ssef char *tmp; 21331567Ssef tmp = realloc(buf, size+64); 21431567Ssef if (tmp == NULL) { 21531567Ssef buf[len] = 0; 21657245Ssef fclose(p); 21731567Ssef return buf; 21831567Ssef } 21931567Ssef size += 64; 22057245Ssef buf = tmp; 22131567Ssef } 22231567Ssef } 22357245Ssef fclose(p); 22431567Ssef return buf; 22531567Ssef} 22631567Ssef 22731567Ssef 22831567Ssef/* 22931567Ssef * Gag. This is really unportable. Multiplication is more portable. 23031567Ssef * But slower, from the code I saw. 23131567Ssef */ 23231567Ssef 23331567Ssefstatic long long 23431567Ssefmake_quad(unsigned long p1, unsigned long p2) { 23531567Ssef union { 23631567Ssef long long ll; 23731567Ssef unsigned long l[2]; 23831567Ssef } t; 23931567Ssef t.l[0] = p1; 24031567Ssef t.l[1] = p2; 24131567Ssef return t.ll; 24231567Ssef} 24331567Ssef 24431567Ssef 24531567Ssef/* 24631567Ssef * print_arg 24731567Ssef * Converts a syscall argument into a string. Said string is 24831567Ssef * allocated via malloc(), so needs to be free()'d. The file 24931567Ssef * descriptor is for the process' memory (via /proc), and is used 25031567Ssef * to get any data (where the argument is a pointer). sc is 25131567Ssef * a pointer to the syscall description (see above); args is 25231567Ssef * an array of all of the system call arguments. 25331567Ssef */ 25431567Ssef 25531567Ssefchar * 25631567Ssefprint_arg(int fd, struct syscall_args *sc, unsigned long *args) { 25732275Scharnier char *tmp = NULL; 25831567Ssef switch (sc->type & ARG_MASK) { 25931567Ssef case Hex: 260122348Smarcel asprintf(&tmp, "0x%lx", args[sc->offset]); 26131567Ssef break; 26231567Ssef case Octal: 263122348Smarcel asprintf(&tmp, "0%lo", args[sc->offset]); 26431567Ssef break; 26531567Ssef case Int: 266122348Smarcel asprintf(&tmp, "%ld", args[sc->offset]); 26731567Ssef break; 26831567Ssef case String: 26931567Ssef { 27031567Ssef char *tmp2; 27131567Ssef tmp2 = get_string(fd, (void*)args[sc->offset], 0); 272122348Smarcel asprintf(&tmp, "\"%s\"", tmp2); 27331567Ssef free(tmp2); 27431567Ssef } 27531567Ssef break; 276101289Smdodd case StringArray: 277101289Smdodd { 278101289Smdodd int num, size, i; 279101289Smdodd char *tmp2; 280101289Smdodd char *string; 281101289Smdodd char *strarray[100]; /* XXX This is ugly. */ 282101289Smdodd 283101289Smdodd if (get_struct(fd, (void *)args[sc->offset], (void *)&strarray, 284101289Smdodd sizeof(strarray)) == -1) { 285101289Smdodd err(1, "get_struct %p", (void *)args[sc->offset]); 286101289Smdodd } 287101289Smdodd num = 0; 288101289Smdodd size = 0; 289101289Smdodd 290101289Smdodd /* Find out how large of a buffer we'll need. */ 291101289Smdodd while (strarray[num] != NULL) { 292101289Smdodd string = get_string(fd, (void*)strarray[num], 0); 293101289Smdodd size += strlen(string); 294101289Smdodd free(string); 295101289Smdodd num++; 296101289Smdodd } 297101289Smdodd size += 4 + (num * 4); 298101289Smdodd tmp = (char *)malloc(size); 299101289Smdodd tmp2 = tmp; 300101289Smdodd 301101289Smdodd tmp2 += sprintf(tmp2, " ["); 302101289Smdodd for (i = 0; i < num; i++) { 303101289Smdodd string = get_string(fd, (void*)strarray[i], 0); 304101289Smdodd tmp2 += sprintf(tmp2, " \"%s\"%c", string, (i+1 == num) ? ' ' : ','); 305101289Smdodd free(string); 306101289Smdodd } 307101289Smdodd tmp2 += sprintf(tmp2, "]"); 308101289Smdodd } 309101289Smdodd break; 31031567Ssef case Quad: 31131567Ssef { 31231567Ssef unsigned long long t; 31331567Ssef unsigned long l1, l2; 31431567Ssef l1 = args[sc->offset]; 31531567Ssef l2 = args[sc->offset+1]; 31631567Ssef t = make_quad(l1, l2); 317122348Smarcel asprintf(&tmp, "0x%qx", t); 31831567Ssef break; 31931567Ssef } 32031567Ssef case Ptr: 321122348Smarcel asprintf(&tmp, "0x%lx", args[sc->offset]); 32231567Ssef break; 32331571Ssef case Ioctl: 32431571Ssef { 32587703Smarkm const char *temp = ioctlname(args[sc->offset]); 32631571Ssef if (temp) 32731571Ssef tmp = strdup(temp); 328122348Smarcel else 329122348Smarcel asprintf(&tmp, "0x%lx", args[sc->offset]); 33031571Ssef } 33149609Sdes break; 33249609Sdes case Signal: 33349609Sdes { 33449609Sdes long sig; 33549609Sdes 33649609Sdes sig = args[sc->offset]; 33749609Sdes if (sig > 0 && sig < NSIG) { 33849609Sdes int i; 339122348Smarcel asprintf(&tmp, "sig%s", sys_signame[sig]); 34049609Sdes for (i = 0; tmp[i] != '\0'; ++i) 34149609Sdes tmp[i] = toupper(tmp[i]); 342122348Smarcel } else 343122348Smarcel asprintf(&tmp, "%ld", sig); 34449609Sdes } 34549609Sdes break; 34685292Sdes case Sockaddr: 34785292Sdes { 34886138Sgreen struct sockaddr_storage ss; 34986138Sgreen char addr[64]; 35087703Smarkm struct sockaddr_in *lsin; 35187703Smarkm struct sockaddr_in6 *lsin6; 35286138Sgreen struct sockaddr_un *sun; 35385292Sdes struct sockaddr *sa; 35486138Sgreen char *p; 35586138Sgreen u_char *q; 35686138Sgreen int i; 35785292Sdes 358121606Smarcel if (args[sc->offset] == 0) { 359121606Smarcel asprintf(&tmp, "NULL"); 360121606Smarcel break; 361121606Smarcel } 362121606Smarcel 36386138Sgreen /* yuck: get ss_len */ 36486138Sgreen if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, 36586138Sgreen sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) 36686138Sgreen err(1, "get_struct %p", (void *)args[sc->offset]); 36786138Sgreen /* sockaddr_un never have the length filled in! */ 36886138Sgreen if (ss.ss_family == AF_UNIX) { 36986138Sgreen if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, 37086138Sgreen sizeof(*sun)) 37186138Sgreen == -1) 37286138Sgreen err(2, "get_struct %p", (void *)args[sc->offset]); 37386138Sgreen } else { 37486138Sgreen if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, ss.ss_len) 37586138Sgreen == -1) 37686138Sgreen err(2, "get_struct %p", (void *)args[sc->offset]); 37786138Sgreen } 37885292Sdes 37986138Sgreen switch (ss.ss_family) { 38086138Sgreen case AF_INET: 38187703Smarkm lsin = (struct sockaddr_in *)&ss; 38287703Smarkm inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); 38387703Smarkm asprintf(&tmp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port)); 38486138Sgreen break; 38586138Sgreen case AF_INET6: 38687703Smarkm lsin6 = (struct sockaddr_in6 *)&ss; 38787703Smarkm inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof addr); 38887703Smarkm asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port)); 38986138Sgreen break; 39086138Sgreen case AF_UNIX: 39186138Sgreen sun = (struct sockaddr_un *)&ss; 39286138Sgreen asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); 39386138Sgreen break; 39486138Sgreen default: 39586138Sgreen sa = (struct sockaddr *)&ss; 39686138Sgreen asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data = {%n%*s } }", 39786138Sgreen (int)sa->sa_len, (int)sa->sa_family, &i, 39886138Sgreen 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - (char *)sa)), ""); 39986138Sgreen if (tmp != NULL) { 40086138Sgreen p = tmp + i; 40186138Sgreen for (q = (u_char *)&sa->sa_data; q < (u_char *)sa + sa->sa_len; q++) 40286138Sgreen p += sprintf(p, " %#02x,", *q); 40386138Sgreen } 40485292Sdes } 40585292Sdes } 40685292Sdes break; 40731567Ssef } 40831567Ssef return tmp; 40931567Ssef} 41031567Ssef 411101373Smdodd#define timespecsubt(tvp, uvp, vvp) \ 412101373Smdodd do { \ 413101373Smdodd (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ 414101373Smdodd (vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec; \ 415101373Smdodd if ((vvp)->tv_nsec < 0) { \ 416101373Smdodd (vvp)->tv_sec--; \ 417101373Smdodd (vvp)->tv_nsec += 1000000000; \ 418101373Smdodd } \ 419101373Smdodd } while (0) 420101373Smdodd 42131567Ssef/* 42231567Ssef * print_syscall 42331567Ssef * Print (to outfile) the system call and its arguments. Note that 42431567Ssef * nargs is the number of arguments (not the number of words; this is 42531567Ssef * potentially confusing, I know). 42631567Ssef */ 42731567Ssef 42831567Ssefvoid 429101282Smdoddprint_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) { 43031567Ssef int i; 43158224Ssef int len = 0; 432101373Smdodd struct timespec timediff; 433101283Smdodd 434101283Smdodd if (trussinfo->flags & FOLLOWFORKS) 435101381Smdodd len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); 436101283Smdodd 437106712Sdwmalone if (name != NULL && (!strcmp(name, "execve") || !strcmp(name, "exit"))) { 438101373Smdodd clock_gettime(CLOCK_REALTIME, &trussinfo->after); 439101285Smdodd } 440101285Smdodd 441101285Smdodd if (trussinfo->flags & ABSOLUTETIMESTAMPS) { 442101373Smdodd timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff); 443101423Smdodd len += fprintf(trussinfo->outfile, "%ld.%09ld ", 444101458Smdodd (long)timediff.tv_sec, timediff.tv_nsec); 445101285Smdodd } 446101285Smdodd 447101285Smdodd if (trussinfo->flags & RELATIVETIMESTAMPS) { 448101373Smdodd timespecsubt(&trussinfo->after, &trussinfo->before, &timediff); 449101423Smdodd len += fprintf(trussinfo->outfile, "%ld.%09ld ", 450101458Smdodd (long)timediff.tv_sec, timediff.tv_nsec); 451101285Smdodd } 452101285Smdodd 453101282Smdodd len += fprintf(trussinfo->outfile, "%s(", name); 454101283Smdodd 45531567Ssef for (i = 0; i < nargs; i++) { 45631567Ssef if (s_args[i]) 457101282Smdodd len += fprintf(trussinfo->outfile, "%s", s_args[i]); 45831567Ssef else 459101282Smdodd len += fprintf(trussinfo->outfile, "<missing argument>"); 460101282Smdodd len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? "," : ""); 46131567Ssef } 462101282Smdodd len += fprintf(trussinfo->outfile, ")"); 46358224Ssef for (i = 0; i < 6 - (len / 8); i++) 464101282Smdodd fprintf(trussinfo->outfile, "\t"); 46531567Ssef} 46658224Ssef 46758224Ssefvoid 468122348Smarcelprint_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, 469122348Smarcel char **s_args, int errorp, long retval) 470122348Smarcel{ 471101282Smdodd print_syscall(trussinfo, name, nargs, s_args); 47258224Ssef if (errorp) { 473101282Smdodd fprintf(trussinfo->outfile, " ERR#%d '%s'\n", retval, strerror(retval)); 47458224Ssef } else { 475122348Smarcel fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); 47658224Ssef } 47758224Ssef} 478