diff options
Diffstat (limited to 'usr.bin')
70 files changed, 1527 insertions, 2940 deletions
diff --git a/usr.bin/bmake/Makefile.inc b/usr.bin/bmake/Makefile.inc index ad7faad29f963..4fa3cf7b5e1d4 100644 --- a/usr.bin/bmake/Makefile.inc +++ b/usr.bin/bmake/Makefile.inc @@ -7,7 +7,9 @@ .export SRCTOP .endif +.if exists(${.CURDIR}/tests) PROG= make +.endif .if !defined(MK_SHARED_TOOLCHAIN) || ${MK_SHARED_TOOLCHAIN} == "no" NO_SHARED?= YES diff --git a/usr.bin/ctlstat/ctlstat.8 b/usr.bin/ctlstat/ctlstat.8 index 500ffb036e9f8..ebf9f5c50502c 100644 --- a/usr.bin/ctlstat/ctlstat.8 +++ b/usr.bin/ctlstat/ctlstat.8 @@ -34,7 +34,7 @@ .\" $Id: //depot/users/kenm/FreeBSD-test2/usr.bin/ctlstat/ctlstat.8#2 $ .\" $FreeBSD$ .\" -.Dd May 22, 2015 +.Dd September 21, 2015 .Dt CTLSTAT 8 .Os .Sh NAME @@ -50,6 +50,7 @@ .Op Fl j .Op Fl l Ar lun .Op Fl n Ar numdevs +.Op Fl p Ar port .Op Fl w Ar wait .Sh DESCRIPTION The @@ -64,7 +65,7 @@ The options are as follows: .Bl -tag -width 10n .It Fl t Total mode. -This displays separate columns with the total CTL read and write output, +This displays separate columns with the total read and write output, and a combined total column that also includes non I/O operations. .It Fl c Ar count Display statistics this many times. @@ -74,23 +75,20 @@ Disable CPU statistics display. Display DMA operation time (latency) instead of overall I/O time (latency). .It Fl D Text dump mode. -Dump all available statistics every 30 seconds in a text format suitable -for parsing. +Dump statistics every 30 seconds in a text format suitable for parsing. No statistics are computed in this mode, only raw numbers are displayed. .It Fl h Suppress display of the header. .It Fl j JSON dump mode. -Dump all available statistics every 30 seconds in JavaScript Object -Notation (JSON) format. +Dump statistics every 30 seconds in JavaScript Object Notation (JSON) format. No statistics are computed in this mode, only raw numbers are displayed. .It Fl l Ar lun Request statistics for the specified LUN. -This option is incompatible with total -.Fl ( t ) -mode. .It Fl n Ar numdevs Display statistics for this many devices. +.It Fl p Ar port +Request statistics for the specified port. .It Fl w Ar wait Wait this many seconds in between displays. If this option is not specified, diff --git a/usr.bin/ctlstat/ctlstat.c b/usr.bin/ctlstat/ctlstat.c index f12dd43723592..358758652aa01 100644 --- a/usr.bin/ctlstat/ctlstat.c +++ b/usr.bin/ctlstat/ctlstat.c @@ -78,7 +78,7 @@ __FBSDID("$FreeBSD$"); */ #define CTL_STAT_LUN_BITS 1024L -static const char *ctlstat_opts = "Cc:Ddhjl:n:tw:"; +static const char *ctlstat_opts = "Cc:Ddhjl:n:p:tw:"; static const char *ctlstat_usage = "Usage: ctlstat [-CDdjht] [-l lunnum]" "[-c count] [-n numdevs] [-w wait]\n"; @@ -102,12 +102,16 @@ typedef enum { #define CTLSTAT_FLAG_TOTALS (1 << 3) #define CTLSTAT_FLAG_DMA_TIME (1 << 4) #define CTLSTAT_FLAG_LUN_TIME_VALID (1 << 5) +#define CTLSTAT_FLAG_LUN_MASK (1 << 6) +#define CTLSTAT_FLAG_PORT_MASK (1 << 7) #define F_CPU(ctx) ((ctx)->flags & CTLSTAT_FLAG_CPU) #define F_HDR(ctx) ((ctx)->flags & CTLSTAT_FLAG_HEADER) #define F_FIRST(ctx) ((ctx)->flags & CTLSTAT_FLAG_FIRST_RUN) #define F_TOTALS(ctx) ((ctx)->flags & CTLSTAT_FLAG_TOTALS) #define F_DMA(ctx) ((ctx)->flags & CTLSTAT_FLAG_DMA_TIME) #define F_LUNVAL(ctx) ((ctx)->flags & CTLSTAT_FLAG_LUN_TIME_VALID) +#define F_LUNMASK(ctx) ((ctx)->flags & CTLSTAT_FLAG_LUN_MASK) +#define F_PORTMASK(ctx) ((ctx)->flags & CTLSTAT_FLAG_PORT_MASK) struct ctlstat_context { ctlstat_mode_types mode; @@ -120,6 +124,7 @@ struct ctlstat_context { uint64_t cur_total_jiffies, prev_total_jiffies; uint64_t cur_idle, prev_idle; bitstr_t bit_decl(lun_mask, CTL_STAT_LUN_BITS); + bitstr_t bit_decl(port_mask, CTL_MAX_PORTS); int num_luns; int numdevs; int header_interval; @@ -133,7 +138,8 @@ static void usage(int error); static int getstats(int fd, int *num_luns, struct ctl_lun_io_stats **xlun_stats, struct timespec *cur_time, int *lun_time_valid); static int getcpu(struct ctl_cpu_stats *cpu_stats); -static void compute_stats(struct ctl_lun_io_stats *cur_stats, +static void compute_stats(struct ctlstat_context *ctx, + struct ctl_lun_io_stats *cur_stats, struct ctl_lun_io_stats *prev_stats, long double etime, long double *mbsec, long double *kb_per_transfer, @@ -234,7 +240,7 @@ getcpu(struct ctl_cpu_stats *cpu_stats) } static void -compute_stats(struct ctl_lun_io_stats *cur_stats, +compute_stats(struct ctlstat_context *ctx, struct ctl_lun_io_stats *cur_stats, struct ctl_lun_io_stats *prev_stats, long double etime, long double *mbsec, long double *kb_per_transfer, long double *transfers_per_second, long double *ms_per_transfer, @@ -251,6 +257,9 @@ compute_stats(struct ctl_lun_io_stats *cur_stats, bzero(&total_time_ts, sizeof(total_time_ts)); bzero(&total_dma_ts, sizeof(total_dma_ts)); for (port = 0; port < CTL_MAX_PORTS; port++) { + if (F_PORTMASK(ctx) && + bit_test(ctx->port_mask, port) == 0) + continue; for (i = 0; i < CTL_STATS_NUM_TYPES; i++) { total_bytes += cur_stats->ports[port].bytes[i]; total_operations += @@ -326,8 +335,8 @@ compute_stats(struct ctl_lun_io_stats *cur_stats, */ #define PRINT_BINTIME(prefix, bt) \ - printf("%s %jd s %ju frac\n", prefix, (intmax_t)(bt).sec, \ - (uintmax_t)(bt).frac) + printf("%s %jd.%06ju\n", prefix, (intmax_t)(bt).sec, \ + (uintmax_t)(((bt).frac >> 32) * 1000000 >> 32)) static const char *iotypes[] = {"NO IO", "READ", "WRITE"}; static void @@ -336,8 +345,13 @@ ctlstat_dump(struct ctlstat_context *ctx) { struct ctl_lun_io_stats *stats = ctx->cur_lun_stats; for (lun = 0; lun < ctx->num_luns;lun++) { + if (F_LUNMASK(ctx) && bit_test(ctx->lun_mask, lun) == 0) + continue; printf("lun %d\n", lun); for (port = 0; port < CTL_MAX_PORTS; port++) { + if (F_PORTMASK(ctx) && + bit_test(ctx->port_mask, port) == 0) + continue; printf(" port %d\n", stats[lun].ports[port].targ_port); for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; @@ -360,9 +374,8 @@ ctlstat_dump(struct ctlstat_context *ctx) { } #define JSON_BINTIME(prefix, bt) \ - printf("\"%s\":{\"sec\":%jd,\"frac\":%ju},", \ - prefix, (intmax_t)(bt).sec, (uintmax_t)(bt).frac) - + printf("\"%s\":%jd.%06ju,", prefix, (intmax_t)(bt).sec, \ + (uintmax_t)(((bt).frac >> 32) * 1000000 >> 32)) static void ctlstat_json(struct ctlstat_context *ctx) { int iotype, lun, port; @@ -370,8 +383,13 @@ ctlstat_json(struct ctlstat_context *ctx) { printf("{\"luns\":["); for (lun = 0; lun < ctx->num_luns; lun++) { + if (F_LUNMASK(ctx) && bit_test(ctx->lun_mask, lun) == 0) + continue; printf("{\"ports\":["); for (port = 0; port < CTL_MAX_PORTS;port++) { + if (F_PORTMASK(ctx) && + bit_test(ctx->port_mask, port) == 0) + continue; printf("{\"num\":%d,\"io\":[", stats[lun].ports[port].targ_port); for (iotype = 0; iotype < CTL_STATS_NUM_TYPES; @@ -442,17 +460,16 @@ ctlstat_standard(struct ctlstat_context *ctx) { hdr_devs = 0; + if (F_CPU(ctx)) + fprintf(stdout, " CPU"); if (F_TOTALS(ctx)) { - fprintf(stdout, "%s System Read %s" - "System Write %sSystem Total%s\n", - (F_LUNVAL(ctx) != 0) ? " " : "", - (F_LUNVAL(ctx) != 0) ? " " : "", - (F_LUNVAL(ctx) != 0) ? " " : "", - (F_CPU(ctx)) ? " CPU" : ""); + fprintf(stdout, "%s Read %s" + " Write %s Total\n", + (F_LUNVAL(ctx) != 0) ? " " : "", + (F_LUNVAL(ctx) != 0) ? " " : "", + (F_LUNVAL(ctx) != 0) ? " " : ""); hdr_devs = 3; } else { - if (F_CPU(ctx)) - fprintf(stdout, " CPU "); for (i = 0; i < min(CTL_STAT_LUN_BITS, ctx->num_luns); i++) { int lun; @@ -465,7 +482,8 @@ ctlstat_standard(struct ctlstat_context *ctx) { lun = (int)ctx->cur_lun_stats[i ].lun_number; - if (bit_test(ctx->lun_mask, lun) == 0) + if (F_LUNMASK(ctx) && + bit_test(ctx->lun_mask, lun) == 0) continue; fprintf(stdout, "%15.6s%d %s", "lun", lun, @@ -474,17 +492,19 @@ ctlstat_standard(struct ctlstat_context *ctx) { } fprintf(stdout, "\n"); } + if (F_CPU(ctx)) + fprintf(stdout, " "); for (i = 0; i < hdr_devs; i++) - fprintf(stdout, "%s %sKB/t %s MB/s ", - ((F_CPU(ctx) != 0) && (i == 0) && - (F_TOTALS(ctx) == 0)) ? " " : "", - (F_LUNVAL(ctx) != 0) ? " ms " : "", + fprintf(stdout, "%s KB/t %s MB/s", + (F_LUNVAL(ctx) != 0) ? " ms" : "", (F_DMA(ctx) == 0) ? "tps" : "dps"); fprintf(stdout, "\n"); ctx->header_interval = 20; } } + if (F_CPU(ctx)) + fprintf(stdout, "%3.0Lf%%", cpu_percentage); if (F_TOTALS(ctx) != 0) { long double mbsec[3]; long double kb_per_transfer[3]; @@ -516,7 +536,13 @@ ctlstat_standard(struct ctlstat_context *ctx) { &ctx->cur_lun_stats[i].ports[p].dma_time[j]) for (i = 0; i < ctx->num_luns; i++) { + if (F_LUNMASK(ctx) && bit_test(ctx->lun_mask, + (int)ctx->cur_lun_stats[i].lun_number) == 0) + continue; for (port = 0; port < CTL_MAX_PORTS; port++) { + if (F_PORTMASK(ctx) && + bit_test(ctx->port_mask, port) == 0) + continue; for (j = 0; j < CTL_STATS_NUM_TYPES; j++) { ADD_STATS_BYTES(2, port, i, j); ADD_STATS_OPERATIONS(2, port, i, j); @@ -541,29 +567,24 @@ ctlstat_standard(struct ctlstat_context *ctx) { } for (i = 0; i < 3; i++) { - compute_stats(&ctx->cur_total_stats[i], + compute_stats(ctx, &ctx->cur_total_stats[i], F_FIRST(ctx) ? NULL : &ctx->prev_total_stats[i], etime, &mbsec[i], &kb_per_transfer[i], &transfers_per_sec[i], &ms_per_transfer[i], &ms_per_dma[i], &dmas_per_sec[i]); if (F_DMA(ctx) != 0) - fprintf(stdout, " %2.2Lf", + fprintf(stdout, " %5.1Lf", ms_per_dma[i]); else if (F_LUNVAL(ctx) != 0) - fprintf(stdout, " %2.2Lf", + fprintf(stdout, " %5.1Lf", ms_per_transfer[i]); - fprintf(stdout, " %5.2Lf %3.0Lf %5.2Lf ", + fprintf(stdout, " %4.0Lf %5.0Lf %4.0Lf", kb_per_transfer[i], (F_DMA(ctx) == 0) ? transfers_per_sec[i] : dmas_per_sec[i], mbsec[i]); } - if (F_CPU(ctx)) - fprintf(stdout, " %5.1Lf%%", cpu_percentage); } else { - if (F_CPU(ctx)) - fprintf(stdout, "%5.1Lf%% ", cpu_percentage); - for (i = 0; i < min(CTL_STAT_LUN_BITS, ctx->num_luns); i++) { long double mbsec, kb_per_transfer; long double transfers_per_sec; @@ -571,21 +592,21 @@ ctlstat_standard(struct ctlstat_context *ctx) { long double ms_per_dma; long double dmas_per_sec; - if (bit_test(ctx->lun_mask, + if (F_LUNMASK(ctx) && bit_test(ctx->lun_mask, (int)ctx->cur_lun_stats[i].lun_number) == 0) continue; - compute_stats(&ctx->cur_lun_stats[i], F_FIRST(ctx) ? - NULL : &ctx->prev_lun_stats[i], etime, - &mbsec, &kb_per_transfer, - &transfers_per_sec, &ms_per_transfer, - &ms_per_dma, &dmas_per_sec); + compute_stats(ctx, &ctx->cur_lun_stats[i], + F_FIRST(ctx) ? NULL : &ctx->prev_lun_stats[i], + etime, &mbsec, &kb_per_transfer, + &transfers_per_sec, &ms_per_transfer, + &ms_per_dma, &dmas_per_sec); if (F_DMA(ctx)) - fprintf(stdout, " %2.2Lf", + fprintf(stdout, " %5.1Lf", ms_per_dma); else if (F_LUNVAL(ctx) != 0) - fprintf(stdout, " %2.2Lf", + fprintf(stdout, " %5.1Lf", ms_per_transfer); - fprintf(stdout, " %5.2Lf %3.0Lf %5.2Lf ", + fprintf(stdout, " %4.0Lf %5.0Lf %4.0Lf", kb_per_transfer, (F_DMA(ctx) == 0) ? transfers_per_sec : dmas_per_sec, mbsec); } @@ -597,7 +618,6 @@ main(int argc, char **argv) { int c; int count, waittime; - int set_lun; int fd, retval; struct ctlstat_context ctx; @@ -641,20 +661,30 @@ main(int argc, char **argv) if (cur_lun > CTL_STAT_LUN_BITS) errx(1, "Invalid LUN number %d", cur_lun); - bit_ffs(ctx.lun_mask, CTL_STAT_LUN_BITS, &set_lun); - if (set_lun == -1) + if (!F_LUNMASK(&ctx)) ctx.numdevs = 1; else ctx.numdevs++; bit_set(ctx.lun_mask, cur_lun); + ctx.flags |= CTLSTAT_FLAG_LUN_MASK; break; } case 'n': ctx.numdevs = atoi(optarg); break; + case 'p': { + int cur_port; + + cur_port = atoi(optarg); + if (cur_port > CTL_MAX_PORTS) + errx(1, "Invalid LUN number %d", cur_port); + + bit_set(ctx.port_mask, cur_port); + ctx.flags |= CTLSTAT_FLAG_PORT_MASK; + break; + } case 't': ctx.flags |= CTLSTAT_FLAG_TOTALS; - ctx.numdevs = 3; break; case 'w': waittime = atoi(optarg); @@ -667,13 +697,7 @@ main(int argc, char **argv) } } - bit_ffs(ctx.lun_mask, CTL_STAT_LUN_BITS, &set_lun); - - if ((F_TOTALS(&ctx)) - && (set_lun != -1)) { - errx(1, "Total Mode (-t) is incompatible with individual " - "LUN mode (-l)"); - } else if (set_lun == -1) { + if (!F_TOTALS(&ctx) && !F_LUNMASK(&ctx)) { /* * Note that this just selects the first N LUNs to display, * but at this point we have no knoweledge of which LUN @@ -682,6 +706,7 @@ main(int argc, char **argv) */ bit_nset(ctx.lun_mask, 0, min(ctx.numdevs - 1, CTL_STAT_LUN_BITS - 1)); + ctx.flags |= CTLSTAT_FLAG_LUN_MASK; } if ((fd = open(CTL_DEFAULT_DEV, O_RDWR)) == -1) diff --git a/usr.bin/elfdump/elfdump.c b/usr.bin/elfdump/elfdump.c index 2147fcb3179bc..908c69964f040 100644 --- a/usr.bin/elfdump/elfdump.c +++ b/usr.bin/elfdump/elfdump.c @@ -296,7 +296,7 @@ static const char *ei_data[] = { }; static const char *ei_abis[256] = { - "ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", + "ELFOSABI_NONE", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", "ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD", @@ -379,7 +379,9 @@ sh_types(uint64_t machine, uint64_t sht) { break; case EM_MIPS: switch (sht) { + case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO"; case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS"; + case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS"; } break; } diff --git a/usr.bin/lex/Makefile.depend b/usr.bin/lex/Makefile.depend index 738376bb43ef0..b5b80431a2a40 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/man/man.sh b/usr.bin/man/man.sh index e125e5be3f855..094ea11c10a34 100755 --- a/usr.bin/man/man.sh +++ b/usr.bin/man/man.sh @@ -315,7 +315,11 @@ man_display_page() { mandoc_args="-O width=${use_width}" fi testline="mandoc -Tlint -Wunsupp 2>/dev/null" - pipeline="mandoc $mandoc_args | $MANPAGER" + if [ -n "$tflag" ]; then + pipeline="mandoc -Tps $mandoc_args" + else + pipeline="mandoc $mandoc_args | $MANPAGER" + fi if ! eval "$cattool $manpage | $testline" ;then if which -s groff; then diff --git a/usr.bin/mkcsmapper_static/Makefile.depend b/usr.bin/mkcsmapper_static/Makefile.depend index 911a48d59cd37..ffee33f34c2ad 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/netstat/Makefile.depend b/usr.bin/netstat/Makefile.depend index fb0bf8cbc34a2..76ce70824fea4 100644 --- a/usr.bin/netstat/Makefile.depend +++ b/usr.bin/netstat/Makefile.depend @@ -21,4 +21,14 @@ DIRDEPS = \ .if ${DEP_RELDIR} == ${_DEP_RELDIR} # local dependencies - needed for -jN in clean tree +main.o: nl_defs.h +main.po: nl_defs.h +mroute.o: nl_defs.h +mroute.po: nl_defs.h +netisr.o: nl_defs.h +netisr.po: nl_defs.h +nl_symbols.o: nl_symbols.c +nl_symbols.po: nl_symbols.c +route.o: nl_defs.h +route.po: nl_defs.h .endif diff --git a/usr.bin/numactl/Makefile.depend b/usr.bin/numactl/Makefile.depend new file mode 100644 index 0000000000000..3646e2e2b1afa --- /dev/null +++ b/usr.bin/numactl/Makefile.depend @@ -0,0 +1,18 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + gnu/lib/libgcc \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.bin/pamtest/Makefile.depend b/usr.bin/pamtest/Makefile.depend index 80d4de249f9e9..916227df0bfda 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/procstat/Makefile.depend b/usr.bin/procstat/Makefile.depend index 588a39431ddcf..5260cce40b480 100644 --- a/usr.bin/procstat/Makefile.depend +++ b/usr.bin/procstat/Makefile.depend @@ -13,7 +13,9 @@ DIRDEPS = \ lib/libelf \ lib/libkvm \ lib/libprocstat \ + lib/libsbuf \ lib/libutil \ + lib/libxo \ .include <dirdeps.mk> diff --git a/usr.bin/rctl/rctl.8 b/usr.bin/rctl/rctl.8 index bebf4fd269c6a..9fc1c1ce79c1b 100644 --- a/usr.bin/rctl/rctl.8 +++ b/usr.bin/rctl/rctl.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 11, 2014 +.Dd September 14, 2015 .Dt RCTL 8 .Os .Sh NAME @@ -193,7 +193,7 @@ resource would be .It Sy openfiles Ta "file descriptor table size" .It Sy vmemoryuse Ta "address space limit, in bytes" .It Sy pseudoterminals Ta "number of PTYs" -.It Sy swapuse Ta "swap usage, in bytes" +.It Sy swapuse Ta "swap space that may be reserved or used, in bytes" .It Sy nthr Ta "number of threads" .It Sy msgqqueued Ta "number of queued SysV messages" .It Sy msgqsize Ta "SysV message queue size, in bytes" diff --git a/usr.bin/setchannel/Makefile.depend b/usr.bin/setchannel/Makefile.depend index f52ca95b0a473..79eb58b4a7798 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 a1b4494b8d920..989cc649e995f 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 44421170457e3..1d2ae21d56c69 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 402745dff3520..bbe68e03366ed 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 9caf2d1afc041..ba7abb3604436 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 b8e3639fd56bc..044c8f776b349 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 ccd19e5321dae..18be76b0cb6f4 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 35add0cbdea4e..b38b34e6ba94d 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 ccd19e5321dae..18be76b0cb6f4 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 ccd19e5321dae..18be76b0cb6f4 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 ccd19e5321dae..18be76b0cb6f4 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 ccd19e5321dae..18be76b0cb6f4 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 ccd19e5321dae..18be76b0cb6f4 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 ccd19e5321dae..18be76b0cb6f4 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 9caf2d1afc041..ba7abb3604436 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 ccd19e5321dae..18be76b0cb6f4 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 ccd19e5321dae..18be76b0cb6f4 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 365567e26755a..10c07481db38b 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 ccd19e5321dae..18be76b0cb6f4 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 ccbe2336599b8..da1efbd4fbadb 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 6a83703854b6e..ae47f0bd1ce41 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 6a83703854b6e..ae47f0bd1ce41 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 327a76ef69980..d0f58660bc56f 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 eb9e68bb0f20e..798e4f3f6cde0 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 ccbe2336599b8..da1efbd4fbadb 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 978f241cbae59..550cd652de064 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 978f241cbae59..550cd652de064 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 ca6c01c50b7d7..12d0cc3305d57 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 bb279d56e8c83..18fd1b1c0bb75 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 c9c9e7d96e48c..273dd3214a07b 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 17fffc1334892..2ac5a51abe7fc 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 fd938307df2ee..5e509ca08b66c 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 6b7bcb9bc9784..af996bb8dc248 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 1b4322c1b307a..ebd409e217ae0 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 0000000000000..2a6606f9d8fb3 --- /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/tip/tip/Makefile b/usr.bin/tip/tip/Makefile index b0fd1f8a105bd..a8ed43f7c579c 100644 --- a/usr.bin/tip/tip/Makefile +++ b/usr.bin/tip/tip/Makefile @@ -53,5 +53,5 @@ acutab.o log.o remote.o: Makefile # is no cu(1) with the schg-bit set. beforeinstall: .if exists(${DESTDIR}${BINDIR}/cu) - -@chflags noschg ${DESTDIR}${BINDIR}/cu + -chflags noschg ${DESTDIR}${BINDIR}/cu .endif diff --git a/usr.bin/truss/amd64-fbsd.c b/usr.bin/truss/amd64-fbsd.c index eeea8db962057..ade9322c31e94 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 40aa152f81cc7..84a4b6ba8a7ce 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 b2d0d040406f2..4f64af343fbb7 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 8dc4d5bef414b..4b8222a534330 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 820f4f0b8e161..708d055cf2c37 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 ef326f02020f7..029815ec711d7 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 6bd930955177d..fa57af2b34844 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 84ae3139cc1bf..55fdedad42cf4 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 d45241ac3be92..d488b7e7c0306 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 cdbd1331f47bf..4a11459e7860b 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 1f50429515a9e..5ca5c22dc2cd6 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 d6e430012e253..4452f9f47c7f3 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 4e64c70271128..c8c1e8c27c073 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 6f4d9a3807ea1..63b2299e649df 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 }; #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 fac47f4568a75..f46a2e17e1be9 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,23 +38,20 @@ 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> @@ -95,26 +90,16 @@ 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, @@ -125,7 +110,7 @@ static struct syscall syscalls[] = { { 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 } } }, { .name = "linux_mkdir", .ret_type = 1, .nargs = 2, @@ -145,49 +130,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 +235,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 +264,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,7 +317,7 @@ 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, @@ -368,9 +353,9 @@ static struct syscall syscalls[] = { { .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 +519,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 +796,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 +821,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 +830,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 +869,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 +909,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 +922,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 @@ -985,7 +972,13 @@ print_arg(struct syscall_args *sc, unsigned long *args, long retval, case Quad: { unsigned long long ll; - ll = *(unsigned long long *)(args + sc->offset); +#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 fprintf(fp, "0x%llx", ll); break; } @@ -996,9 +989,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; @@ -1395,8 +1388,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 +1508,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 +1544,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 +1584,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 +1604,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 dcc86a57136d9..0f58bd8583b91 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 876dbca71daf1..49cf0af2a8f2f 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 f52ca95b0a473..79eb58b4a7798 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/wc/Makefile.depend b/usr.bin/wc/Makefile.depend index 9b71a677693fe..137678c21e469 100644 --- a/usr.bin/wc/Makefile.depend +++ b/usr.bin/wc/Makefile.depend @@ -9,6 +9,7 @@ DIRDEPS = \ lib/${CSU_DIR} \ lib/libc \ lib/libcompiler_rt \ + lib/libutil \ lib/libxo \ diff --git a/usr.bin/xinstall/install.1 b/usr.bin/xinstall/install.1 index 60d48c6c9364e..a0afebe14caa1 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 33e818a907eeb..30cc6c7a77682 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 c8125a6f39c34..2e157ec61319d 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} |
