summaryrefslogtreecommitdiff
path: root/usr/src/cmd/truss/listopts.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/truss/listopts.c')
-rw-r--r--usr/src/cmd/truss/listopts.c661
1 files changed, 661 insertions, 0 deletions
diff --git a/usr/src/cmd/truss/listopts.c b/usr/src/cmd/truss/listopts.c
new file mode 100644
index 0000000..17d9a50
--- /dev/null
+++ b/usr/src/cmd/truss/listopts.c
@@ -0,0 +1,661 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <libproc.h>
+#include "ramdata.h"
+#include "systable.h"
+#include "proto.h"
+
+/* XXX A bug in the <string.h> header file requires this */
+extern char *strtok_r(char *s1, const char *s2, char **lasts);
+
+/*
+ * option procesing ---
+ * Routines for scanning syscall, signal, fault
+ * and file descriptor lists.
+ */
+
+/*
+ * Function prototypes for static routines in this module.
+ */
+void upcase(char *);
+
+const char white[] = " \t\n"; /* white space characters */
+const char sepr[] = " ,\t\n"; /* list separator characters */
+const char csepr[] = " :,\t\n"; /* same, with ':' added */
+
+/*
+ * Scan list of syscall names.
+ * Return 0 on success, != 0 on any failure.
+ */
+int
+syslist(char *str, /* string of syscall names */
+ sysset_t *setp, /* syscall set */
+ int *fp) /* first-time flag */
+{
+ char *name;
+ int exclude = FALSE;
+ int rc = 0;
+ char *lasts;
+
+ name = strtok_r(str, sepr, &lasts);
+
+ if (name != NULL && *name == '!') { /* exclude from set */
+ exclude = TRUE;
+ if (*++name == '\0')
+ name = strtok_r(NULL, sepr, &lasts);
+ } else if (!*fp) { /* first time, clear the set */
+ premptyset(setp);
+ *fp = TRUE;
+ }
+
+ for (; name; name = strtok_r(NULL, sepr, &lasts)) {
+ int sys;
+ int sysx;
+ int sysxx;
+ int sys64;
+ char *next;
+
+ if (*name == '!') { /* exclude remainder from set */
+ exclude = TRUE;
+ while (*++name == '!')
+ /* empty */;
+ if (*name == '\0')
+ continue;
+ }
+
+ sys = strtol(name, &next, 0);
+ sysx = sysxx = sys64 = 0;
+ if (sys < 0 || sys > PRMAXSYS || *next != '\0')
+ sys = 0;
+ if (sys == 0) {
+ const struct systable *stp = systable;
+ for (; sys == 0 && stp->nargs >= 0; stp++)
+ if (stp->name && strcmp(stp->name, name) == 0)
+ sys = stp-systable;
+ }
+ if (sys == 0) {
+ const struct sysalias *sap = sysalias;
+ for (; sys == 0 && sap->name; sap++)
+ if (strcmp(sap->name, name) == 0)
+ sys = sap->number;
+ }
+ if (sys > 0 && sys <= PRMAXSYS) {
+ switch (sys) {
+ case SYS_fstatat: /* set both if either */
+ case SYS_fstatat64:
+ sys = SYS_fstatat;
+ sys64 = SYS_fstatat64;
+ goto def;
+
+ case SYS_stat: /* set all if either */
+ case SYS_stat64:
+ sys = SYS_stat;
+ sys64 = SYS_stat64;
+ sysx = SYS_fstatat;
+ sysxx = SYS_fstatat64;
+ goto def;
+
+ case SYS_lstat: /* set all if either */
+ case SYS_lstat64:
+ sys = SYS_lstat;
+ sys64 = SYS_lstat64;
+ sysx = SYS_fstatat;
+ sysxx = SYS_fstatat64;
+ goto def;
+
+ case SYS_fstat: /* set all if either */
+ case SYS_fstat64:
+ sys = SYS_fstat;
+ sys64 = SYS_fstat64;
+ sysx = SYS_fstatat;
+ sysxx = SYS_fstatat64;
+ goto def;
+
+ case SYS_getdents: /* set both if either */
+ case SYS_getdents64:
+ sys = SYS_getdents;
+ sys64 = SYS_getdents64;
+ goto def;
+
+ case SYS_mmap: /* set both if either */
+ case SYS_mmap64:
+ sys = SYS_mmap;
+ sys64 = SYS_mmap64;
+ goto def;
+
+ case SYS_statvfs: /* set both if either */
+ case SYS_statvfs64:
+ sys = SYS_statvfs;
+ sys64 = SYS_statvfs64;
+ goto def;
+
+ case SYS_fstatvfs: /* set both if either */
+ case SYS_fstatvfs64:
+ sys = SYS_fstatvfs;
+ sys64 = SYS_fstatvfs64;
+ goto def;
+
+ case SYS_setrlimit: /* set both if either */
+ case SYS_setrlimit64:
+ sys = SYS_setrlimit;
+ sys64 = SYS_setrlimit64;
+ goto def;
+
+ case SYS_getrlimit: /* set both if either */
+ case SYS_getrlimit64:
+ sys = SYS_getrlimit;
+ sys64 = SYS_getrlimit64;
+ goto def;
+
+ case SYS_pread: /* set both if either */
+ case SYS_pread64:
+ sys = SYS_pread;
+ sys64 = SYS_pread64;
+ goto def;
+
+ case SYS_pwrite: /* set both if either */
+ case SYS_pwrite64:
+ sys = SYS_pwrite;
+ sys64 = SYS_pwrite64;
+ goto def;
+
+ case SYS_openat: /* set all if any */
+ case SYS_openat64:
+ case SYS_open:
+ case SYS_open64:
+ sys = SYS_openat;
+ sys64 = SYS_openat64;
+ sysx = SYS_open;
+ sysxx = SYS_open64;
+ goto def;
+
+ case SYS_forksys: /* set both if either */
+ case SYS_vfork:
+ sysx = SYS_forksys;
+ sys = SYS_vfork;
+ goto def;
+
+ case SYS_sigprocmask: /* set both if either */
+ case SYS_lwp_sigmask:
+ sysx = SYS_sigprocmask;
+ sys = SYS_lwp_sigmask;
+ goto def;
+
+ case SYS_lseek: /* set both if either */
+ case SYS_llseek:
+ sysx = SYS_lseek;
+ sys = SYS_llseek;
+ goto def;
+
+ case SYS_rename: /* set both */
+ sysx = SYS_renameat;
+ goto def;
+
+ case SYS_link: /* set both */
+ sysx = SYS_linkat;
+ goto def;
+
+ case SYS_unlink: /* set both */
+ case SYS_rmdir: /* set both */
+ sysx = SYS_unlinkat;
+ goto def;
+
+ case SYS_symlink: /* set both */
+ sysx = SYS_symlinkat;
+ goto def;
+
+ case SYS_readlink: /* set both */
+ sysx = SYS_readlinkat;
+ goto def;
+
+ case SYS_chmod: /* set both */
+ case SYS_fchmod: /* set both */
+ sysx = SYS_fchmodat;
+ goto def;
+
+ case SYS_chown: /* set both */
+ case SYS_lchown: /* set both */
+ case SYS_fchown: /* set both */
+ sysx = SYS_fchownat;
+ goto def;
+
+ case SYS_mkdir: /* set both */
+ sysx = SYS_mkdirat;
+ goto def;
+
+ case SYS_mknod: /* set both */
+ sysx = SYS_mknodat;
+ goto def;
+
+ case SYS_access: /* set both */
+ sysx = SYS_faccessat;
+ goto def;
+
+ default:
+ def:
+ if (exclude) {
+ prdelset(setp, sys);
+ if (sysx)
+ prdelset(setp, sysx);
+ if (sysxx)
+ prdelset(setp, sysxx);
+ if (sys64)
+ prdelset(setp, sys64);
+ } else {
+ praddset(setp, sys);
+ if (sysx)
+ praddset(setp, sysx);
+ if (sysxx)
+ praddset(setp, sysxx);
+ if (sys64)
+ praddset(setp, sys64);
+ }
+ break;
+ }
+ } else if (strcmp(name, "all") == 0 ||
+ strcmp(name, "ALL") == 0) {
+ if (exclude) {
+ premptyset(setp);
+ } else {
+ prfillset(setp);
+ }
+ } else {
+ (void) fprintf(stderr,
+ "%s: unrecognized syscall: %s\n",
+ command, name);
+ rc = -1;
+ }
+ }
+
+ return (rc);
+}
+
+/*
+ * List of signals to trace.
+ * Return 0 on success, != 0 on any failure.
+ */
+int
+siglist(private_t *pri,
+ char *str, /* string of signal names */
+ sigset_t *setp, /* signal set */
+ int *fp) /* first-time flag */
+{
+ char *name;
+ int exclude = FALSE;
+ int rc = 0;
+ char *lasts;
+
+ upcase(str);
+ name = strtok_r(str, sepr, &lasts);
+
+ if (name != NULL && *name == '!') { /* exclude from set */
+ exclude = TRUE;
+ if (*++name == '\0')
+ name = strtok_r(NULL, sepr, &lasts);
+ } else if (!*fp) { /* first time, clear the set */
+ premptyset(setp);
+ *fp = TRUE;
+ }
+
+ for (; name; name = strtok_r(NULL, sepr, &lasts)) {
+ int sig;
+ char *next;
+
+ if (*name == '!') { /* exclude remainder from set */
+ exclude = TRUE;
+ while (*++name == '!')
+ /* empty */;
+ if (*name == '\0')
+ continue;
+ }
+
+ sig = strtol(name, &next, 0);
+ if (sig <= 0 || sig > PRMAXSIG || *next != '\0') {
+ for (sig = 1; sig <= PRMAXSIG; sig++) {
+ const char *sname = rawsigname(pri, sig);
+ if (sname == NULL)
+ continue;
+ if (strcmp(sname, name) == 0 ||
+ strcmp(sname+3, name) == 0)
+ break;
+ }
+ if (sig > PRMAXSIG)
+ sig = 0;
+ }
+ if (sig > 0 && sig <= PRMAXSIG) {
+ if (exclude) {
+ prdelset(setp, sig);
+ } else {
+ praddset(setp, sig);
+ }
+ } else if (strcmp(name, "ALL") == 0) {
+ if (exclude) {
+ premptyset(setp);
+ } else {
+ prfillset(setp);
+ }
+ } else {
+ (void) fprintf(stderr,
+ "%s: unrecognized signal name/number: %s\n",
+ command, name);
+ rc = -1;
+ }
+ }
+
+ return (rc);
+}
+
+/*
+ * List of faults to trace.
+ * return 0 on success, != 0 on any failure.
+ */
+int
+fltlist(char *str, /* string of fault names */
+ fltset_t *setp, /* fault set */
+ int *fp) /* first-time flag */
+{
+ char *name;
+ int exclude = FALSE;
+ int rc = 0;
+ char *lasts;
+
+ upcase(str);
+ name = strtok_r(str, sepr, &lasts);
+
+ if (name != NULL && *name == '!') { /* exclude from set */
+ exclude = TRUE;
+ if (*++name == '\0')
+ name = strtok_r(NULL, sepr, &lasts);
+ } else if (!*fp) { /* first time, clear the set */
+ premptyset(setp);
+ *fp = TRUE;
+ }
+
+ for (; name; name = strtok_r(NULL, sepr, &lasts)) {
+ int flt;
+ char *next;
+
+ if (*name == '!') { /* exclude remainder from set */
+ exclude = TRUE;
+ while (*++name == '!')
+ /* empty */;
+ if (*name == '\0')
+ continue;
+ }
+
+ flt = strtol(name, &next, 0);
+ if (flt <= 0 || flt > PRMAXFAULT || *next != '\0') {
+ for (flt = 1; flt <= PRMAXFAULT; flt++) {
+ char fname[32];
+
+ if (proc_fltname(flt, fname,
+ sizeof (fname)) == NULL)
+ continue;
+
+ if (strcmp(fname, name) == 0 ||
+ strcmp(fname+3, name) == 0)
+ break;
+ }
+ if (flt > PRMAXFAULT)
+ flt = 0;
+ }
+ if (flt > 0 && flt <= PRMAXFAULT) {
+ if (exclude) {
+ prdelset(setp, flt);
+ } else {
+ praddset(setp, flt);
+ }
+ } else if (strcmp(name, "ALL") == 0) {
+ if (exclude) {
+ premptyset(setp);
+ } else {
+ prfillset(setp);
+ }
+ } else {
+ (void) fprintf(stderr,
+ "%s: unrecognized fault name/number: %s\n",
+ command, name);
+ rc = -1;
+ }
+ }
+
+ return (rc);
+}
+
+/*
+ * Gather file descriptors to dump.
+ * Return 0 on success, != 0 on any failure.
+ */
+int
+fdlist(char *str, /* string of filedescriptors */
+ fileset_t *setp) /* set of boolean flags */
+{
+ char *name;
+ int exclude = FALSE;
+ int rc = 0;
+ char *lasts;
+
+ upcase(str);
+ name = strtok_r(str, sepr, &lasts);
+
+ if (name != NULL && *name == '!') { /* exclude from set */
+ exclude = TRUE;
+ if (*++name == '\0')
+ name = strtok_r(NULL, sepr, &lasts);
+ }
+
+ for (; name; name = strtok_r(NULL, sepr, &lasts)) {
+ int fd;
+ char *next;
+
+ if (*name == '!') { /* exclude remainder from set */
+ exclude = TRUE;
+ while (*++name == '!')
+ /* empty */;
+ if (*name == '\0')
+ continue;
+ }
+
+ fd = strtol(name, &next, 0);
+ if (fd >= 0 && fd < NOFILES_MAX && *next == '\0') {
+ fd++;
+ if (exclude) {
+ prdelset(setp, fd);
+ } else {
+ praddset(setp, fd);
+ }
+ } else if (strcmp(name, "ALL") == 0) {
+ if (exclude) {
+ premptyset(setp);
+ } else {
+ prfillset(setp);
+ }
+ } else {
+ (void) fprintf(stderr,
+ "%s: filedescriptor not in range[0..%d]: %s\n",
+ command, NOFILES_MAX-1, name);
+ rc = -1;
+ }
+ }
+
+ return (rc);
+}
+
+void
+upcase(char *str)
+{
+ int c;
+
+ while ((c = *str) != '\0')
+ *str++ = toupper(c);
+}
+
+/*
+ * 'arg' points to a string like:
+ * libc,libnsl,... : printf,read,write,...
+ * or
+ * libc,libnsl,... :: printf,read,write,...
+ * with possible filename pattern-matching metacharacters.
+ *
+ * Assumption: No library or function name can contain ',' or ':'.
+ */
+int
+liblist(char *arg, int hang)
+{
+ const char *star = "*";
+ struct dynpat *Dyp;
+ char *pat;
+ char *fpat;
+ char *lasts;
+ uint_t maxpat;
+
+ /* append a new dynpat structure to the end of the Dynpat list */
+ Dyp = my_malloc(sizeof (struct dynpat), NULL);
+ Dyp->next = NULL;
+ if (Lastpat == NULL)
+ Dynpat = Lastpat = Dyp;
+ else {
+ Lastpat->next = Dyp;
+ Lastpat = Dyp;
+ }
+ Dyp->flag = hang? BPT_HANG : 0;
+ Dyp->exclude_lib = 0;
+ Dyp->exclude = 0;
+ Dyp->internal = 0;
+ Dyp->Dp = NULL;
+
+ /*
+ * Find the beginning of the filename patterns
+ * and null-terminate the library name patterns.
+ */
+ if ((fpat = strchr(arg, ':')) != NULL)
+ *fpat++ = '\0';
+
+ /*
+ * Library name patterns.
+ */
+ pat = strtok_r(arg, sepr, &lasts);
+
+ /* '!' introduces an exclusion list */
+ if (pat != NULL && *pat == '!') {
+ Dyp->exclude_lib = 1;
+ pat += strspn(pat, "!");
+ if (*pat == '\0')
+ pat = strtok_r(NULL, sepr, &lasts);
+ /* force exclusion of all functions as well */
+ Dyp->exclude = 1;
+ Dyp->internal = 1;
+ fpat = NULL;
+ }
+
+ if (pat == NULL) {
+ /* empty list means all libraries */
+ Dyp->libpat = my_malloc(sizeof (char *), NULL);
+ Dyp->libpat[0] = star;
+ Dyp->nlibpat = 1;
+ } else {
+ /*
+ * We are now at the library list.
+ * Generate the list and count the library name patterns.
+ */
+ maxpat = 1;
+ Dyp->libpat = my_malloc(maxpat * sizeof (char *), NULL);
+ Dyp->nlibpat = 0;
+ Dyp->libpat[Dyp->nlibpat++] = pat;
+ while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) {
+ if (Dyp->nlibpat == maxpat) {
+ maxpat *= 2;
+ Dyp->libpat = my_realloc(Dyp->libpat,
+ maxpat * sizeof (char *), NULL);
+ }
+ Dyp->libpat[Dyp->nlibpat++] = pat;
+ }
+ }
+
+ /*
+ * Function name patterns.
+ */
+ if (fpat == NULL)
+ pat = NULL;
+ else {
+ /*
+ * We have already seen a ':'. Look for another.
+ * Double ':' means trace internal calls.
+ */
+ fpat += strspn(fpat, white);
+ if (*fpat == ':') {
+ Dyp->internal = 1;
+ *fpat++ = '\0';
+ }
+ pat = strtok_r(fpat, csepr, &lasts);
+ }
+
+ /* '!' introduces an exclusion list */
+ if (pat != NULL && *pat == '!') {
+ Dyp->exclude = 1;
+ Dyp->internal = 1;
+ pat += strspn(pat, "!");
+ if (*pat == '\0')
+ pat = strtok_r(NULL, sepr, &lasts);
+ }
+
+ if (pat == NULL) {
+ /* empty function list means exclude all functions */
+ Dyp->sympat = my_malloc(sizeof (char *), NULL);
+ Dyp->sympat[0] = star;
+ Dyp->nsympat = 1;
+ } else {
+ /*
+ * We are now at the function list.
+ * Generate the list and count the symbol name patterns.
+ */
+ maxpat = 1;
+ Dyp->sympat = my_malloc(maxpat * sizeof (char *), NULL);
+ Dyp->nsympat = 0;
+ Dyp->sympat[Dyp->nsympat++] = pat;
+ while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) {
+ if (Dyp->nsympat == maxpat) {
+ maxpat *= 2;
+ Dyp->sympat = my_realloc(Dyp->sympat,
+ maxpat * sizeof (char *), NULL);
+ }
+ Dyp->sympat[Dyp->nsympat++] = pat;
+ }
+ }
+
+ return (0);
+}