diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-10-01 19:02:45 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-10-01 19:02:45 +0000 |
| commit | 65dcb5bcb1993631f47d8acc207904411e135758 (patch) | |
| tree | 65e063ba4063b01c208d44deddda2fe59ac5f224 /usr.bin | |
| parent | ba96f361ba1399631d6d10294aa380c3b408702a (diff) | |
| parent | 66917ca9d2bea3fa9c890412c55f4929bb63118b (diff) | |
Notes
Diffstat (limited to 'usr.bin')
59 files changed, 1460 insertions, 2921 deletions
diff --git a/usr.bin/lex/Makefile.depend b/usr.bin/lex/Makefile.depend index 738376bb43ef..b5b80431a2a4 100644 --- a/usr.bin/lex/Makefile.depend +++ b/usr.bin/lex/Makefile.depend @@ -1,10 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - -DEP_MACHINE := ${.PARSEFILE:E} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/mkcsmapper_static/Makefile.depend b/usr.bin/mkcsmapper_static/Makefile.depend index 911a48d59cd3..ffee33f34c2a 100644 --- a/usr.bin/mkcsmapper_static/Makefile.depend +++ b/usr.bin/mkcsmapper_static/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/arpa \ diff --git a/usr.bin/pamtest/Makefile.depend b/usr.bin/pamtest/Makefile.depend index 80d4de249f9e..916227df0bfd 100644 --- a/usr.bin/pamtest/Makefile.depend +++ b/usr.bin/pamtest/Makefile.depend @@ -1,10 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - -DEP_MACHINE := ${.PARSEFILE:E} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/setchannel/Makefile.depend b/usr.bin/setchannel/Makefile.depend index f52ca95b0a47..79eb58b4a779 100644 --- a/usr.bin/setchannel/Makefile.depend +++ b/usr.bin/setchannel/Makefile.depend @@ -1,10 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - -DEP_MACHINE := ${.PARSEFILE:E} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/smbutil/Makefile.depend b/usr.bin/smbutil/Makefile.depend index a1b4494b8d92..989cc649e995 100644 --- a/usr.bin/smbutil/Makefile.depend +++ b/usr.bin/smbutil/Makefile.depend @@ -1,10 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - -DEP_MACHINE := ${.PARSEFILE:E} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/Makefile b/usr.bin/svn/Makefile index 44421170457e..1d2ae21d56c6 100644 --- a/usr.bin/svn/Makefile +++ b/usr.bin/svn/Makefile @@ -1,5 +1,8 @@ # $FreeBSD$ -SUBDIR = lib svn svnadmin svndumpfilter svnlook svnserve svnsync svnversion svnmucc svnrdump +SUBDIR = lib .WAIT \ + svn svnadmin svndumpfilter svnlook svnserve svnsync svnversion \ + svnmucc svnrdump +SUBDIR_PARALLEL= .include <bsd.subdir.mk> diff --git a/usr.bin/svn/lib/libapr/Makefile.depend b/usr.bin/svn/lib/libapr/Makefile.depend index 402745dff352..bbe68e03366e 100644 --- a/usr.bin/svn/lib/libapr/Makefile.depend +++ b/usr.bin/svn/lib/libapr/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/arpa \ diff --git a/usr.bin/svn/lib/libapr_util/Makefile.depend b/usr.bin/svn/lib/libapr_util/Makefile.depend index 9caf2d1afc04..ba7abb360443 100644 --- a/usr.bin/svn/lib/libapr_util/Makefile.depend +++ b/usr.bin/svn/lib/libapr_util/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libserf/Makefile.depend b/usr.bin/svn/lib/libserf/Makefile.depend index b8e3639fd56b..044c8f776b34 100644 --- a/usr.bin/svn/lib/libserf/Makefile.depend +++ b/usr.bin/svn/lib/libserf/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_client/Makefile.depend b/usr.bin/svn/lib/libsvn_client/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_client/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_client/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_delta/Makefile.depend b/usr.bin/svn/lib/libsvn_delta/Makefile.depend index 35add0cbdea4..b38b34e6ba94 100644 --- a/usr.bin/svn/lib/libsvn_delta/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_delta/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_diff/Makefile.depend b/usr.bin/svn/lib/libsvn_diff/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_diff/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_diff/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_fs/Makefile.depend b/usr.bin/svn/lib/libsvn_fs/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_fs/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_fs/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_fs_fs/Makefile.depend b/usr.bin/svn/lib/libsvn_fs_fs/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_fs_fs/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_fs_fs/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_fs_util/Makefile.depend b/usr.bin/svn/lib/libsvn_fs_util/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_fs_util/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_fs_util/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_ra/Makefile.depend b/usr.bin/svn/lib/libsvn_ra/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_ra/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_ra/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_ra_local/Makefile.depend b/usr.bin/svn/lib/libsvn_ra_local/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_ra_local/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_ra_local/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_ra_serf/Makefile.depend b/usr.bin/svn/lib/libsvn_ra_serf/Makefile.depend index 9caf2d1afc04..ba7abb360443 100644 --- a/usr.bin/svn/lib/libsvn_ra_serf/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_ra_serf/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_ra_svn/Makefile.depend b/usr.bin/svn/lib/libsvn_ra_svn/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_ra_svn/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_ra_svn/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_repos/Makefile.depend b/usr.bin/svn/lib/libsvn_repos/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_repos/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_repos/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_subr/Makefile.depend b/usr.bin/svn/lib/libsvn_subr/Makefile.depend index 365567e26755..10c07481db38 100644 --- a/usr.bin/svn/lib/libsvn_subr/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_subr/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/lib/libsvn_wc/Makefile.depend b/usr.bin/svn/lib/libsvn_wc/Makefile.depend index ccd19e5321da..18be76b0cb6f 100644 --- a/usr.bin/svn/lib/libsvn_wc/Makefile.depend +++ b/usr.bin/svn/lib/libsvn_wc/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ include \ include/xlocale \ diff --git a/usr.bin/svn/svn/Makefile.depend b/usr.bin/svn/svn/Makefile.depend index ccbe2336599b..da1efbd4fbad 100644 --- a/usr.bin/svn/svn/Makefile.depend +++ b/usr.bin/svn/svn/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/svnadmin/Makefile.depend b/usr.bin/svn/svnadmin/Makefile.depend index 6a83703854b6..ae47f0bd1ce4 100644 --- a/usr.bin/svn/svnadmin/Makefile.depend +++ b/usr.bin/svn/svnadmin/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/svndumpfilter/Makefile.depend b/usr.bin/svn/svndumpfilter/Makefile.depend index 6a83703854b6..ae47f0bd1ce4 100644 --- a/usr.bin/svn/svndumpfilter/Makefile.depend +++ b/usr.bin/svn/svndumpfilter/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/svnlook/Makefile.depend b/usr.bin/svn/svnlook/Makefile.depend index 327a76ef6998..d0f58660bc56 100644 --- a/usr.bin/svn/svnlook/Makefile.depend +++ b/usr.bin/svn/svnlook/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/svnmucc/Makefile.depend b/usr.bin/svn/svnmucc/Makefile.depend index eb9e68bb0f20..798e4f3f6cde 100644 --- a/usr.bin/svn/svnmucc/Makefile.depend +++ b/usr.bin/svn/svnmucc/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/svnrdump/Makefile.depend b/usr.bin/svn/svnrdump/Makefile.depend index ccbe2336599b..da1efbd4fbad 100644 --- a/usr.bin/svn/svnrdump/Makefile.depend +++ b/usr.bin/svn/svnrdump/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/svnserve/Makefile.depend b/usr.bin/svn/svnserve/Makefile.depend index 978f241cbae5..550cd652de06 100644 --- a/usr.bin/svn/svnserve/Makefile.depend +++ b/usr.bin/svn/svnserve/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/svnsync/Makefile.depend b/usr.bin/svn/svnsync/Makefile.depend index 978f241cbae5..550cd652de06 100644 --- a/usr.bin/svn/svnsync/Makefile.depend +++ b/usr.bin/svn/svnsync/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/svn/svnversion/Makefile.depend b/usr.bin/svn/svnversion/Makefile.depend index ca6c01c50b7d..12d0cc3305d5 100644 --- a/usr.bin/svn/svnversion/Makefile.depend +++ b/usr.bin/svn/svnversion/Makefile.depend @@ -1,8 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile index bb279d56e8c8..18fd1b1c0bb7 100644 --- a/usr.bin/systat/Makefile +++ b/usr.bin/systat/Makefile @@ -6,7 +6,7 @@ PROG= systat SRCS= cmds.c cmdtab.c devs.c fetch.c iostat.c keyboard.c main.c \ netcmds.c netstat.c pigs.c swap.c icmp.c \ - mode.c ip.c tcp.c \ + mode.c ip.c tcp.c zarc.c \ vmstat.c convtbl.c ifcmds.c ifstat.c .if ${MK_INET6_SUPPORT} != "no" diff --git a/usr.bin/systat/cmdtab.c b/usr.bin/systat/cmdtab.c index c9c9e7d96e48..273dd3214a07 100644 --- a/usr.bin/systat/cmdtab.c +++ b/usr.bin/systat/cmdtab.c @@ -75,6 +75,9 @@ struct cmdtab cmdtab[] = { { "ifstat", showifstat, fetchifstat, labelifstat, initifstat, openifstat, closeifstat, cmdifstat, 0, CF_LOADAV }, + { "zarc", showzarc, fetchzarc, labelzarc, + initzarc, openzarc, closezarc, 0, + resetzarc, CF_ZFSARC }, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0 } }; struct cmdtab *curcmd = &cmdtab[0]; diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h index 17fffc133489..2ac5a51abe7f 100644 --- a/usr.bin/systat/extern.h +++ b/usr.bin/systat/extern.h @@ -163,3 +163,14 @@ void showtcp(void); void status(void); void suspend(int); char *sysctl_dynread(const char *, size_t *); + +#define SYSTAT_CMD(name) \ + void close ## name(WINDOW *); \ + void fetch ## name(void); \ + int init ## name(void); \ + void label ## name(void); \ + WINDOW *open ## name(void); \ + void reset ## name(void); \ + void show ## name(void) + +SYSTAT_CMD( zarc ); diff --git a/usr.bin/systat/main.c b/usr.bin/systat/main.c index fd938307df2e..5e509ca08b66 100644 --- a/usr.bin/systat/main.c +++ b/usr.bin/systat/main.c @@ -178,7 +178,7 @@ main(int argc, char **argv) * devices. We can now use sysctl only. */ use_kvm = 0; - kd = kvm_openfiles("/dev/null", "/dev/null", "/dev/null", + kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, O_RDONLY, errbuf); if (kd == NULL) { error("%s", errbuf); @@ -243,6 +243,11 @@ labels(void) "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); mvaddstr(1, 5, "Load Average"); } + if (curcmd->c_flags & CF_ZFSARC) { + mvaddstr(0, 20, + " Total MFU MRU Anon Hdr L2Hdr Other"); + mvaddstr(1, 5, "ZFS ARC "); + } (*curcmd->c_label)(); #ifdef notdef mvprintw(21, 25, "CPU usage on %s", hostname); @@ -276,8 +281,33 @@ display(void) if (j > 50) wprintw(wload, " %4.1f", avenrun[0]); } + if (curcmd->c_flags & CF_ZFSARC) { + uint64_t arc[7] = {}; + size_t size = sizeof(arc[0]); + if (sysctlbyname("kstat.zfs.misc.arcstats.size", + &arc[0], &size, NULL, 0) == 0 ) { + GETSYSCTL("vfs.zfs.mfu_size", arc[1]); + GETSYSCTL("vfs.zfs.mru_size", arc[2]); + GETSYSCTL("vfs.zfs.anon_size", arc[3]); + GETSYSCTL("kstat.zfs.misc.arcstats.hdr_size", arc[4]); + GETSYSCTL("kstat.zfs.misc.arcstats.l2_hdr_size", arc[5]); + GETSYSCTL("kstat.zfs.misc.arcstats.other_size", arc[6]); + wmove(wload, 0, 0); wclrtoeol(wload); + for (i = 0 ; i < sizeof(arc) / sizeof(arc[0]) ; i++) { + if (arc[i] > 10llu * 1024 * 1024 * 1024 ) { + wprintw(wload, "%7lluG", arc[i] >> 30); + } + else if (arc[i] > 10 * 1024 * 1024 ) { + wprintw(wload, "%7lluM", arc[i] >> 20); + } + else { + wprintw(wload, "%7lluK", arc[i] >> 10); + } + } + } + } (*curcmd->c_refresh)(); - if (curcmd->c_flags & CF_LOADAV) + if (curcmd->c_flags & (CF_LOADAV |CF_ZFSARC)) wrefresh(wload); wrefresh(wnd); move(CMDLINE, col); diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1 index 6b7bcb9bc978..af996bb8dc24 100644 --- a/usr.bin/systat/systat.1 +++ b/usr.bin/systat/systat.1 @@ -98,8 +98,9 @@ to be one of: .Ic pigs , .Ic swap , .Ic tcp , +.Ic vmstat , or -.Ic vmstat . +.Ic zarc , These displays can also be requested interactively (without the .Dq Fl ) and are described in @@ -441,6 +442,8 @@ Display statistics averaged over the refresh interval (the default). .It Cm zero Reset running statistics to zero. .El +.It Ic zarc +display arc cache usage and hit/miss statistics. .It Ic netstat Display, in the lower window, network connections. By default, diff --git a/usr.bin/systat/systat.h b/usr.bin/systat/systat.h index 1b4322c1b307..ebd409e217ae 100644 --- a/usr.bin/systat/systat.h +++ b/usr.bin/systat/systat.h @@ -54,6 +54,7 @@ extern int use_kvm; #define CF_INIT 0x1 /* been initialized */ #define CF_LOADAV 0x2 /* display w/ load average */ +#define CF_ZFSARC 0x4 /* display w/ ZFS cache usage */ #define TCP 0x1 #define UDP 0x2 diff --git a/usr.bin/systat/zarc.c b/usr.bin/systat/zarc.c new file mode 100644 index 000000000000..2a6606f9d8fb --- /dev/null +++ b/usr.bin/systat/zarc.c @@ -0,0 +1,221 @@ +/*- + * Copyright (c) 2014 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/sysctl.h> + +#include <string.h> + +#include "systat.h" +#include "extern.h" + +struct zfield{ + uint64_t arcstats; + uint64_t arcstats_demand_data; + uint64_t arcstats_demand_metadata; + uint64_t arcstats_prefetch_data; + uint64_t arcstats_prefetch_metadata; + uint64_t zfetchstats; + uint64_t arcstats_l2; + uint64_t vdev_cache_stats; +}; + +static struct zarcstats { + struct zfield hits; + struct zfield misses; +} curstat, initstat, oldstat; + +static void +getinfo(struct zarcstats *ls); + +WINDOW * +openzarc(void) +{ + return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); +} + +void +closezarc(WINDOW *w) +{ + if (w == NULL) + return; + wclear(w); + wrefresh(w); + delwin(w); +} + +void +labelzarc(void) +{ + wmove(wnd, 0, 0); wclrtoeol(wnd); + mvwprintw(wnd, 0, 31+1, "%4.4s %7.7s %7.7s %12.12s %12.12s", + "rate", "hits", "misses", "total hits", "total misses"); +#define L(row, str) mvwprintw(wnd, row, 5, str); \ + mvwprintw(wnd, row, 31, ":"); \ + mvwprintw(wnd, row, 31+4, "%%") + L(1, "arcstats"); + L(2, "arcstats.demand_data"); + L(3, "arcstats.demand_metadata"); + L(4, "arcstats.prefetch_data"); + L(5, "arcstats.prefetch_metadata"); + L(6, "zfetchstats"); + L(7, "arcstats.l2"); + L(8, "vdev_cache_stats"); +#undef L +} + +static int calc(uint64_t hits, uint64_t misses) +{ + if( hits ) + return 100 * hits / ( hits + misses ); + else + return 0; +} + +static void +domode(struct zarcstats *delta, struct zarcstats *rate) +{ +#define DO(stat) \ + delta->hits.stat = (curstat.hits.stat - oldstat.hits.stat); \ + delta->misses.stat = (curstat.misses.stat - oldstat.misses.stat); \ + rate->hits.stat = calc(delta->hits.stat, delta->misses.stat) + DO(arcstats); + DO(arcstats_demand_data); + DO(arcstats_demand_metadata); + DO(arcstats_prefetch_data); + DO(arcstats_prefetch_metadata); + DO(zfetchstats); + DO(arcstats_l2); + DO(vdev_cache_stats); + DO(arcstats); + DO(arcstats_demand_data); + DO(arcstats_demand_metadata); + DO(arcstats_prefetch_data); + DO(arcstats_prefetch_metadata); + DO(zfetchstats); + DO(arcstats_l2); + DO(vdev_cache_stats); +#undef DO +} + +void +showzarc(void) +{ + struct zarcstats delta, rate; + + memset(&delta, 0, sizeof delta); + memset(&rate, 0, sizeof rate); + + domode(&delta, &rate); + +#define DO(stat, row, col, fmt) \ + mvwprintw(wnd, row, col, fmt, stat) +#define R(row, stat) DO(rate.hits.stat, row, 31+1, "%3lu") +#define H(row, stat) DO(delta.hits.stat, row, 31+1+5, "%7lu"); \ + DO(curstat.hits.stat, row, 31+1+5+8+8, "%12lu") +#define M(row, stat) DO(delta.misses.stat, row, 31+1+5+8, "%7lu"); \ + DO(curstat.misses.stat, row, 31+1+5+8+8+13, "%12lu") +#define E(row, stat) R(row, stat); H(row, stat); M(row, stat); + E(1, arcstats); + E(2, arcstats_demand_data); + E(3, arcstats_demand_metadata); + E(4, arcstats_prefetch_data); + E(5, arcstats_prefetch_metadata); + E(6, zfetchstats); + E(7, arcstats_l2); + E(8, vdev_cache_stats); +#undef DO +#undef E +#undef M +#undef H +#undef R +} + +int +initzarc(void) +{ + getinfo(&initstat); + curstat = oldstat = initstat; + return 1; +} + +void +resetzarc(void) +{ + initzarc(); +} + +static void +getinfo(struct zarcstats *ls) +{ + size_t size = sizeof( ls->hits.arcstats ); + if ( sysctlbyname("kstat.zfs.misc.arcstats.hits", + &ls->hits.arcstats, &size, NULL, 0 ) != 0 ) + return; + GETSYSCTL("kstat.zfs.misc.arcstats.misses", + ls->misses.arcstats); + GETSYSCTL("kstat.zfs.misc.arcstats.demand_data_hits", + ls->hits.arcstats_demand_data); + GETSYSCTL("kstat.zfs.misc.arcstats.demand_data_misses", + ls->misses.arcstats_demand_data); + GETSYSCTL("kstat.zfs.misc.arcstats.demand_metadata_hits", + ls->hits.arcstats_demand_metadata); + GETSYSCTL("kstat.zfs.misc.arcstats.demand_metadata_misses", + ls->misses.arcstats_demand_metadata); + GETSYSCTL("kstat.zfs.misc.arcstats.prefetch_data_hits", + ls->hits.arcstats_prefetch_data); + GETSYSCTL("kstat.zfs.misc.arcstats.prefetch_data_misses", + ls->misses.arcstats_prefetch_data); + GETSYSCTL("kstat.zfs.misc.arcstats.prefetch_metadata_hits", + ls->hits.arcstats_prefetch_metadata); + GETSYSCTL("kstat.zfs.misc.arcstats.prefetch_metadata_misses", + ls->misses.arcstats_prefetch_metadata); + GETSYSCTL("kstat.zfs.misc.zfetchstats.hits", + ls->hits.zfetchstats); + GETSYSCTL("kstat.zfs.misc.zfetchstats.misses", + ls->misses.zfetchstats); + GETSYSCTL("kstat.zfs.misc.arcstats.l2_hits", + ls->hits.arcstats_l2); + GETSYSCTL("kstat.zfs.misc.arcstats.l2_misses", + ls->misses.arcstats_l2); + GETSYSCTL("kstat.zfs.misc.vdev_cache_stats.hits", + ls->hits.vdev_cache_stats); + GETSYSCTL("kstat.zfs.misc.vdev_cache_stats.misses", + ls->misses.vdev_cache_stats); +} + +void +fetchzarc(void) +{ + oldstat = curstat; + getinfo(&curstat); +} diff --git a/usr.bin/truss/amd64-fbsd.c b/usr.bin/truss/amd64-fbsd.c index eeea8db96205..ade9322c31e9 100644 --- a/usr.bin/truss/amd64-fbsd.c +++ b/usr.bin/truss/amd64-fbsd.c @@ -29,290 +29,103 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * FreeBSD/amd64-specific system call handling. This is probably the most - * complex part of the entire truss program, although I've got lots of - * it handled relatively cleanly now. The system call names are generated - * automatically, thanks to /usr/src/sys/kern/syscalls.master. The - * names used for the various structures are confusing, I sadly admit. - */ +/* FreeBSD/amd64-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <sys/syscall.h> #include <machine/reg.h> #include <machine/psl.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "syscalls.h" -static int nsyscalls = nitems(syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct freebsd_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long *args; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct freebsd_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct freebsd_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct freebsd_syscall *fsc) -{ - int i; - - free(fsc->args); - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in amd64/amd64/trap.c - * is ever changed these functions need to keep up. - */ - -void -amd64_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +amd64_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct ptrace_io_desc iorequest; struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; + struct current_syscall *cs; lwpid_t tid; - int i, reg, syscall_num; + u_int i, reg; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; + return (-1); } /* - * FreeBSD has two special kinds of system call redirctions -- + * FreeBSD has two special kinds of system call redirections -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over %rax if it contains + * either of these values. */ reg = 0; - syscall_num = regs.r_rax; - switch (syscall_num) { + switch (regs.r_rax) { case SYS_syscall: case SYS___syscall: - syscall_num = regs.r_rdi; reg++; break; } - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); - } - - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "fork") == 0 || - strcmp(fsc->name, "pdfork") == 0 || - strcmp(fsc->name, "rfork") == 0 || - strcmp(fsc->name, "vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - - fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); - for (i = 0; i < nargs && reg < 6; i++, reg++) { + for (i = 0; i < narg && reg < 6; i++, reg++) { switch (reg) { - case 0: fsc->args[i] = regs.r_rdi; break; - case 1: fsc->args[i] = regs.r_rsi; break; - case 2: fsc->args[i] = regs.r_rdx; break; - case 3: fsc->args[i] = regs.r_rcx; break; - case 4: fsc->args[i] = regs.r_r8; break; - case 5: fsc->args[i] = regs.r_r9; break; + case 0: cs->args[i] = regs.r_rdi; break; + case 1: cs->args[i] = regs.r_rsi; break; + case 2: cs->args[i] = regs.r_rdx; break; + case 3: cs->args[i] = regs.r_rcx; break; + case 4: cs->args[i] = regs.r_r8; break; + case 5: cs->args[i] = regs.r_r9; break; } } - if (nargs > i) { + if (narg > i) { iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)(regs.r_rsp + sizeof(register_t)); - iorequest.piod_addr = &fsc->args[i]; - iorequest.piod_len = (nargs - i) * sizeof(register_t); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(register_t); ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) - return; - } - - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; + return (-1); } - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%lx%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif - } - -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + return (0); } -/* - * And when the system call is done, we handle it here. - * Currently, no attempt is made to ensure that the system calls - * match -- this needs to be fixed (and is, in fact, why S_SCX includes - * the system call number instead of, say, an error status). - */ - -long -amd64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +amd64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.r_rax; - errorp = !!(regs.r_rflags & PSL_C); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ - - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; - } - } - } - - if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; - - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ + retval[0] = regs.r_rax; + retval[1] = regs.r_rdx; + *errorp = !!(regs.r_rflags & PSL_C); + return (0); +} - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - retval, fsc->sc); - free_fsc(fsc); +static struct procabi amd64_fbsd = { + "FreeBSD ELF64", + syscallnames, + nitems(syscallnames), + amd64_fetch_args, + amd64_fetch_retval +}; - return (retval); -} +PROCABI(amd64_fbsd); diff --git a/usr.bin/truss/amd64-fbsd32.c b/usr.bin/truss/amd64-fbsd32.c index 40aa152f81cc..84a4b6ba8a7c 100644 --- a/usr.bin/truss/amd64-fbsd32.c +++ b/usr.bin/truss/amd64-fbsd32.c @@ -29,290 +29,109 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * FreeBSD/i386-specific system call handling. This is probably the most - * complex part of the entire truss program, although I've got lots of - * it handled relatively cleanly now. The system call names are generated - * automatically, thanks to /usr/src/sys/kern/syscalls.master. The - * names used for the various structures are confusing, I sadly admit. - */ +/* FreeBSD/i386-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <sys/syscall.h> #include <machine/reg.h> #include <machine/psl.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "freebsd32_syscalls.h" -static int nsyscalls = nitems(freebsd32_syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct freebsd32_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long *args; - unsigned int *args32; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct freebsd32_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct freebsd32_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct freebsd32_syscall *fsc) -{ - int i; - - free(fsc->args); - free(fsc->args32); - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c - * is ever changed these functions need to keep up. - */ - -void -amd64_fbsd32_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +amd64_fbsd32_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct ptrace_io_desc iorequest; struct reg regs; - struct freebsd32_syscall *fsc; - struct syscall *sc; - lwpid_t tid; + struct current_syscall *cs; + unsigned int args32[narg]; unsigned long parm_offset; - int i, syscall_num; + lwpid_t tid; + u_int i; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; + return (-1); } parm_offset = regs.r_rsp + sizeof(int); /* - * FreeBSD has two special kinds of system call redirctions -- + * FreeBSD has two special kinds of system call redirections -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. */ - syscall_num = regs.r_rax; - switch (syscall_num) { + switch (regs.r_rax) { case SYS_syscall: - syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); parm_offset += sizeof(int); break; case SYS___syscall: - syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); parm_offset += sizeof(quad_t); break; } - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : freebsd32_syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); - } - - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "fork") == 0 || - strcmp(fsc->name, "pdfork") == 0 || - strcmp(fsc->name, "rfork") == 0 || - strcmp(fsc->name, "vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - - fsc->args32 = malloc((1 + nargs) * sizeof(unsigned int)); iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)parm_offset; - iorequest.piod_addr = fsc->args32; - iorequest.piod_len = (1 + nargs) * sizeof(unsigned int); + iorequest.piod_addr = args32; + iorequest.piod_len = sizeof(args32); ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return; - - fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); - for (i = 0; i < nargs + 1; i++) - fsc->args[i] = fsc->args32[i]; - - sc = NULL; - if (fsc->name) - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; - } - - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif + if (iorequest.piod_len == 0) { + return (-1); } -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + for (i = 0; i < narg; i++) + cs->args[i] = args32[i]; + return (0); } -/* - * And when the system call is done, we handle it here. - * Currently, no attempt is made to ensure that the system calls - * match -- this needs to be fixed (and is, in fact, why S_SCX includes - * the system call number instead of, say, an error status). - */ - -long -amd64_fbsd32_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +amd64_fbsd32_fetch_retval(struct trussinfo *trussinfo, long *retval, + int *errorp) { struct reg regs; - struct freebsd32_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.r_rax; - errorp = !!(regs.r_rflags & PSL_C); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ - - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; - } - } - } + retval[0] = regs.r_rax & 0xffffffff; + retval[1] = regs.r_rdx & 0xffffffff; + *errorp = !!(regs.r_rflags & PSL_C); + return (0); +} - if (fsc->name != NULL && (strcmp(fsc->name, "freebsd32_execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; +static struct procabi amd64_fbsd32 = { + "FreeBSD ELF32", + freebsd32_syscallnames, + nitems(freebsd32_syscallnames), + amd64_fbsd32_fetch_args, + amd64_fbsd32_fetch_retval +}; - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ +PROCABI(amd64_fbsd32); - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - retval, fsc->sc); - free_fsc(fsc); +static struct procabi amd64_fbsd32_aout = { + "FreeBSD a.out", + freebsd32_syscallnames, + nitems(freebsd32_syscallnames), + amd64_fbsd32_fetch_args, + amd64_fbsd32_fetch_retval +}; - return (retval); -} +PROCABI(amd64_fbsd32_aout); diff --git a/usr.bin/truss/amd64-linux32.c b/usr.bin/truss/amd64-linux32.c index b2d0d040406f..4f64af343fbb 100644 --- a/usr.bin/truss/amd64-linux32.c +++ b/usr.bin/truss/amd64-linux32.c @@ -29,123 +29,36 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * Linux/i386-specific system call handling. Given how much of this code - * is taken from the freebsd equivalent, I can probably put even more of - * it in support routines that can be used by any personality support. - */ +/* Linux/i386-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <machine/reg.h> #include <machine/psl.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "linux32_syscalls.h" -static int nsyscalls = nitems(linux32_syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct linux_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long args[5]; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct linux_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct linux_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct linux_syscall *fsc) -{ - int i; - - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c - * is ever changed these functions need to keep up. - */ - -void -amd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +amd64_linux32_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct reg regs; - struct linux_syscall *fsc; - struct syscall *sc; + struct current_syscall *cs; lwpid_t tid; - int i, syscall_num; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; - } - - syscall_num = regs.r_rax; - - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : linux32_syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); + return (-1); } - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "linux_fork") == 0 || - strcmp(fsc->name, "linux_vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - /* * Linux passes syscall arguments in registers, not * on the stack. Fortunately, we've got access to the @@ -153,60 +66,22 @@ amd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs) * number of arguments. And what does linux do for syscalls * that have more than five arguments? */ - - fsc->args[0] = regs.r_rbx; - fsc->args[1] = regs.r_rcx; - fsc->args[2] = regs.r_rdx; - fsc->args[3] = regs.r_rsi; - fsc->args[4] = regs.r_rdi; - - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; + switch (narg) { + default: + cs->args[5] = regs.r_rbp; /* Unconfirmed */ + case 5: + cs->args[4] = regs.r_rdi; + case 4: + cs->args[3] = regs.r_rsi; + case 3: + cs->args[2] = regs.r_rdx; + case 2: + cs->args[1] = regs.r_rcx; + case 1: + cs->args[0] = regs.r_rbx; } - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif - } - -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + return (0); } /* @@ -224,83 +99,43 @@ static const int bsd_to_linux_errno[] = { -6, }; -long -amd64_linux32_syscall_exit(struct trussinfo *trussinfo, - int syscall_num __unused) +static int +amd64_linux32_fetch_retval(struct trussinfo *trussinfo, long *retval, + int *errorp) { struct reg regs; - struct linux_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); + size_t i; tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.r_rax; - errorp = !!(regs.r_rflags & PSL_C); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ + retval[0] = regs.r_rax & 0xffffffff; + retval[1] = regs.r_rdx & 0xffffffff; + *errorp = !!(regs.r_rflags & PSL_C); - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; + if (*errorp) { + for (i = 0; i < nitems(bsd_to_linux_errno); i++) { + if (retval[0] == bsd_to_linux_errno[i]) { + retval[0] = i; + return (0); } } - } - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ - if (errorp) { - for (i = 0; (size_t)i < nitems(bsd_to_linux_errno); i++) { - if (retval == bsd_to_linux_errno[i]) - break; - } + /* XXX: How to handle unknown errors? */ } + return (0); +} - if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; - - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - errorp ? i : retval, fsc->sc); - free_fsc(fsc); +static struct procabi amd64_linux32 = { + "Linux ELF32", + linux32_syscallnames, + nitems(linux32_syscallnames), + amd64_linux32_fetch_args, + amd64_linux32_fetch_retval +}; - return (retval); -} +PROCABI(amd64_linux32); diff --git a/usr.bin/truss/arm-fbsd.c b/usr.bin/truss/arm-fbsd.c index 8dc4d5bef414..4b8222a53433 100644 --- a/usr.bin/truss/arm-fbsd.c +++ b/usr.bin/truss/arm-fbsd.c @@ -29,17 +29,11 @@ * SUCH DAMAGE. */ -/* - * FreeBSD/arm-specific system call handling. This is probably the most - * complex part of the entire truss program, although I've got lots of - * it handled relatively cleanly now. The system call names are generated - * automatically, thanks to /usr/src/sys/kern/syscalls.master. The - * names used for the various structures are confusing, I sadly admit. - */ - #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/types.h> + +/* FreeBSD/arm-specific system call handling. */ + #include <sys/ptrace.h> #include <sys/syscall.h> @@ -47,303 +41,98 @@ __FBSDID("$FreeBSD$"); #include <machine/armreg.h> #include <machine/ucontext.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <err.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "syscalls.h" - -static int nsyscalls = nitems(syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct freebsd_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long *args; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct freebsd_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct freebsd_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct freebsd_syscall *fsc) -{ - int i; - - free(fsc->args); - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c - * is ever changed these functions need to keep up. - */ - -void -arm_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +arm_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct ptrace_io_desc iorequest; struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; + struct current_syscall *cs; lwpid_t tid; - int i, syscall_num; - register_t *ap; + u_int i, reg, syscall_num; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; + return (-1); } - ap = ®s.r[0]; /* - * FreeBSD has two special kinds of system call redirctions -- + * FreeBSD has two special kinds of system call redirections -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. */ #ifdef __ARM_EABI__ syscall_num = regs.r[7]; #else - if ((syscall_num = ptrace(PT_READ_I, tid, + if ((syscall_num = ptrace(PT_READ_I, tid, (caddr_t)(regs.r[_REG_PC] - INSN_SIZE), 0)) == -1) { fprintf(trussinfo->outfile, "-- CANNOT READ PC --\n"); - return; + return (-1); } syscall_num = syscall_num & 0x000fffff; #endif + + reg = 0; switch (syscall_num) { case SYS_syscall: - syscall_num = *ap++; - nargs--; + reg = 1; break; case SYS___syscall: - syscall_num = ap[_QUAD_LOWWORD]; - ap += 2; - nargs -= 2; + reg = 2; break; } - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); - } - - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "fork") == 0 || - strcmp(fsc->name, "pdfork") == 0 || - strcmp(fsc->name, "rfork") == 0 || - strcmp(fsc->name, "vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - - fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); - switch (nargs) { - default: - /* - * The OS doesn't seem to allow more than 10 words of - * parameters (yay!). So we shouldn't be here. - */ - warn("More than 10 words (%d) of arguments!\n", nargs); - break; - case 10: - case 9: - case 8: - case 7: - case 6: - case 5: - /* - * If there are 7-10 words of arguments, they are placed - * on the stack, as is normal for other processors. - * The fall-through for all of these is deliberate!!! - */ - // XXX BAD constant used here + for (i = 0; i < narg && reg < 4; i++, reg++) + cs->args[i] = regs.r[reg]; + if (narg > i) { iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)(regs.r_sp + 4 * sizeof(uint32_t)); - iorequest.piod_addr = &fsc->args[4]; - iorequest.piod_len = (nargs - 4) * sizeof(fsc->args[0]); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) - return; - case 4: fsc->args[3] = ap[3]; - case 3: fsc->args[2] = ap[2]; - case 2: fsc->args[1] = ap[1]; - case 1: fsc->args[0] = ap[0]; - case 0: break; + return (-1); } - sc = NULL; - if (fsc->name) - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; - } - - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif - } - -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + return (0); } -/* - * And when the system call is done, we handle it here. - * Currently, no attempt is made to ensure that the system calls - * match -- this needs to be fixed (and is, in fact, why S_SCX includes - * the system call number instead of, say, an error status). - */ - -long -arm_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +arm_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.r[0]; - errorp = !!(regs.r_cpsr & PSR_C); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ - - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; - } - } - } - - if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; - - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ + /* XXX: Does not have the __ARMEB__ handling for __syscall(). */ + retval[0] = regs.r[0]; + retval[1] = regs.r[1]; + *errorp = !!(regs.r_cpsr & PSR_C); + return (0); +} - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - retval, fsc->sc); - free_fsc(fsc); +static struct procabi arm_fbsd = { + "FreeBSD ELF32", + syscallnames, + nitems(syscallnames), + arm_fetch_args, + arm_fetch_retval +}; - return (retval); -} +PROCABI(arm_fbsd); diff --git a/usr.bin/truss/extern.h b/usr.bin/truss/extern.h index 820f4f0b8e16..708d055cf2c3 100644 --- a/usr.bin/truss/extern.h +++ b/usr.bin/truss/extern.h @@ -31,42 +31,9 @@ * $FreeBSD$ */ -extern int setup_and_wait(char **); -extern int start_tracing(pid_t); +extern void setup_and_wait(struct trussinfo *, char **); +extern void start_tracing(struct trussinfo *, pid_t); extern void restore_proc(int); -extern void waitevent(struct trussinfo *); +extern void eventloop(struct trussinfo *); extern const char *ioctlname(unsigned long val); extern char *strsig(int sig); -#ifdef __arm__ -extern void arm_syscall_entry(struct trussinfo *, int); -extern long arm_syscall_exit(struct trussinfo *, int); -#endif -#ifdef __amd64__ -extern void amd64_syscall_entry(struct trussinfo *, int); -extern long amd64_syscall_exit(struct trussinfo *, int); -extern void amd64_linux32_syscall_entry(struct trussinfo *, int); -extern long amd64_linux32_syscall_exit(struct trussinfo *, int); -extern void amd64_fbsd32_syscall_entry(struct trussinfo *, int); -extern long amd64_fbsd32_syscall_exit(struct trussinfo *, int); -#endif -#ifdef __i386__ -extern void i386_syscall_entry(struct trussinfo *, int); -extern long i386_syscall_exit(struct trussinfo *, int); -extern void i386_linux_syscall_entry(struct trussinfo *, int); -extern long i386_linux_syscall_exit(struct trussinfo *, int); -#endif -#ifdef __powerpc__ -extern void powerpc_syscall_entry(struct trussinfo *, int); -extern long powerpc_syscall_exit(struct trussinfo *, int); -extern void powerpc64_syscall_entry(struct trussinfo *, int); -extern long powerpc64_syscall_exit(struct trussinfo *, int); -#endif -#ifdef __sparc64__ -extern void sparc64_syscall_entry(struct trussinfo *, int); -extern long sparc64_syscall_exit(struct trussinfo *, int); -#endif -#ifdef __mips__ -extern void mips_syscall_entry(struct trussinfo *, int); -extern long mips_syscall_exit(struct trussinfo *, int); -#endif - diff --git a/usr.bin/truss/i386-fbsd.c b/usr.bin/truss/i386-fbsd.c index ef326f02020f..029815ec711d 100644 --- a/usr.bin/truss/i386-fbsd.c +++ b/usr.bin/truss/i386-fbsd.c @@ -29,284 +29,103 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * FreeBSD/i386-specific system call handling. This is probably the most - * complex part of the entire truss program, although I've got lots of - * it handled relatively cleanly now. The system call names are generated - * automatically, thanks to /usr/src/sys/kern/syscalls.master. The - * names used for the various structures are confusing, I sadly admit. - */ +/* FreeBSD/i386-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <sys/syscall.h> #include <machine/reg.h> #include <machine/psl.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "syscalls.h" -static int nsyscalls = nitems(syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct freebsd_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long *args; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct freebsd_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct freebsd_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct freebsd_syscall *fsc) -{ - int i; - - free(fsc->args); - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c - * is ever changed these functions need to keep up. - */ - -void -i386_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +i386_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct ptrace_io_desc iorequest; struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; + struct current_syscall *cs; lwpid_t tid; unsigned int parm_offset; - int i, syscall_num; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; + return (-1); } parm_offset = regs.r_esp + sizeof(int); /* - * FreeBSD has two special kinds of system call redirctions -- + * FreeBSD has two special kinds of system call redirections -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. */ - syscall_num = regs.r_eax; - switch (syscall_num) { + switch (regs.r_eax) { case SYS_syscall: - syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); parm_offset += sizeof(int); break; case SYS___syscall: - syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); parm_offset += sizeof(quad_t); break; } - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); - } - - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "fork") == 0 || - strcmp(fsc->name, "pdfork") == 0 || - strcmp(fsc->name, "rfork") == 0 || - strcmp(fsc->name, "vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - - fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)parm_offset; - iorequest.piod_addr = fsc->args; - iorequest.piod_len = (1 + nargs) * sizeof(unsigned long); + iorequest.piod_addr = cs->args; + iorequest.piod_len = narg * sizeof(unsigned long); ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) - return; - - sc = NULL; - if (fsc->name) - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; - } - - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif - } - -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif + return (-1); - trussinfo->curthread->fsc = fsc; + return (0); } -/* - * And when the system call is done, we handle it here. - * Currently, no attempt is made to ensure that the system calls - * match -- this needs to be fixed (and is, in fact, why S_SCX includes - * the system call number instead of, say, an error status). - */ - -long -i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +i386_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.r_eax; - errorp = !!(regs.r_eflags & PSL_C); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ - - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; + retval[0] = regs.r_eax; + retval[1] = regs.r_edx; + *errorp = !!(regs.r_eflags & PSL_C); + return (0); +} - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; - } - } - } +static struct procabi i386_fbsd = { + "FreeBSD ELF32", + syscallnames, + nitems(syscallnames), + i386_fetch_args, + i386_fetch_retval +}; - if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; +PROCABI(i386_fbsd); - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ +static struct procabi i386_fbsd_aout = { + "FreeBSD a.out", + syscallnames, + nitems(syscallnames), + i386_fetch_args, + i386_fetch_retval +}; - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - retval, fsc->sc); - free_fsc(fsc); +PROCABI(i386_fbsd_aout); - return (retval); -} diff --git a/usr.bin/truss/i386-linux.c b/usr.bin/truss/i386-linux.c index 6bd930955177..fa57af2b3484 100644 --- a/usr.bin/truss/i386-linux.c +++ b/usr.bin/truss/i386-linux.c @@ -29,123 +29,36 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * Linux/i386-specific system call handling. Given how much of this code - * is taken from the freebsd equivalent, I can probably put even more of - * it in support routines that can be used by any personality support. - */ +/* Linux/i386-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <machine/reg.h> #include <machine/psl.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "linux_syscalls.h" -static int nsyscalls = nitems(linux_syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct linux_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long args[5]; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct linux_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct linux_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct linux_syscall *fsc) -{ - int i; - - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c - * is ever changed these functions need to keep up. - */ - -void -i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +i386_linux_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct reg regs; - struct linux_syscall *fsc; - struct syscall *sc; + struct current_syscall *cs; lwpid_t tid; - int i, syscall_num; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; - } - - syscall_num = regs.r_eax; - - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : linux_syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); + return (-1); } - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "linux_fork") == 0 || - strcmp(fsc->name, "linux_vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - /* * Linux passes syscall arguments in registers, not * on the stack. Fortunately, we've got access to the @@ -153,60 +66,22 @@ i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) * number of arguments. And what does linux do for syscalls * that have more than five arguments? */ - - fsc->args[0] = regs.r_ebx; - fsc->args[1] = regs.r_ecx; - fsc->args[2] = regs.r_edx; - fsc->args[3] = regs.r_esi; - fsc->args[4] = regs.r_edi; - - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; + switch (narg) { + default: + cs->args[5] = regs.r_ebp; /* Unconfirmed */ + case 5: + cs->args[4] = regs.r_edi; + case 4: + cs->args[3] = regs.r_esi; + case 3: + cs->args[2] = regs.r_edx; + case 2: + cs->args[1] = regs.r_ecx; + case 1: + cs->args[0] = regs.r_ebx; } - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif - } - -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + return (0); } /* @@ -224,82 +99,42 @@ static const int bsd_to_linux_errno[] = { -6, }; -long -i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +i386_linux_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; - struct linux_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); + size_t i; tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.r_eax; - errorp = !!(regs.r_eflags & PSL_C); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ + retval[0] = regs.r_eax; + retval[1] = regs.r_edx; + *errorp = !!(regs.r_eflags & PSL_C); - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; + if (*errorp) { + for (i = 0; i < nitems(bsd_to_linux_errno); i++) { + if (retval[0] == bsd_to_linux_errno[i]) { + retval[0] = i; + return (0); } } - } - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ - if (errorp) { - for (i = 0; (size_t)i < nitems(bsd_to_linux_errno); i++) { - if (retval == bsd_to_linux_errno[i]) - break; - } + /* XXX: How to handle unknown errors? */ } + return (0); +} - if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; - - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - errorp ? i : retval, fsc->sc); - free_fsc(fsc); +static struct procabi i386_linux = { + "Linux ELF32", + linux_syscallnames, + nitems(linux_syscallnames), + i386_linux_fetch_args, + i386_linux_fetch_retval +}; - return (retval); -} +PROCABI(i386_linux); diff --git a/usr.bin/truss/main.c b/usr.bin/truss/main.c index 84ae3139cc1b..55fdedad42cf 100644 --- a/usr.bin/truss/main.c +++ b/usr.bin/truss/main.c @@ -38,21 +38,12 @@ __FBSDID("$FreeBSD$"); * do a lot of the work :). */ -#include <sys/param.h> -#include <sys/types.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/sysctl.h> -#include <sys/wait.h> +#include <sys/ptrace.h> #include <err.h> -#include <errno.h> -#include <fcntl.h> #include <signal.h> -#include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <time.h> #include <unistd.h> @@ -60,8 +51,6 @@ __FBSDID("$FreeBSD$"); #include "extern.h" #include "syscall.h" -#define MAXARGS 6 - static void usage(void) { @@ -71,82 +60,6 @@ usage(void) exit(1); } -/* - * WARNING! "FreeBSD a.out" must be first, or set_etype will not - * work correctly. - */ -static struct ex_types { - const char *type; - void (*enter_syscall)(struct trussinfo *, int); - long (*exit_syscall)(struct trussinfo *, int); -} ex_types[] = { -#ifdef __arm__ - { "FreeBSD ELF32", arm_syscall_entry, arm_syscall_exit }, -#endif -#ifdef __amd64__ - { "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit }, - { "FreeBSD ELF32", amd64_fbsd32_syscall_entry, amd64_fbsd32_syscall_exit }, - { "Linux ELF32", amd64_linux32_syscall_entry, amd64_linux32_syscall_exit }, -#endif -#ifdef __i386__ - { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit }, - { "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit }, - { "FreeBSD ELF32", i386_syscall_entry, i386_syscall_exit }, - { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit }, -#endif -#ifdef __powerpc__ - { "FreeBSD ELF", powerpc_syscall_entry, powerpc_syscall_exit }, - { "FreeBSD ELF32", powerpc_syscall_entry, powerpc_syscall_exit }, -#ifdef __powerpc64__ - { "FreeBSD ELF64", powerpc64_syscall_entry, powerpc64_syscall_exit }, -#endif -#endif -#ifdef __sparc64__ - { "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit }, -#endif -#ifdef __mips__ - { "FreeBSD ELF", mips_syscall_entry, mips_syscall_exit }, - { "FreeBSD ELF32", mips_syscall_entry, mips_syscall_exit }, - { "FreeBSD ELF64", mips_syscall_entry, mips_syscall_exit }, // XXX -#endif - { 0, 0, 0 }, -}; - -/* - * Set the execution type. This is called after every exec, and when - * a process is first monitored. - */ - -static struct ex_types * -set_etype(struct trussinfo *trussinfo) -{ - struct ex_types *funcs; - size_t len; - int error; - int mib[4]; - char progt[32]; - - len = sizeof(progt); - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_SV_NAME; - mib[3] = trussinfo->pid; - error = sysctl(mib, 4, progt, &len, NULL, 0); - if (error != 0) - err(2, "can not get etype"); - - for (funcs = ex_types; funcs->type; funcs++) - if (strcmp(funcs->type, progt) == 0) - break; - - if (funcs->type == NULL) { - funcs = &ex_types[0]; - warn("execution type %s is not supported -- using %s", - progt, funcs->type); - } - return (funcs); -} - char * strsig(int sig) { @@ -162,37 +75,32 @@ strsig(int sig) int main(int ac, char **av) { - struct timespec timediff; struct sigaction sa; - struct ex_types *funcs; struct trussinfo *trussinfo; char *fname; - char *signame; char **command; - pid_t childpid; - int c, initial_open, status; + pid_t pid; + int c; fname = NULL; - initial_open = 1; /* Initialize the trussinfo struct */ trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo)); if (trussinfo == NULL) errx(1, "calloc() failed"); + pid = 0; trussinfo->outfile = stderr; trussinfo->strsize = 32; - trussinfo->pr_why = S_NONE; trussinfo->curthread = NULL; - SLIST_INIT(&trussinfo->threadlist); + LIST_INIT(&trussinfo->proclist); while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) { switch (c) { case 'p': /* specified pid */ - trussinfo->pid = atoi(optarg); + pid = atoi(optarg); /* make sure i don't trace me */ - if (trussinfo->pid == getpid()) { - fprintf(stderr, "attempt to grab self.\n"); - exit(2); + if (pid == getpid()) { + errx(2, "attempt to grab self."); } break; case 'f': /* Follow fork()'s */ @@ -228,8 +136,8 @@ main(int ac, char **av) } ac -= optind; av += optind; - if ((trussinfo->pid == 0 && ac == 0) || - (trussinfo->pid != 0 && ac != 0)) + if ((pid == 0 && ac == 0) || + (pid != 0 && ac != 0)) usage(); if (fname != NULL) { /* Use output file */ @@ -247,10 +155,10 @@ main(int ac, char **av) * exit. If, however, we are examining an already-running process, * then we restore the event mask on these same signals. */ - - if (trussinfo->pid == 0) { /* Start a command ourselves */ + if (pid == 0) { + /* Start a command ourselves */ command = av; - trussinfo->pid = setup_and_wait(command); + setup_and_wait(trussinfo, command); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGQUIT, SIG_IGN); @@ -261,119 +169,37 @@ main(int ac, char **av) sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - start_tracing(trussinfo->pid); + start_tracing(trussinfo, pid); } - /* * At this point, if we started the process, it is stopped waiting to * be woken up, either in exit() or in execve(). */ + if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) { + /* + * If we are not able to handle this ABI, detach from the + * process and exit. If we just created a new process to + * run a command, kill the new process rather than letting + * it run untraced. + */ + if (pid == 0) + kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL); + ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL, + 0); + return (1); + } + ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1, + 0); -START_TRACE: - funcs = set_etype(trussinfo); - - initial_open = 0; /* * At this point, it's a simple loop, waiting for the process to * stop, finding out why, printing out why, and then continuing it. * All of the grunt work is done in the support routines. */ - clock_gettime(CLOCK_REALTIME, &trussinfo->start_time); - do { - waitevent(trussinfo); - - switch (trussinfo->pr_why) { - case S_SCE: - funcs->enter_syscall(trussinfo, MAXARGS); - clock_gettime(CLOCK_REALTIME, - &trussinfo->curthread->before); - break; - case S_SCX: - clock_gettime(CLOCK_REALTIME, - &trussinfo->curthread->after); - - if (trussinfo->curthread->in_fork && - (trussinfo->flags & FOLLOWFORKS)) { - trussinfo->curthread->in_fork = 0; - childpid = funcs->exit_syscall(trussinfo, - trussinfo->pr_data); - - /* - * Fork a new copy of ourself to trace - * the child of the original traced - * process. - */ - if (fork() == 0) { - trussinfo->pid = childpid; - start_tracing(trussinfo->pid); - goto START_TRACE; - } - break; - } - funcs->exit_syscall(trussinfo, MAXARGS); - break; - case S_SIG: - if (trussinfo->flags & NOSIGS) - break; - if (trussinfo->flags & FOLLOWFORKS) - fprintf(trussinfo->outfile, "%5d: ", - trussinfo->pid); - if (trussinfo->flags & ABSOLUTETIMESTAMPS) { - timespecsubt(&trussinfo->curthread->after, - &trussinfo->start_time, &timediff); - fprintf(trussinfo->outfile, "%jd.%09ld ", - (intmax_t)timediff.tv_sec, - timediff.tv_nsec); - } - if (trussinfo->flags & RELATIVETIMESTAMPS) { - timespecsubt(&trussinfo->curthread->after, - &trussinfo->curthread->before, &timediff); - fprintf(trussinfo->outfile, "%jd.%09ld ", - (intmax_t)timediff.tv_sec, - timediff.tv_nsec); - } - signame = strsig(trussinfo->pr_data); - fprintf(trussinfo->outfile, - "SIGNAL %u (%s)\n", trussinfo->pr_data, - signame == NULL ? "?" : signame); - break; - case S_EXIT: - if (trussinfo->flags & COUNTONLY) - break; - if (trussinfo->flags & FOLLOWFORKS) - fprintf(trussinfo->outfile, "%5d: ", - trussinfo->pid); - if (trussinfo->flags & ABSOLUTETIMESTAMPS) { - timespecsubt(&trussinfo->curthread->after, - &trussinfo->start_time, &timediff); - fprintf(trussinfo->outfile, "%jd.%09ld ", - (intmax_t)timediff.tv_sec, - timediff.tv_nsec); - } - if (trussinfo->flags & RELATIVETIMESTAMPS) { - timespecsubt(&trussinfo->curthread->after, - &trussinfo->curthread->before, &timediff); - fprintf(trussinfo->outfile, "%jd.%09ld ", - (intmax_t)timediff.tv_sec, - timediff.tv_nsec); - } - fprintf(trussinfo->outfile, - "process exit, rval = %u\n", trussinfo->pr_data); - break; - default: - break; - } - } while (trussinfo->pr_why != S_EXIT && - trussinfo->pr_why != S_DETACHED); - - if (trussinfo->flags & FOLLOWFORKS) { - do { - childpid = wait(&status); - } while (childpid != -1); - } + eventloop(trussinfo); if (trussinfo->flags & COUNTONLY) print_summary(trussinfo); diff --git a/usr.bin/truss/mips-fbsd.c b/usr.bin/truss/mips-fbsd.c index d45241ac3be9..d488b7e7c030 100644 --- a/usr.bin/truss/mips-fbsd.c +++ b/usr.bin/truss/mips-fbsd.c @@ -29,318 +29,113 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * FreeBSD/sparc64-specific system call handling. This is probably the most - * complex part of the entire truss program, although I've got lots of - * it handled relatively cleanly now. The system call names are generated - * automatically, thanks to /usr/src/sys/kern/syscalls.master. The - * names used for the various structures are confusing, I sadly admit. - * - * This file is almost nothing more than a slightly-edited i386-fbsd.c. - */ +/* FreeBSD/mips-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <sys/syscall.h> #include <machine/frame.h> #include <machine/reg.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stddef.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "syscalls.h" -static int nsyscalls = nitems(syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct freebsd_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long *args; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct freebsd_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct freebsd_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct freebsd_syscall *fsc) -{ - int i; - - free(fsc->args); - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in sparc64/sparc64/trap.c - * is ever changed these functions need to keep up. - */ - -void -mips_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +mips_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct ptrace_io_desc iorequest; struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; + struct current_syscall *cs; lwpid_t tid; - int i, syscall_num; - int indir; /* indirect system call */ + u_int i, reg; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; - } - - indir = 0; - syscall_num = regs.r_regs[V0]; - if (syscall_num == SYS_syscall) { - indir = 1; - syscall_num = regs.r_regs[A0]; + return (-1); } - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + reg = A0; + switch (regs.r_regs[V0]) { + case SYS_syscall: + reg = A1; + break; + case SYS___syscall: +#if defined(__mips_n32) || defined(__mips_n64) + reg = A1; +#else + reg = A2; +#endif + break; } - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "fork") == 0 || - strcmp(fsc->name, "pdfork") == 0 || - strcmp(fsc->name, "rfork") == 0 || - strcmp(fsc->name, "vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - - fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); -#if 0 // XXX - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)parm_offset; - iorequest.piod_addr = fsc->args; - iorequest.piod_len = (1 + nargs) * sizeof(unsigned long); - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return; +#if defined(__mips_n32) || defined(__mips_n64) +#define MAXREG A7 #else - iorequest.piod_op = PIOD_READ_D; +#define MAXREG A3 #endif - switch (nargs) { - default: - /* - * The OS doesn't seem to allow more than 10 words of - * parameters (yay!). So we shouldn't be here. - */ - warn("More than 10 words (%d) of arguments!\n", nargs); - break; - case 10: - case 9: - case 8: - case 7: - case 6: - case 5: - /* - * If there are 7-10 words of arguments, they are placed - * on the stack, as is normal for other processors. - * The fall-through for all of these is deliberate!!! - */ - // XXX BAD constant used here + for (i = 0; i < narg && reg <= MAXREG; i++, reg++) + cs->args[i] = regs.r_regs[reg]; + if (narg > i) { iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)(regs.r_regs[SP] + - 4 * sizeof(uint32_t)); - iorequest.piod_addr = &fsc->args[4]; - iorequest.piod_len = (nargs - 4) * sizeof(fsc->args[0]); + iorequest.piod_offs = (void *)((uintptr_t)regs.r_regs[SP] + + 4 * sizeof(cs->args[0])); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) - return; - case 4: fsc->args[3] = regs.r_regs[A3]; - case 3: fsc->args[2] = regs.r_regs[A2]; - case 2: fsc->args[1] = regs.r_regs[A1]; - case 1: fsc->args[0] = regs.r_regs[A0]; - case 0: break; - } - if (indir) { - memmove(&fsc->args[0], &fsc->args[1], - (nargs - 1) * sizeof(fsc->args[0])); + return (-1); } - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; - } - - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif - } - -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + return (0); } -/* - * And when the system call is done, we handle it here. - * Currently, no attempt is made to ensure that the system calls - * match -- this needs to be fixed (and is, in fact, why S_SCX includes - * the system call number instead of, say, an error status). - */ - -long -mips_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +mips_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.r_regs[V0]; - errorp = !!regs.r_regs[A3]; - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ - - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; - } - } - } - - if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; + /* XXX: Does not have special handling for __syscall(). */ + retval[0] = regs.r_regs[V0]; + retval[1] = regs.r_regs[V1]; + *errorp = !!regs.r_regs[A3]; + return (0); +} - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - retval, fsc->sc); - free_fsc(fsc); +static struct procabi mips_fbsd = { +#ifdef __mips_n64 + "FreeBSD ELF64", +#else + "FreeBSD ELF32", +#endif + syscallnames, + nitems(syscallnames), + mips_fetch_args, + mips_fetch_retval +}; - return (retval); -} +PROCABI(mips_fbsd); diff --git a/usr.bin/truss/powerpc-fbsd.c b/usr.bin/truss/powerpc-fbsd.c index cdbd1331f47b..4a11459e7860 100644 --- a/usr.bin/truss/powerpc-fbsd.c +++ b/usr.bin/truss/powerpc-fbsd.c @@ -25,41 +25,20 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * FreeBSD/powerpc-specific system call handling. This is probably the most - * complex part of the entire truss program, although I've got lots of - * it handled relatively cleanly now. The system call names are generated - * automatically, thanks to /usr/src/sys/kern/syscalls.master. The - * names used for the various structures are confusing, I sadly admit. - * - * This file is almost nothing more than a slightly-edited i386-fbsd.c. - */ +/* FreeBSD/powerpc-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <sys/syscall.h> #include <machine/reg.h> #include <machine/frame.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #ifdef __powerpc64__ /* 32-bit compatibility */ #include "freebsd32_syscalls.h" @@ -68,264 +47,104 @@ static const char rcsid[] = #include "syscalls.h" #endif -static int nsyscalls = nitems(syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct freebsd_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long *args; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct freebsd_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct freebsd_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct freebsd_syscall *fsc) -{ - int i; - - free(fsc->args); - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in powerpc/powerpc/trap.c - * is ever changed these functions need to keep up. - */ - -void -powerpc_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +powerpc_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct ptrace_io_desc iorequest; struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; - void *args; + struct current_syscall *cs; lwpid_t tid; - int i, regargs, syscall_num; - - /* Account for a 64-bit argument with corresponding alignment. */ - nargs += 2; + u_int i, reg; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; + return (-1); } /* - * FreeBSD has two special kinds of system call redirctions -- + * FreeBSD has two special kinds of system call redirections -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. */ - regargs = NARGREG; - syscall_num = regs.fixreg[0]; - args = ®s.fixreg[3]; - if (syscall_num == SYS_syscall) { - args = ®s.fixreg[4]; - regargs -= 1; - syscall_num = regs.fixreg[3]; - } else if (syscall_num == SYS___syscall) { - args = ®s.fixreg[5]; - regargs -= 2; - syscall_num = regs.fixreg[4]; + reg = 0; + switch (regs.fixreg[0]) { + case SYS_syscall: + reg += 1; + break; + case SYS___syscall: + reg += 2; + break; } - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); + for (i = 0; i < narg && reg < NARGREG; i++, reg++) { +#ifdef __powerpc64__ + cs->args[i] = regs.fixreg[FIRSTARG + reg] & 0xffffffff; +#else + cs->args[i] = regs.fixreg[FIRSTARG + reg]; +#endif } + if (narg > i) { +#ifdef __powerpc64__ + uint32_t args32[narg - i]; + u_int j; - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "fork") == 0 || - strcmp(fsc->name, "pdfork") == 0 || - strcmp(fsc->name, "rfork") == 0 || - strcmp(fsc->name, "vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - - fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); - - if (nargs > regargs) { - memmove(&fsc->args[0], args, regargs * sizeof(fsc->args[0])); - +#endif iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)(regs.fixreg[1] + 8); - iorequest.piod_addr = &fsc->args[regargs]; - iorequest.piod_len = (nargs - regargs) * sizeof(fsc->args[0]); +#ifdef __powerpc64__ + iorequest.piod_addr = args32; + iorequest.piod_len = sizeof(args32); +#else + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); +#endif ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) - return; - } else - memmove(&fsc->args[0], args, nargs * sizeof(fsc->args[0])); - - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); + return (-1); +#ifdef __powerpc64__ + for (j = 0; j < narg - i; j++) + cs->args[i + j] = args32[j]; #endif - fsc->nargs = nargs; } - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif - } - -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + return (0); } -/* - * And when the system call is done, we handle it here. - * Currently, no attempt is made to ensure that the system calls - * match -- this needs to be fixed (and is, in fact, why S_SCX includes - * the system call number instead of, say, an error status). - */ - -long -powerpc_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +powerpc_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.fixreg[3]; - errorp = !!(regs.cr & 0x10000000); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ - - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * On 32-bit big-endian, the low word of a 64-bit return is - * in the greater address. Switch to this. XXX note that - * print_syscall_ret can't handle 64-bit return values (llseek) - */ - if (sc->ret_type == 2) - retval = regs.fixreg[4]; - - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; - } - } - } - - if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; - - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ + /* XXX: Does not have fixup for __syscall(). */ +#ifdef __powerpc64__ + retval[0] = regs.fixreg[3] & 0xffffffff; + retval[1] = regs.fixreg[4] & 0xffffffff; +#else + retval[0] = regs.fixreg[3]; + retval[1] = regs.fixreg[4]; +#endif + *errorp = !!(regs.cr & 0x10000000); + return (0); +} - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - retval, fsc->sc); - free_fsc(fsc); +static struct procabi powerpc_fbsd = { + "FreeBSD ELF32", + syscallnames, + nitems(syscallnames), + powerpc_fetch_args, + powerpc_fetch_retval +}; - return (retval); -} +PROCABI(powerpc_fbsd); diff --git a/usr.bin/truss/powerpc64-fbsd.c b/usr.bin/truss/powerpc64-fbsd.c index 1f50429515a9..5ca5c22dc2cd 100644 --- a/usr.bin/truss/powerpc64-fbsd.c +++ b/usr.bin/truss/powerpc64-fbsd.c @@ -25,287 +25,94 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * FreeBSD/powerpc-specific system call handling. This is probably the most - * complex part of the entire truss program, although I've got lots of - * it handled relatively cleanly now. The system call names are generated - * automatically, thanks to /usr/src/sys/kern/syscalls.master. The - * names used for the various structures are confusing, I sadly admit. - * - * This file is almost nothing more than a slightly-edited i386-fbsd.c. - */ +/* FreeBSD/powerpc64-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <sys/syscall.h> #include <machine/reg.h> #include <machine/frame.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "syscalls.h" -static int nsyscalls = nitems(syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct freebsd_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long *args; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct freebsd_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct freebsd_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct freebsd_syscall *fsc) -{ - int i; - - free(fsc->args); - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in powerpc/powerpc/trap.c - * is ever changed these functions need to keep up. - */ - -void -powerpc64_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +powerpc64_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct ptrace_io_desc iorequest; struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; - void *args; + struct current_syscall *cs; lwpid_t tid; - int i, regargs, syscall_num; + u_int i, reg; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; + return (-1); } /* - * FreeBSD has two special kinds of system call redirctions -- + * FreeBSD has two special kinds of system call redirections -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. */ - regargs = NARGREG; - syscall_num = regs.fixreg[0]; - args = ®s.fixreg[3]; - if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) { - args = ®s.fixreg[4]; - regargs -= 1; - syscall_num = regs.fixreg[3]; - } - - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); + reg = 0; + switch (regs.fixreg[0]) { + case SYS_syscall: + case SYS___syscall: + reg += 1; + break; } - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "fork") == 0 || - strcmp(fsc->name, "pdfork") == 0 || - strcmp(fsc->name, "rfork") == 0 || - strcmp(fsc->name, "vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - - fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); - - if (nargs > regargs) { - memmove(&fsc->args[0], args, regargs * sizeof(fsc->args[0])); - + for (i = 0; i < narg && reg < NARGREG; i++, reg++) + cs->args[i] = regs.fixreg[FIRSTARG + reg]; + if (narg > i) { iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)(regs.fixreg[1] + 48); - iorequest.piod_addr = &fsc->args[regargs]; - iorequest.piod_len = (nargs - regargs) * sizeof(fsc->args[0]); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) - return; - } else - memmove(&fsc->args[0], args, nargs * sizeof(fsc->args[0])); - - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; - } - - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif + return (-1); } -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + return (0); } -/* - * And when the system call is done, we handle it here. - * Currently, no attempt is made to ensure that the system calls - * match -- this needs to be fixed (and is, in fact, why S_SCX includes - * the system call number instead of, say, an error status). - */ - -long -powerpc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +powerpc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.fixreg[3]; - errorp = !!(regs.cr & 0x10000000); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ - - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; - } - } - } - - if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; - - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ + retval[0] = regs.fixreg[3]; + retval[1] = regs.fixreg[4]; + *errorp = !!(regs.cr & 0x10000000); + return (0); +} - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - retval, fsc->sc); - free_fsc(fsc); +static struct procabi powerpc64_fbsd = { + "FreeBSD ELF64", + syscallnames, + nitems(syscallnames), + powerpc64_fetch_args, + powerpc64_fetch_retval +}; - return (retval); -} +PROCABI(powerpc64_fbsd); diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c index d6e430012e25..4452f9f47c7f 100644 --- a/usr.bin/truss/setup.c +++ b/usr.bin/truss/setup.c @@ -37,37 +37,39 @@ __FBSDID("$FreeBSD$"); * I'm afraid. */ -#include <sys/param.h> -#include <sys/types.h> #include <sys/ptrace.h> +#include <sys/sysctl.h> #include <sys/wait.h> +#include <assert.h> #include <err.h> #include <errno.h> -#include <fcntl.h> #include <signal.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> -#include <machine/reg.h> - #include "truss.h" +#include "syscall.h" #include "extern.h" +SET_DECLARE(procabi, struct procabi); + static sig_atomic_t detaching; +static void new_proc(struct trussinfo *, pid_t); + /* * setup_and_wait() is called to start a process. All it really does - * is fork(), set itself up to stop on exec or exit, and then exec - * the given command. At that point, the child process stops, and - * the parent can wake up and deal with it. + * is fork(), enable tracing in the child, and then exec the given + * command. At that point, the child process stops, and the parent + * can wake up and deal with it. */ - -int -setup_and_wait(char *command[]) +void +setup_and_wait(struct trussinfo *info, char *command[]) { pid_t pid; @@ -84,17 +86,14 @@ setup_and_wait(char *command[]) if (waitpid(pid, NULL, 0) < 0) err(1, "unexpect stop in waitpid"); - return (pid); + new_proc(info, pid); } /* - * start_tracing picks up where setup_and_wait() dropped off -- namely, - * it sets the event mask for the given process id. Called for both - * monitoring an existing process and when we create our own. + * start_tracing is called to attach to an existing process. */ - -int -start_tracing(pid_t pid) +void +start_tracing(struct trussinfo *info, pid_t pid) { int ret, retry; @@ -109,7 +108,7 @@ start_tracing(pid_t pid) if (waitpid(pid, NULL, 0) < 0) err(1, "Unexpect stop in waitpid"); - return (0); + new_proc(info, pid); } /* @@ -118,7 +117,6 @@ start_tracing(pid_t pid) * applies if truss was told to monitor an already-existing * process. */ - void restore_proc(int signo __unused) { @@ -126,116 +124,485 @@ restore_proc(int signo __unused) detaching = 1; } -static int +static void detach_proc(pid_t pid) { - int waitval; /* stop the child so that we can detach */ kill(pid, SIGSTOP); - if (waitpid(pid, &waitval, 0) < 0) + if (waitpid(pid, NULL, 0) < 0) err(1, "Unexpected stop in waitpid"); if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) err(1, "Can not detach the process"); kill(pid, SIGCONT); +} + +/* + * Determine the ABI. This is called after every exec, and when + * a process is first monitored. + */ +static struct procabi * +find_abi(pid_t pid) +{ + struct procabi **pabi; + size_t len; + int error; + int mib[4]; + char progt[32]; + + len = sizeof(progt); + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_SV_NAME; + mib[3] = pid; + error = sysctl(mib, 4, progt, &len, NULL, 0); + if (error != 0) + err(2, "can not get sysvec name"); + + SET_FOREACH(pabi, procabi) { + if (strcmp((*pabi)->type, progt) == 0) + return (*pabi); + } + warnx("ABI %s for pid %ld is not supported", progt, (long)pid); + return (NULL); +} + +static void +new_proc(struct trussinfo *info, pid_t pid) +{ + struct procinfo *np; + + /* + * If this happens it means there is a bug in truss. Unfortunately + * this will kill any processes are attached to. + */ + LIST_FOREACH(np, &info->proclist, entries) { + if (np->pid == pid) + errx(1, "Duplicate process for pid %ld", (long)pid); + } + + if (info->flags & FOLLOWFORKS) + if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1) + err(1, "Unable to follow forks for pid %ld", (long)pid); + np = calloc(1, sizeof(struct procinfo)); + np->pid = pid; + np->abi = find_abi(pid); + SLIST_INIT(&np->threadlist); + LIST_INSERT_HEAD(&info->proclist, np, entries); +} + +static void +free_proc(struct procinfo *p) +{ + struct threadinfo *t, *t2; + + SLIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) { + free(t); + } + LIST_REMOVE(p, entries); + free(p); +} - return (waitval); +static void +detach_all_procs(struct trussinfo *info) +{ + struct procinfo *p, *p2; + + LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) { + detach_proc(p->pid); + free_proc(p); + } +} + +static struct procinfo * +find_proc(struct trussinfo *info, pid_t pid) +{ + struct procinfo *np; + + LIST_FOREACH(np, &info->proclist, entries) { + if (np->pid == pid) + return (np); + } + + return (NULL); } /* - * Change curthread member based on lwpid. - * If it is a new thread, create a threadinfo structure + * Change curthread member based on (pid, lwpid). + * If it is a new thread, create a threadinfo structure. */ static void -find_thread(struct trussinfo *info, lwpid_t lwpid) +find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid) { - struct threadinfo *np; + struct procinfo *np; + struct threadinfo *nt; - info->curthread = NULL; - SLIST_FOREACH(np, &info->threadlist, entries) { - if (np->tid == lwpid) { - info->curthread = np; + np = find_proc(info, pid); + assert(np != NULL); + + SLIST_FOREACH(nt, &np->threadlist, entries) { + if (nt->tid == lwpid) { + info->curthread = nt; return; } } - np = (struct threadinfo *)calloc(1, sizeof(struct threadinfo)); - if (np == NULL) + nt = calloc(1, sizeof(struct threadinfo)); + if (nt == NULL) err(1, "calloc() failed"); - np->tid = lwpid; - SLIST_INSERT_HEAD(&info->threadlist, np, entries); - info->curthread = np; + nt->proc = np; + nt->tid = lwpid; + SLIST_INSERT_HEAD(&np->threadlist, nt, entries); + info->curthread = nt; } /* - * Start the traced process and wait until it stoped. - * Fill trussinfo structure. - * When this even returns, the traced process is in stop state. + * When a process exits, it no longer has any threads left. However, + * the main loop expects a valid curthread. In cases when a thread + * triggers the termination (e.g. calling exit or triggering a fault) + * we would ideally use that thread. However, if a process is killed + * by a signal sent from another process then there is no "correct" + * thread. We just punt and use the first thread. */ -void -waitevent(struct trussinfo *info) +static void +find_exit_thread(struct trussinfo *info, pid_t pid) +{ + struct procinfo *np; + struct threadinfo *nt; + + np = find_proc(info, pid); + assert(np != NULL); + + if (SLIST_EMPTY(&np->threadlist)) { + /* + * If an existing process exits right after we attach + * to it but before it posts any events, there won't + * be any threads. Create a dummy thread and set its + * "before" time to the global start time. + */ + nt = calloc(1, sizeof(struct threadinfo)); + if (nt == NULL) + err(1, "calloc() failed"); + nt->proc = np; + nt->tid = 0; + SLIST_INSERT_HEAD(&np->threadlist, nt, entries); + nt->before = info->start_time; + } + info->curthread = SLIST_FIRST(&np->threadlist); +} + +static void +alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl) +{ + u_int i; + + assert(t->in_syscall == 0); + assert(t->cs.number == 0); + assert(t->cs.name == NULL); + assert(t->cs.nargs == 0); + for (i = 0; i < nitems(t->cs.s_args); i++) + assert(t->cs.s_args[i] == NULL); + memset(t->cs.args, 0, sizeof(t->cs.args)); + t->cs.number = pl->pl_syscall_code; + t->in_syscall = 1; +} + +static void +free_syscall(struct threadinfo *t) { - struct ptrace_lwpinfo lwpinfo; - static int pending_signal = 0; - int waitval; + u_int i; + + for (i = 0; i < t->cs.nargs; i++) + free(t->cs.s_args[i]); + memset(&t->cs, 0, sizeof(t->cs)); + t->in_syscall = 0; +} - ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal); - pending_signal = 0; +static void +enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) +{ + struct threadinfo *t; + struct syscall *sc; + u_int i, narg; -detach: - if (detaching) { - waitval = detach_proc(info->pid); - info->pr_why = S_DETACHED; - info->pr_data = WEXITSTATUS(waitval); + t = info->curthread; + alloc_syscall(t, pl); + narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args)); + if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) { + free_syscall(t); return; } - if (waitpid(info->pid, &waitval, 0) == -1) { - if (errno == EINTR) - goto detach; - err(1, "Unexpected stop in waitpid"); + if (t->cs.number >= 0 && t->cs.number < t->proc->abi->nsyscalls) + t->cs.name = t->proc->abi->syscallnames[t->cs.number]; + if (t->cs.name == NULL) + fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", + t->proc->abi->type, t->cs.number); + + sc = get_syscall(t->cs.name); + if (sc) { + t->cs.nargs = sc->nargs; + assert(sc->nargs <= nitems(t->cs.s_args)); + } else { +#if DEBUG + fprintf(stderr, "unknown syscall %s -- setting " + "args to %d\n", t->cs.name, t->cs.nargs); +#endif + t->cs.nargs = narg; } - if (WIFCONTINUED(waitval)) { - info->pr_why = S_NONE; - return; + t->cs.sc = sc; + + /* + * At this point, we set up the system call arguments. + * We ignore any OUT ones, however -- those are arguments that + * are set by the system call, and so are probably meaningless + * now. This doesn't currently support arguments that are + * passed in *and* out, however. + */ + if (t->cs.name != NULL) { +#if DEBUG + fprintf(stderr, "syscall %s(", t->cs.name); +#endif + for (i = 0; i < t->cs.nargs; i++) { +#if DEBUG + fprintf(stderr, "0x%lx%s", sc ? + t->cs.args[sc->args[i].offset] : t->cs.args[i], + i < (t->cs.nargs - 1) ? "," : ""); +#endif + if (sc && !(sc->args[i].type & OUT)) { + t->cs.s_args[i] = print_arg(&sc->args[i], + t->cs.args, 0, info); + } + } +#if DEBUG + fprintf(stderr, ")\n"); +#endif } - if (WIFEXITED(waitval)) { - info->pr_why = S_EXIT; - info->pr_data = WEXITSTATUS(waitval); + + clock_gettime(CLOCK_REALTIME, &t->before); +} + +static void +exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) +{ + struct threadinfo *t; + struct procinfo *p; + struct syscall *sc; + long retval[2]; + u_int i; + int errorp; + + t = info->curthread; + if (!t->in_syscall) + return; + + clock_gettime(CLOCK_REALTIME, &t->after); + p = t->proc; + if (p->abi->fetch_retval(info, retval, &errorp) < 0) { + free_syscall(t); return; } - if (WIFSTOPPED(waitval)) { - ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo, - sizeof(lwpinfo)); - find_thread(info, lwpinfo.pl_lwpid); - switch (WSTOPSIG(waitval)) { - case SIGTRAP: - if (lwpinfo.pl_flags & PL_FLAG_SCE) { - info->pr_why = S_SCE; - info->curthread->in_syscall = 1; - break; - } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { - info->pr_why = S_SCX; - info->curthread->in_syscall = 0; - break; - } else { - errx(1, + + sc = t->cs.sc; + if (sc == NULL) { + for (i = 0; i < t->cs.nargs; i++) + asprintf(&t->cs.s_args[i], "0x%lx", t->cs.args[i]); + } else { + /* + * Here, we only look for arguments that have OUT masked in -- + * otherwise, they were handled in enter_syscall(). + */ + for (i = 0; i < sc->nargs; i++) { + char *temp; + + if (sc->args[i].type & OUT) { + /* + * If an error occurred, then don't bother + * getting the data; it may not be valid. + */ + if (errorp) { + asprintf(&temp, "0x%lx", + t->cs.args[sc->args[i].offset]); + } else { + temp = print_arg(&sc->args[i], + t->cs.args, retval, info); + } + t->cs.s_args[i] = temp; + } + } + } + + print_syscall_ret(info, t->cs.name, t->cs.nargs, t->cs.s_args, + errorp, retval, sc); + free_syscall(t); + + /* + * If the process executed a new image, check the ABI. If the + * new ABI isn't supported, stop tracing this process. + */ + if (pl->pl_flags & PL_FLAG_EXEC) { + p->abi = find_abi(p->pid); + if (p->abi == NULL) { + if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0) + err(1, "Can not detach the process"); + free_proc(p); + } + } +} + +static void +report_exit(struct trussinfo *info, siginfo_t *si) +{ + struct timespec timediff; + + if (info->flags & FOLLOWFORKS) + fprintf(info->outfile, "%5d: ", si->si_pid); + clock_gettime(CLOCK_REALTIME, &info->curthread->after); + if (info->flags & ABSOLUTETIMESTAMPS) { + timespecsubt(&info->curthread->after, &info->start_time, + &timediff); + fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, + timediff.tv_nsec); + } + if (info->flags & RELATIVETIMESTAMPS) { + timespecsubt(&info->curthread->after, &info->curthread->before, + &timediff); + fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, + timediff.tv_nsec); + } + if (si->si_code == CLD_EXITED) + fprintf(info->outfile, "process exit, rval = %u\n", + si->si_status); + else + fprintf(info->outfile, "process killed, signal = %u%s\n", + si->si_status, si->si_code == CLD_DUMPED ? + " (core dumped)" : ""); +} + +static void +report_new_child(struct trussinfo *info, pid_t pid) +{ + struct timespec timediff; + + clock_gettime(CLOCK_REALTIME, &info->curthread->after); + assert(info->flags & FOLLOWFORKS); + fprintf(info->outfile, "%5d: ", pid); + if (info->flags & ABSOLUTETIMESTAMPS) { + timespecsubt(&info->curthread->after, &info->start_time, + &timediff); + fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, + timediff.tv_nsec); + } + if (info->flags & RELATIVETIMESTAMPS) { + timediff.tv_sec = 0; + timediff.tv_nsec = 0; + fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, + timediff.tv_nsec); + } + fprintf(info->outfile, "<new process>\n"); +} + +static void +report_signal(struct trussinfo *info, siginfo_t *si) +{ + struct timespec timediff; + char *signame; + + if (info->flags & FOLLOWFORKS) + fprintf(info->outfile, "%5d: ", si->si_pid); + if (info->flags & ABSOLUTETIMESTAMPS) { + timespecsubt(&info->curthread->after, &info->start_time, + &timediff); + fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, + timediff.tv_nsec); + } + if (info->flags & RELATIVETIMESTAMPS) { + timespecsubt(&info->curthread->after, &info->curthread->before, + &timediff); + fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, + timediff.tv_nsec); + } + signame = strsig(si->si_status); + fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status, + signame == NULL ? "?" : signame); +} + +/* + * Wait for events until all the processes have exited or truss has been + * asked to stop. + */ +void +eventloop(struct trussinfo *info) +{ + struct ptrace_lwpinfo pl; + siginfo_t si; + int pending_signal; + + while (!LIST_EMPTY(&info->proclist)) { + if (detaching) { + detach_all_procs(info); + return; + } + + if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { + if (errno == EINTR) + continue; + err(1, "Unexpected error from waitid"); + } + + assert(si.si_signo == SIGCHLD); + + switch (si.si_code) { + case CLD_EXITED: + case CLD_KILLED: + case CLD_DUMPED: + find_exit_thread(info, si.si_pid); + if ((info->flags & COUNTONLY) == 0) + report_exit(info, &si); + free_proc(info->curthread->proc); + info->curthread = NULL; + break; + case CLD_TRAPPED: + if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl, + sizeof(pl)) == -1) + err(1, "ptrace(PT_LWPINFO)"); + + if (pl.pl_flags & PL_FLAG_CHILD) { + new_proc(info, si.si_pid); + assert(LIST_FIRST(&info->proclist)->abi != + NULL); + } + find_thread(info, si.si_pid, pl.pl_lwpid); + + if (si.si_status == SIGTRAP) { + if (pl.pl_flags & PL_FLAG_SCE) + enter_syscall(info, &pl); + else if (pl.pl_flags & PL_FLAG_SCX) + exit_syscall(info, &pl); + else + errx(1, "pl_flags %x contains neither PL_FLAG_SCE nor PL_FLAG_SCX", - lwpinfo.pl_flags); + pl.pl_flags); + pending_signal = 0; + } else if (pl.pl_flags & PL_FLAG_CHILD) { + if ((info->flags & COUNTONLY) == 0) + report_new_child(info, si.si_pid); + pending_signal = 0; + } else { + if ((info->flags & NOSIGS) == 0) + report_signal(info, &si); + pending_signal = si.si_status; } - default: - info->pr_why = S_SIG; - info->pr_data = WSTOPSIG(waitval); - pending_signal = info->pr_data; + ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1, + pending_signal); + break; + case CLD_STOPPED: + errx(1, "waitid reported CLD_STOPPED"); + case CLD_CONTINUED: break; } } - if (WIFSIGNALED(waitval)) { - info->pr_why = S_EXIT; - info->pr_data = 0; - return; - } } diff --git a/usr.bin/truss/sparc64-fbsd.c b/usr.bin/truss/sparc64-fbsd.c index 4e64c7027112..c8c1e8c27c07 100644 --- a/usr.bin/truss/sparc64-fbsd.c +++ b/usr.bin/truss/sparc64-fbsd.c @@ -29,22 +29,11 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/* - * FreeBSD/sparc64-specific system call handling. This is probably the most - * complex part of the entire truss program, although I've got lots of - * it handled relatively cleanly now. The system call names are generated - * automatically, thanks to /usr/src/sys/kern/syscalls.master. The - * names used for the various structures are confusing, I sadly admit. - * - * This file is almost nothing more than a slightly-edited i386-fbsd.c. - */ +/* FreeBSD/sparc64-specific system call handling. */ -#include <sys/types.h> #include <sys/ptrace.h> #include <sys/syscall.h> @@ -52,289 +41,85 @@ static const char rcsid[] = #include <machine/reg.h> #include <machine/tstate.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <stddef.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> #include "truss.h" -#include "syscall.h" -#include "extern.h" #include "syscalls.h" -static int nsyscalls = nitems(syscallnames); - -/* - * This is what this particular file uses to keep track of a system call. - * It is probably not quite sufficient -- I can probably use the same - * structure for the various syscall personalities, and I also probably - * need to nest system calls (for signal handlers). - * - * 'struct syscall' describes the system call; it may be NULL, however, - * if we don't know about this particular system call yet. - */ -struct freebsd_syscall { - struct syscall *sc; - const char *name; - int number; - unsigned long *args; - int nargs; /* number of arguments -- *not* number of words! */ - char **s_args; /* the printable arguments */ -}; - -static struct freebsd_syscall * -alloc_fsc(void) -{ - - return (malloc(sizeof(struct freebsd_syscall))); -} - -/* Clear up and free parts of the fsc structure. */ -static void -free_fsc(struct freebsd_syscall *fsc) -{ - int i; - - free(fsc->args); - if (fsc->s_args) { - for (i = 0; i < fsc->nargs; i++) - free(fsc->s_args[i]); - free(fsc->s_args); - } - free(fsc); -} - -/* - * Called when a process has entered a system call. nargs is the - * number of words, not number of arguments (a necessary distinction - * in some cases). Note that if the STOPEVENT() code in sparc64/sparc64/trap.c - * is ever changed these functions need to keep up. - */ - -void -sparc64_syscall_entry(struct trussinfo *trussinfo, int nargs) +static int +sparc64_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct ptrace_io_desc iorequest; struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; + struct current_syscall *cs; lwpid_t tid; - int i, syscall_num; - int indir; /* indirect system call */ + u_int i, reg; tid = trussinfo->curthread->tid; - + cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return; + return (-1); } /* - * FreeBSD has two special kinds of system call redirctions -- + * FreeBSD has two special kinds of system call redirections -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. */ - indir = 0; - syscall_num = regs.r_global[1]; - if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) { - indir = 1; - syscall_num = regs.r_out[0]; - } - - fsc = alloc_fsc(); - if (fsc == NULL) - return; - fsc->number = syscall_num; - fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? - NULL : syscallnames[syscall_num]; - if (!fsc->name) { - fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", - syscall_num); + reg = 0; + switch (regs.r_global[1]) { + case SYS_syscall: + case SYS___syscall: + reg = 1; + break; } - if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && - (strcmp(fsc->name, "fork") == 0 || - strcmp(fsc->name, "pdfork") == 0 || - strcmp(fsc->name, "rfork") == 0 || - strcmp(fsc->name, "vfork") == 0)) - trussinfo->curthread->in_fork = 1; - - if (nargs == 0) - return; - - fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); - switch (nargs) { - default: - /* - * The OS doesn't seem to allow more than 10 words of - * parameters (yay!). So we shouldn't be here. - */ - warn("More than 10 words (%d) of arguments!\n", nargs); - break; - case 10: - case 9: - case 8: - case 7: - /* - * If there are 7-10 words of arguments, they are placed - * on the stack, as is normal for other processors. - * The fall-through for all of these is deliberate!!! - */ + for (i = 0; i < narg && reg < 6; i++, reg++) + cs->args[i] = regs.r_out[reg]; + if (narg > i) { iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)(regs.r_out[6] + SPOFF + offsetof(struct frame, fr_pad[6])); - iorequest.piod_addr = &fsc->args[6]; - iorequest.piod_len = (nargs - 6) * sizeof(fsc->args[0]); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) - return; - case 6: fsc->args[5] = regs.r_out[5]; - case 5: fsc->args[4] = regs.r_out[4]; - case 4: fsc->args[3] = regs.r_out[3]; - case 3: fsc->args[2] = regs.r_out[2]; - case 2: fsc->args[1] = regs.r_out[1]; - case 1: fsc->args[0] = regs.r_out[0]; - case 0: - break; + return (-1); } - if (indir) - memmove(&fsc->args[0], &fsc->args[1], (nargs - 1) * - sizeof(fsc->args[0])); - - sc = get_syscall(fsc->name); - if (sc) - fsc->nargs = sc->nargs; - else { -#if DEBUG - fprintf(trussinfo->outfile, "unknown syscall %s -- setting " - "args to %d\n", fsc->name, nargs); -#endif - fsc->nargs = nargs; - } - - fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); - fsc->sc = sc; - - /* - * At this point, we set up the system call arguments. - * We ignore any OUT ones, however -- those are arguments that - * are set by the system call, and so are probably meaningless - * now. This doesn't currently support arguments that are - * passed in *and* out, however. - */ - - if (fsc->name) { -#if DEBUG - fprintf(stderr, "syscall %s(", fsc->name); -#endif - for (i = 0; i < fsc->nargs; i++) { -#if DEBUG - fprintf(stderr, "0x%x%s", sc ? - fsc->args[sc->args[i].offset] : fsc->args[i], - i < (fsc->nargs - 1) ? "," : ""); -#endif - if (sc && !(sc->args[i].type & OUT)) { - fsc->s_args[i] = print_arg(&sc->args[i], - fsc->args, 0, trussinfo); - } - } -#if DEBUG - fprintf(stderr, ")\n"); -#endif - } - -#if DEBUG - fprintf(trussinfo->outfile, "\n"); -#endif - - trussinfo->curthread->fsc = fsc; + return (0); } -/* - * And when the system call is done, we handle it here. - * Currently, no attempt is made to ensure that the system calls - * match -- this needs to be fixed (and is, in fact, why S_SCX includes - * the system call number instead of, say, an error status). - */ - -long -sparc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) +static int +sparc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; - struct freebsd_syscall *fsc; - struct syscall *sc; lwpid_t tid; - long retval; - int errorp, i; - - if (trussinfo->curthread->fsc == NULL) - return (-1); tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } - retval = regs.r_out[0]; - errorp = !!(regs.r_tstate & TSTATE_XCC_C); - - /* - * This code, while simpler than the initial versions I used, could - * stand some significant cleaning. - */ - - fsc = trussinfo->curthread->fsc; - sc = fsc->sc; - if (!sc) { - for (i = 0; i < fsc->nargs; i++) - asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); - } else { - /* - * Here, we only look for arguments that have OUT masked in -- - * otherwise, they were handled in the syscall_entry function. - */ - for (i = 0; i < sc->nargs; i++) { - char *temp; - - if (sc->args[i].type & OUT) { - /* - * If an error occurred, then don't bother - * getting the data; it may not be valid. - */ - if (errorp) { - asprintf(&temp, "0x%lx", - fsc->args[sc->args[i].offset]); - } else { - temp = print_arg(&sc->args[i], - fsc->args, retval, trussinfo); - } - fsc->s_args[i] = temp; - } - } - } - - if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || - strcmp(fsc->name, "exit") == 0)) - trussinfo->curthread->in_syscall = 1; - - /* - * It would probably be a good idea to merge the error handling, - * but that complicates things considerably. - */ + retval[0] = regs.r_out[0]; + retval[1] = regs.r_out[1]; + *errorp = !!(regs.r_tstate & TSTATE_XCC_C); + return (0); +} - print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, - retval, fsc->sc); - free_fsc(fsc); +static struct procabi sparc64_fbsd = { + "FreeBSD ELF64", + syscallnames, + nitems(syscallnames), + sparc64_fetch_args, + sparc64_fetch_retval +}; - return (retval); -} +PROCABI(sparc64_fbsd); diff --git a/usr.bin/truss/syscall.h b/usr.bin/truss/syscall.h index 6f4d9a3807ea..ee352147b125 100644 --- a/usr.bin/truss/syscall.h +++ b/usr.bin/truss/syscall.h @@ -42,7 +42,7 @@ enum Argtype { None = 1, Hex, Octal, Int, LongHex, Name, Ptr, Stat, Ioctl, Quad, Fcntlflag, Rusage, BinString, Shutdown, Resource, Rlimit, Timeval2, Pathconf, Rforkflags, ExitStatus, Waitoptions, Idtype, Procctl, LinuxSockArgs, Umtxop, Atfd, Atflags, Timespec2, Accessmode, Long, - Sysarch, ExecArgs, ExecEnv }; + Sysarch, ExecArgs, ExecEnv, PipeFds, QuadHex }; #define ARG_MASK 0xff #define OUT 0x100 @@ -55,8 +55,8 @@ struct syscall_args { struct syscall { const char *name; - int ret_type; /* 0, 1, or 2 return values */ - int nargs; /* actual number of meaningful arguments */ + u_int ret_type; /* 0, 1, or 2 return values */ + u_int nargs; /* actual number of meaningful arguments */ /* Hopefully, no syscalls with > 10 args */ struct syscall_args args[10]; struct timespec time; /* Time spent for this call */ @@ -65,7 +65,7 @@ struct syscall { }; struct syscall *get_syscall(const char*); -char *print_arg(struct syscall_args *, unsigned long*, long, struct trussinfo *); +char *print_arg(struct syscall_args *, unsigned long*, long *, struct trussinfo *); /* * Linux Socket defines @@ -86,11 +86,11 @@ char *print_arg(struct syscall_args *, unsigned long*, long, struct trussinfo *) #define LINUX_SETSOCKOPT 14 #define LINUX_GETSOCKOPT 15 #define LINUX_SENDMSG 16 -#define LINUX_RECVMSG 17 +#define LINUX_RECVMSG 17 #define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \ 0 : sizeof(register_t) - sizeof(t)) - + #if BYTE_ORDER == LITTLE_ENDIAN #define PADL_(t) 0 #define PADR_(t) PAD_(t) @@ -109,5 +109,5 @@ struct linux_socketcall_args { void print_syscall(struct trussinfo *, const char *, int, char **); void print_syscall_ret(struct trussinfo *, const char *, int, char **, int, - long, struct syscall *); + long *, struct syscall *); void print_summary(struct trussinfo *trussinfo); diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c index fac47f4568a7..ab163d8e02a5 100644 --- a/usr.bin/truss/syscalls.c +++ b/usr.bin/truss/syscalls.c @@ -29,10 +29,8 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); /* * This file has routines used to print out system calls and their @@ -40,29 +38,27 @@ static const char rcsid[] = */ #include <sys/types.h> +#include <sys/event.h> +#include <sys/ioccom.h> #include <sys/mman.h> #include <sys/procctl.h> #include <sys/ptrace.h> +#include <sys/resource.h> #include <sys/socket.h> -#include <sys/time.h> +#include <sys/stat.h> +#include <sys/umtx.h> #include <sys/un.h> #include <sys/wait.h> +#include <machine/sysarch.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <sys/ioccom.h> -#include <machine/atomic.h> -#include <errno.h> -#include <sys/umtx.h> -#include <sys/event.h> -#include <sys/stat.h> -#include <sys/resource.h> -#include <machine/sysarch.h> #include <ctype.h> #include <err.h> #include <fcntl.h> #include <poll.h> #include <signal.h> +#include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -76,7 +72,7 @@ static const char rcsid[] = #include "syscall.h" /* 64-bit alignment on 32-bit platforms. */ -#ifdef __powerpc__ +#if !defined(__LP64__) && defined(__powerpc__) #define QUAD_ALIGN 1 #else #define QUAD_ALIGN 0 @@ -95,39 +91,29 @@ static const char rcsid[] = static struct syscall syscalls[] = { { .name = "fcntl", .ret_type = 1, .nargs = 3, .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } }, - { .name = "fork", .ret_type = 1, .nargs = 0 }, - { .name = "vfork", .ret_type = 1, .nargs = 0 }, { .name = "rfork", .ret_type = 1, .nargs = 1, .args = { { Rforkflags, 0 } } }, - { .name = "getegid", .ret_type = 1, .nargs = 0 }, - { .name = "geteuid", .ret_type = 1, .nargs = 0 }, { .name = "linux_readlink", .ret_type = 1, .nargs = 3, .args = { { Name, 0 }, { Name | OUT, 1 }, { Int, 2 } } }, { .name = "linux_socketcall", .ret_type = 1, .nargs = 2, .args = { { Int, 0 }, { LinuxSockArgs, 1 } } }, - { .name = "getgid", .ret_type = 1, .nargs = 0 }, - { .name = "getpid", .ret_type = 1, .nargs = 0 }, { .name = "getpgid", .ret_type = 1, .nargs = 1, .args = { { Int, 0 } } }, - { .name = "getpgrp", .ret_type = 1, .nargs = 0 }, - { .name = "getppid", .ret_type = 1, .nargs = 0 }, { .name = "getsid", .ret_type = 1, .nargs = 1, .args = { { Int, 0 } } }, - { .name = "getuid", .ret_type = 1, .nargs = 0 }, - { .name = "issetugid", .ret_type = 1, .nargs = 0 }, { .name = "readlink", .ret_type = 1, .nargs = 3, .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Int, 2 } } }, { .name = "readlinkat", .ret_type = 1, .nargs = 4, .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 }, { Int, 3 } } }, { .name = "lseek", .ret_type = 2, .nargs = 3, - .args = { { Int, 0 }, { Quad, 1 + QUAD_ALIGN }, + .args = { { Int, 0 }, { QuadHex, 1 + QUAD_ALIGN }, { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } }, { .name = "linux_lseek", .ret_type = 2, .nargs = 3, .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } }, - { .name = "mmap", .ret_type = 2, .nargs = 6, + { .name = "mmap", .ret_type = 1, .nargs = 6, .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, - { Int, 4 }, { Quad, 5 + QUAD_ALIGN } } }, + { Int, 4 }, { QuadHex, 5 + QUAD_ALIGN } } }, { .name = "linux_mkdir", .ret_type = 1, .nargs = 2, .args = { { Name | IN, 0 }, { Int, 1 } } }, { .name = "mprotect", .ret_type = 1, .nargs = 3, @@ -145,49 +131,49 @@ static struct syscall syscalls[] = { .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } }, { .name = "close", .ret_type = 1, .nargs = 1, .args = { { Int, 0 } } }, - { .name = "link", .ret_type = 0, .nargs = 2, + { .name = "link", .ret_type = 1, .nargs = 2, .args = { { Name, 0 }, { Name, 1 } } }, - { .name = "linkat", .ret_type = 0, .nargs = 5, + { .name = "linkat", .ret_type = 1, .nargs = 5, .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 }, { Atflags, 4 } } }, - { .name = "unlink", .ret_type = 0, .nargs = 1, + { .name = "unlink", .ret_type = 1, .nargs = 1, .args = { { Name, 0 } } }, - { .name = "unlinkat", .ret_type = 0, .nargs = 3, + { .name = "unlinkat", .ret_type = 1, .nargs = 3, .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } }, - { .name = "chdir", .ret_type = 0, .nargs = 1, + { .name = "chdir", .ret_type = 1, .nargs = 1, .args = { { Name, 0 } } }, - { .name = "chroot", .ret_type = 0, .nargs = 1, + { .name = "chroot", .ret_type = 1, .nargs = 1, .args = { { Name, 0 } } }, - { .name = "mkfifo", .ret_type = 0, .nargs = 2, + { .name = "mkfifo", .ret_type = 1, .nargs = 2, .args = { { Name, 0 }, { Octal, 1 } } }, - { .name = "mkfifoat", .ret_type = 0, .nargs = 3, + { .name = "mkfifoat", .ret_type = 1, .nargs = 3, .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } }, - { .name = "mknod", .ret_type = 0, .nargs = 3, + { .name = "mknod", .ret_type = 1, .nargs = 3, .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } }, - { .name = "mknodat", .ret_type = 0, .nargs = 4, + { .name = "mknodat", .ret_type = 1, .nargs = 4, .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } }, - { .name = "chmod", .ret_type = 0, .nargs = 2, + { .name = "chmod", .ret_type = 1, .nargs = 2, .args = { { Name, 0 }, { Octal, 1 } } }, - { .name = "fchmod", .ret_type = 0, .nargs = 2, + { .name = "fchmod", .ret_type = 1, .nargs = 2, .args = { { Int, 0 }, { Octal, 1 } } }, - { .name = "lchmod", .ret_type = 0, .nargs = 2, + { .name = "lchmod", .ret_type = 1, .nargs = 2, .args = { { Name, 0 }, { Octal, 1 } } }, - { .name = "fchmodat", .ret_type = 0, .nargs = 4, + { .name = "fchmodat", .ret_type = 1, .nargs = 4, .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } }, - { .name = "chown", .ret_type = 0, .nargs = 3, + { .name = "chown", .ret_type = 1, .nargs = 3, .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, - { .name = "fchown", .ret_type = 0, .nargs = 3, + { .name = "fchown", .ret_type = 1, .nargs = 3, .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } }, - { .name = "lchown", .ret_type = 0, .nargs = 3, + { .name = "lchown", .ret_type = 1, .nargs = 3, .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, - { .name = "fchownat", .ret_type = 0, .nargs = 5, + { .name = "fchownat", .ret_type = 1, .nargs = 5, .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 }, { Atflags, 4 } } }, { .name = "linux_stat64", .ret_type = 1, .nargs = 3, .args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 } } }, - { .name = "mount", .ret_type = 0, .nargs = 4, + { .name = "mount", .ret_type = 1, .nargs = 4, .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } }, - { .name = "umount", .ret_type = 0, .nargs = 2, + { .name = "umount", .ret_type = 1, .nargs = 2, .args = { { Name, 0 }, { Int, 2 } } }, { .name = "fstat", .ret_type = 1, .nargs = 2, .args = { { Int, 0 }, { Stat | OUT, 1 } } }, @@ -250,19 +236,19 @@ static struct syscall syscalls[] = { { .name = "linux_execve", .ret_type = 1, .nargs = 3, .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 }, { ExecEnv | IN, 2 } } }, - { .name = "kldload", .ret_type = 0, .nargs = 1, + { .name = "kldload", .ret_type = 1, .nargs = 1, .args = { { Name | IN, 0 } } }, - { .name = "kldunload", .ret_type = 0, .nargs = 1, + { .name = "kldunload", .ret_type = 1, .nargs = 1, .args = { { Int, 0 } } }, - { .name = "kldfind", .ret_type = 0, .nargs = 1, + { .name = "kldfind", .ret_type = 1, .nargs = 1, .args = { { Name | IN, 0 } } }, - { .name = "kldnext", .ret_type = 0, .nargs = 1, + { .name = "kldnext", .ret_type = 1, .nargs = 1, .args = { { Int, 0 } } }, - { .name = "kldstat", .ret_type = 0, .nargs = 2, + { .name = "kldstat", .ret_type = 1, .nargs = 2, .args = { { Int, 0 }, { Ptr, 1 } } }, - { .name = "kldfirstmod", .ret_type = 0, .nargs = 1, + { .name = "kldfirstmod", .ret_type = 1, .nargs = 1, .args = { { Int, 0 } } }, - { .name = "nanosleep", .ret_type = 0, .nargs = 1, + { .name = "nanosleep", .ret_type = 1, .nargs = 1, .args = { { Timespec, 0 } } }, { .name = "select", .ret_type = 1, .nargs = 5, .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, @@ -279,18 +265,18 @@ static struct syscall syscalls[] = { .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } }, { .name = "kse_release", .ret_type = 0, .nargs = 1, .args = { { Timespec, 0 } } }, - { .name = "kevent", .ret_type = 0, .nargs = 6, + { .name = "kevent", .ret_type = 1, .nargs = 6, .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } }, - { .name = "sigpending", .ret_type = 0, .nargs = 1, + { .name = "sigpending", .ret_type = 1, .nargs = 1, .args = { { Sigset | OUT, 0 } } }, - { .name = "sigprocmask", .ret_type = 0, .nargs = 3, + { .name = "sigprocmask", .ret_type = 1, .nargs = 3, .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } }, - { .name = "sigqueue", .ret_type = 0, .nargs = 3, + { .name = "sigqueue", .ret_type = 1, .nargs = 3, .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } }, - { .name = "sigreturn", .ret_type = 0, .nargs = 1, + { .name = "sigreturn", .ret_type = 1, .nargs = 1, .args = { { Ptr, 0 } } }, - { .name = "sigsuspend", .ret_type = 0, .nargs = 1, + { .name = "sigsuspend", .ret_type = 1, .nargs = 1, .args = { { Sigset | IN, 0 } } }, { .name = "sigtimedwait", .ret_type = 1, .nargs = 3, .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } }, @@ -332,13 +318,13 @@ static struct syscall syscalls[] = { { .name = "pathconf", .ret_type = 1, .nargs = 2, .args = { { Name | IN, 0 }, { Pathconf, 1 } } }, { .name = "pipe", .ret_type = 1, .nargs = 1, - .args = { { Ptr, 0 } } }, + .args = { { PipeFds | OUT, 0 } } }, { .name = "pipe2", .ret_type = 1, .nargs = 2, .args = { { Ptr, 0 }, { Open, 1 } } }, - { .name = "truncate", .ret_type = 1, .nargs = 3, - .args = { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, - { .name = "ftruncate", .ret_type = 1, .nargs = 3, - .args = { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, + { .name = "truncate", .ret_type = 1, .nargs = 2, + .args = { { Name | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } }, + { .name = "ftruncate", .ret_type = 1, .nargs = 2, + .args = { { Int | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } }, { .name = "kill", .ret_type = 1, .nargs = 2, .args = { { Int | IN, 0 }, { Signal | IN, 1 } } }, { .name = "munmap", .ret_type = 1, .nargs = 2, @@ -359,18 +345,23 @@ static struct syscall syscalls[] = { .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 }, { Rusage | OUT, 3 } } }, { .name = "wait6", .ret_type = 1, .nargs = 6, - .args = { { Idtype, 0 }, { Int, 1 }, { ExitStatus | OUT, 2 }, - { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } }, + .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN }, + { ExitStatus | OUT, 1 + QUAD_ALIGN + QUAD_SLOTS }, + { Waitoptions, 2 + QUAD_ALIGN + QUAD_SLOTS }, + { Rusage | OUT, 3 + QUAD_ALIGN + QUAD_SLOTS }, + { Ptr, 4 + QUAD_ALIGN + QUAD_SLOTS } } }, { .name = "procctl", .ret_type = 1, .nargs = 4, - .args = { { Idtype, 0 }, { Int, 1 }, { Procctl, 2 }, { Ptr, 3 } } }, + .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN }, + { Procctl, 1 + QUAD_ALIGN + QUAD_SLOTS }, + { Ptr, 2 + QUAD_ALIGN + QUAD_SLOTS } } }, { .name = "sysarch", .ret_type = 1, .nargs = 2, .args = { { Sysarch, 0 }, { Ptr, 1 } } }, { .name = "_umtx_op", .ret_type = 1, .nargs = 5, .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 }, { Ptr, 4 } } }, - { .name = "thr_kill", .ret_type = 0, .nargs = 2, + { .name = "thr_kill", .ret_type = 1, .nargs = 2, .args = { { Long, 0 }, { Signal, 1 } } }, - { .name = "thr_self", .ret_type = 0, .nargs = 1, + { .name = "thr_self", .ret_type = 1, .nargs = 1, .args = { { Ptr, 0 } } }, { .name = 0 }, }; @@ -534,7 +525,9 @@ static struct xlat idtype_arg[] = { }; static struct xlat procctl_arg[] = { - X(PROC_SPROTECT) XEND + X(PROC_SPROTECT) X(PROC_REAP_ACQUIRE) X(PROC_REAP_RELEASE) + X(PROC_REAP_STATUS) X(PROC_REAP_GETPIDS) X(PROC_REAP_KILL) + X(PROC_TRACE_CTL) X(PROC_TRACE_STATUS) XEND }; static struct xlat umtx_ops[] = { @@ -809,7 +802,7 @@ print_kevent(FILE *fp, struct kevent *ke, int input) int ctrl, data; ctrl = ke->fflags & NOTE_FFCTRLMASK; - data = ke->fflags & NOTE_FFLAGSMASK; + data = ke->fflags & NOTE_FFLAGSMASK; if (input) { fputs(xlookup(kevent_user_ffctrl, ctrl), fp); if (ke->fflags & NOTE_TRIGGER) @@ -834,7 +827,7 @@ print_kevent(FILE *fp, struct kevent *ke, int input) * an array of all of the system call arguments. */ char * -print_arg(struct syscall_args *sc, unsigned long *args, long retval, +print_arg(struct syscall_args *sc, unsigned long *args, long *retval, struct trussinfo *trussinfo) { FILE *fp; @@ -843,7 +836,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, pid_t pid; fp = open_memstream(&tmp, &tmplen); - pid = trussinfo->pid; + pid = trussinfo->curthread->proc->pid; switch (sc->type & ARG_MASK) { case Hex: fprintf(fp, "0x%x", (int)args[sc->offset]); @@ -882,7 +875,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, int truncated = 0; if (sc->type & OUT) - len = retval; + len = retval[0]; else len = args[sc->offset + 1]; @@ -922,7 +915,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, } u; char *string; size_t len; - int first, i; + u_int first, i; /* * Only parse argv[] and environment arrays from exec calls @@ -935,7 +928,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, fprintf(fp, "0x%lx", args[sc->offset]); break; } - + /* * Read a page of pointers at a time. Punt if the top-level * pointer is not aligned. Note that the first read is of @@ -979,14 +972,27 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, } #ifdef __LP64__ case Quad: + fprintf(fp, "%ld", args[sc->offset]); + break; + case QuadHex: fprintf(fp, "0x%lx", args[sc->offset]); break; #else - case Quad: { + case Quad: + case QuadHex: { unsigned long long ll; - ll = *(unsigned long long *)(args + sc->offset); - fprintf(fp, "0x%llx", ll); +#if _BYTE_ORDER == _LITTLE_ENDIAN + ll = (unsigned long long)args[sc->offset + 1] << 32 | + args[sc->offset]; +#else + ll = (unsigned long long)args[sc->offset] << 32 | + args[sc->offset + 1]; +#endif + if ((sc->type & ARG_MASK) == Quad) + fprintf(fp, "%lld", ll); + else + fprintf(fp, "0x%llx", ll); break; } #endif @@ -996,9 +1002,9 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, case Readlinkres: { char *tmp2; - if (retval == -1) + if (retval[0] == -1) break; - tmp2 = get_string(pid, (void*)args[sc->offset], retval); + tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]); fprintf(fp, "\"%s\"", tmp2); free(tmp2); break; @@ -1283,12 +1289,12 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, fputs(xlookup_bits(rfork_flags, args[sc->offset]), fp); break; case Sockaddr: { - struct sockaddr_storage ss; char addr[64]; struct sockaddr_in *lsin; struct sockaddr_in6 *lsin6; struct sockaddr_un *sun; struct sockaddr *sa; + socklen_t len; u_char *q; if (args[sc->offset] == 0) { @@ -1296,70 +1302,71 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, break; } - /* yuck: get ss_len */ - if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, - sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) { - fprintf(fp, "0x%lx", args[sc->offset]); - break; - } - /* - * If ss_len is 0, then try to guess from the sockaddr type. - * AF_UNIX may be initialized incorrectly, so always frob - * it by using the "right" size. + * Extract the address length from the next argument. If + * this is an output sockaddr (OUT is set), then the + * next argument is a pointer to a socklen_t. Otherwise + * the next argument contains a socklen_t by value. */ - if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) { - switch (ss.ss_family) { - case AF_INET: - ss.ss_len = sizeof(*lsin); - break; - case AF_INET6: - ss.ss_len = sizeof(*lsin6); - break; - case AF_UNIX: - ss.ss_len = sizeof(*sun); - break; - default: + if (sc->type & OUT) { + if (get_struct(pid, (void *)args[sc->offset + 1], + &len, sizeof(len)) == -1) { + fprintf(fp, "0x%lx", args[sc->offset]); break; } + } else + len = args[sc->offset + 1]; + + /* If the length is too small, just bail. */ + if (len < sizeof(*sa)) { + fprintf(fp, "0x%lx", args[sc->offset]); + break; } - if (ss.ss_len != 0 && - get_struct(pid, (void *)args[sc->offset], (void *)&ss, - ss.ss_len) == -1) { + + sa = calloc(1, len); + if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) { + free(sa); fprintf(fp, "0x%lx", args[sc->offset]); break; } - switch (ss.ss_family) { + switch (sa->sa_family) { case AF_INET: - lsin = (struct sockaddr_in *)&ss; + if (len < sizeof(*lsin)) + goto sockaddr_short; + lsin = (struct sockaddr_in *)(void *)sa; inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr)); fprintf(fp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port)); break; case AF_INET6: - lsin6 = (struct sockaddr_in6 *)&ss; + if (len < sizeof(*lsin6)) + goto sockaddr_short; + lsin6 = (struct sockaddr_in6 *)(void *)sa; inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof(addr)); fprintf(fp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port)); break; case AF_UNIX: - sun = (struct sockaddr_un *)&ss; - fprintf(fp, "{ AF_UNIX \"%s\" }", sun->sun_path); + sun = (struct sockaddr_un *)sa; + fprintf(fp, "{ AF_UNIX \"%.*s\" }", + (int)(len - offsetof(struct sockaddr_un, sun_path)), + sun->sun_path); break; default: - sa = (struct sockaddr *)&ss; + sockaddr_short: fprintf(fp, "{ sa_len = %d, sa_family = %d, sa_data = {", (int)sa->sa_len, (int)sa->sa_family); for (q = (u_char *)sa->sa_data; - q < (u_char *)sa + sa->sa_len; q++) + q < (u_char *)sa + len; q++) fprintf(fp, "%s 0x%02x", q == (u_char *)sa->sa_data ? "" : ",", *q); fputs(" } }", fp); } + free(sa); break; } case Sigaction: { @@ -1395,8 +1402,8 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, if (sc->offset == 1) numevents = args[sc->offset+1]; - else if (sc->offset == 3 && retval != -1) - numevents = retval; + else if (sc->offset == 3 && retval[0] != -1) + numevents = retval[0]; if (numevents >= 0) { bytes = sizeof(struct kevent) * numevents; @@ -1515,6 +1522,21 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, case Sysarch: fputs(xlookup(sysarch_ops, args[sc->offset]), fp); break; + case PipeFds: + /* + * The pipe() system call in the kernel returns its + * two file descriptors via return values. However, + * the interface exposed by libc is that pipe() + * accepts a pointer to an array of descriptors. + * Format the output to match the libc API by printing + * the returned file descriptors as a fake argument. + * + * Overwrite the first retval to signal a successful + * return as well. + */ + fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]); + retval[0] = 0; + break; default: errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); } @@ -1536,7 +1558,8 @@ print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, len = 0; if (trussinfo->flags & FOLLOWFORKS) - len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); + len += fprintf(trussinfo->outfile, "%5d: ", + trussinfo->curthread->proc->pid); if (name != NULL && (strcmp(name, "execve") == 0 || strcmp(name, "exit") == 0)) { @@ -1575,7 +1598,7 @@ print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, void print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, - char **s_args, int errorp, long retval, struct syscall *sc) + char **s_args, int errorp, long *retval, struct syscall *sc) { struct timespec timediff; @@ -1595,17 +1618,24 @@ print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, print_syscall(trussinfo, name, nargs, s_args); fflush(trussinfo->outfile); if (errorp) - fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, - strerror(retval)); - else { - /* - * Because pipe(2) has a special assembly glue to provide the - * libc API, we have to adjust retval. - */ - if (name != NULL && strcmp(name, "pipe") == 0) - retval = 0; - fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); + fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0], + strerror(retval[0])); +#ifndef __LP64__ + else if (sc != NULL && sc->ret_type == 2) { + off_t off; + +#if _BYTE_ORDER == _LITTLE_ENDIAN + off = (off_t)retval[1] << 32 | retval[0]; +#else + off = (off_t)retval[0] << 32 | retval[1]; +#endif + fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off, + (intmax_t)off); } +#endif + else + fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0], + retval[0]); } void diff --git a/usr.bin/truss/truss.h b/usr.bin/truss/truss.h index dcc86a57136d..0f58bd8583b9 100644 --- a/usr.bin/truss/truss.h +++ b/usr.bin/truss/truss.h @@ -25,6 +25,7 @@ * $FreeBSD$ */ +#include <sys/linker_set.h> #include <sys/queue.h> #define FOLLOWFORKS 0x00000001 @@ -35,23 +36,63 @@ #define EXECVEENVS 0x00000020 #define COUNTONLY 0x00000040 +struct procinfo; +struct trussinfo; + +struct procabi { + const char *type; + const char **syscallnames; + int nsyscalls; + int (*fetch_args)(struct trussinfo *, u_int); + int (*fetch_retval)(struct trussinfo *, long *, int *); +}; + +#define PROCABI(abi) DATA_SET(procabi, abi) + +/* + * This is confusingly named. It holds per-thread state about the + * currently executing system call. syscalls.h defines a struct + * syscall that holds metadata used to format system call arguments. + * + * NB: args[] stores the raw argument values (e.g. from registers) + * passed to the system call. s_args[] stores a string representation + * of a system call's arguments. These do not necessarily map one to + * one. A system call description may omit individual arguments + * (padding) or combine adjacent arguments (e.g. when passing an off_t + * argument on a 32-bit system). The nargs member contains the count + * of valid pointers in s_args[], not args[]. + */ +struct current_syscall { + struct syscall *sc; + const char *name; + int number; + unsigned long args[10]; + unsigned int nargs; + char *s_args[10]; /* the printable arguments */ +}; + struct threadinfo { SLIST_ENTRY(threadinfo) entries; + struct procinfo *proc; lwpid_t tid; int in_syscall; - int in_fork; - void *fsc; + struct current_syscall cs; struct timespec before; struct timespec after; }; +struct procinfo { + LIST_ENTRY(procinfo) entries; + pid_t pid; + struct procabi *abi; + + SLIST_HEAD(, threadinfo) threadlist; +}; + struct trussinfo { - pid_t pid; int flags; - int pr_why; - int pr_data; int strsize; FILE *outfile; @@ -59,7 +100,7 @@ struct trussinfo struct threadinfo *curthread; - SLIST_HEAD(, threadinfo) threadlist; + LIST_HEAD(, procinfo) proclist; }; #define timespecsubt(tvp, uvp, vvp) \ @@ -81,11 +122,3 @@ struct trussinfo (vvp)->tv_nsec -= 1000000000; \ } \ } while (0) - -#define S_NONE 0 -#define S_SCE 1 -#define S_SCX 2 -#define S_EXIT 3 -#define S_SIG 4 -#define S_EXEC 5 -#define S_DETACHED 6 diff --git a/usr.bin/usbhidaction/usbhidaction.c b/usr.bin/usbhidaction/usbhidaction.c index 876dbca71daf..49cf0af2a8f2 100644 --- a/usr.bin/usbhidaction/usbhidaction.c +++ b/usr.bin/usbhidaction/usbhidaction.c @@ -166,17 +166,15 @@ main(int argc, char **argv) if (demon) { fp = open(pidfile, O_WRONLY|O_CREAT, S_IRUSR|S_IRGRP|S_IROTH); - if (fp >= 0) { - sz1 = snprintf(buf, sizeof buf, "%ld\n", - (long)getpid()); - if (sz1 > sizeof buf) - sz1 = sizeof buf; - write(fp, buf, sz1); - close(fp); - } else + if (fp < 0) err(1, "%s", pidfile); if (daemon(0, 0) < 0) err(1, "daemon()"); + snprintf(buf, sizeof(buf), "%ld\n", (long)getpid()); + sz1 = strlen(buf); + if (write(fp, buf, sz1) < 0) + err(1, "%s", pidfile); + close(fp); isdemon = 1; } diff --git a/usr.bin/vgrind/RETEST/Makefile.depend b/usr.bin/vgrind/RETEST/Makefile.depend index f52ca95b0a47..79eb58b4a779 100644 --- a/usr.bin/vgrind/RETEST/Makefile.depend +++ b/usr.bin/vgrind/RETEST/Makefile.depend @@ -1,10 +1,6 @@ # $FreeBSD$ # Autogenerated - do NOT edit! -DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,} - -DEP_MACHINE := ${.PARSEFILE:E} - DIRDEPS = \ gnu/lib/libgcc \ include \ diff --git a/usr.bin/xinstall/install.1 b/usr.bin/xinstall/install.1 index 60d48c6c9364..a0afebe14caa 100644 --- a/usr.bin/xinstall/install.1 +++ b/usr.bin/xinstall/install.1 @@ -9,7 +9,7 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 4. Neither the name of the University nor the names of its contributors +.\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c index 33e818a907ee..30cc6c7a7768 100644 --- a/usr.bin/xinstall/xinstall.c +++ b/usr.bin/xinstall/xinstall.c @@ -11,7 +11,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/usr.bin/yacc/tests/Makefile b/usr.bin/yacc/tests/Makefile index c8125a6f39c3..2e157ec61319 100644 --- a/usr.bin/yacc/tests/Makefile +++ b/usr.bin/yacc/tests/Makefile @@ -17,6 +17,8 @@ TEST_METADATA.yacc_tests+= required_user="unprivileged" SCRIPTS= run_test SCRIPTSDIR= ${TESTSDIR} +CLEANFILES= run_test + FILESGROUPS= FILES FILEStest FILEStest_yacc FILEStestDIR= ${TESTSDIR} |
