summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbdrewery <bdrewery@FreeBSD.org>2015-10-06 21:58:38 +0000
committerbdrewery <bdrewery@FreeBSD.org>2015-10-06 21:58:38 +0000
commit7c2a5d79afd81f0e773ba7ddc4fe40c4c3d62627 (patch)
tree52c11c1990eccc6a0f7281e868a447f7a337a01d
parentcb4dcd0eff4e6b716d70dbc789e83538ea109d30 (diff)
downloadFreeBSD-src-7c2a5d79afd81f0e773ba7ddc4fe40c4c3d62627.zip
FreeBSD-src-7c2a5d79afd81f0e773ba7ddc4fe40c4c3d62627.tar.gz
truss: Add support for utrace(2).
This uses the kdump(1) utrace support code directly until a common library is created. This allows malloc(3) tracing with MALLOC_CONF=utrace:true and rtld tracing with LD_UTRACE=1. Unknown utrace(2) data is just printed as hex. PR: 43819 [inspired by] Reviewed by: jhb MFC after: 2 weeks Relnotes: yes Differential Revision: https://reviews.freebsd.org/D3819
-rw-r--r--lib/libc/sys/utrace.25
-rw-r--r--usr.bin/kdump/Makefile2
-rw-r--r--usr.bin/kdump/kdump.c144
-rw-r--r--usr.bin/kdump/utrace.c187
-rw-r--r--usr.bin/truss/Makefile3
-rw-r--r--usr.bin/truss/syscall.h3
-rw-r--r--usr.bin/truss/syscalls.c37
-rw-r--r--usr.bin/truss/truss.15
8 files changed, 239 insertions, 147 deletions
diff --git a/lib/libc/sys/utrace.2 b/lib/libc/sys/utrace.2
index 9d24f20..345c1fd 100644
--- a/lib/libc/sys/utrace.2
+++ b/lib/libc/sys/utrace.2
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 1, 2014
+.Dd October 5, 2015
.Dt UTRACE 2
.Os
.Sh NAME
@@ -70,7 +70,8 @@ support
.Sh SEE ALSO
.Xr kdump 1 ,
.Xr ktrace 1 ,
-.Xr ktrace 2
+.Xr ktrace 2 ,
+.Xr truss 1
.Sh HISTORY
The
.Fn utrace
diff --git a/usr.bin/kdump/Makefile b/usr.bin/kdump/Makefile
index 72e6305..6f196ac 100644
--- a/usr.bin/kdump/Makefile
+++ b/usr.bin/kdump/Makefile
@@ -6,7 +6,7 @@
.PATH: ${.CURDIR}/../ktrace
PROG= kdump
-SRCS= kdump_subr.c kdump.c ioctl.c subr.c
+SRCS= kdump_subr.c kdump.c ioctl.c subr.c utrace.c
DPSRCS= kdump_subr.h
CFLAGS+= -I${.CURDIR}/../ktrace -I${.CURDIR} -I${.CURDIR}/../.. -I.
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index d8b6ccd..4804a81 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -67,7 +67,6 @@ extern int errno;
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>
-#include <dlfcn.h>
#include <err.h>
#include <grp.h>
#include <inttypes.h>
@@ -117,6 +116,7 @@ void ktrfaultend(struct ktr_faultend *);
void limitfd(int fd);
void usage(void);
void ioctlname(unsigned long, int);
+int kdump_print_utrace(FILE *, void *, size_t, int);
#define TIMESTAMP_NONE 0x0
#define TIMESTAMP_ABSOLUTE 0x1
@@ -1536,151 +1536,13 @@ ktrcsw(struct ktr_csw *cs)
cs->user ? "user" : "kernel", cs->wmesg);
}
-#define UTRACE_DLOPEN_START 1
-#define UTRACE_DLOPEN_STOP 2
-#define UTRACE_DLCLOSE_START 3
-#define UTRACE_DLCLOSE_STOP 4
-#define UTRACE_LOAD_OBJECT 5
-#define UTRACE_UNLOAD_OBJECT 6
-#define UTRACE_ADD_RUNDEP 7
-#define UTRACE_PRELOAD_FINISHED 8
-#define UTRACE_INIT_CALL 9
-#define UTRACE_FINI_CALL 10
-#define UTRACE_DLSYM_START 11
-#define UTRACE_DLSYM_STOP 12
-
-struct utrace_rtld {
- char sig[4]; /* 'RTLD' */
- int event;
- void *handle;
- void *mapbase;
- size_t mapsize;
- int refcnt;
- char name[MAXPATHLEN];
-};
-
-void
-ktruser_rtld(int len, void *p)
-{
- struct utrace_rtld *ut = p;
- unsigned char *cp;
- void *parent;
- int mode;
-
- switch (ut->event) {
- case UTRACE_DLOPEN_START:
- mode = ut->refcnt;
- printf("dlopen(%s, ", ut->name);
- switch (mode & RTLD_MODEMASK) {
- case RTLD_NOW:
- printf("RTLD_NOW");
- break;
- case RTLD_LAZY:
- printf("RTLD_LAZY");
- break;
- default:
- printf("%#x", mode & RTLD_MODEMASK);
- }
- if (mode & RTLD_GLOBAL)
- printf(" | RTLD_GLOBAL");
- if (mode & RTLD_TRACE)
- printf(" | RTLD_TRACE");
- if (mode & ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE))
- printf(" | %#x", mode &
- ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE));
- printf(")\n");
- break;
- case UTRACE_DLOPEN_STOP:
- printf("%p = dlopen(%s) ref %d\n", ut->handle, ut->name,
- ut->refcnt);
- break;
- case UTRACE_DLCLOSE_START:
- printf("dlclose(%p) (%s, %d)\n", ut->handle, ut->name,
- ut->refcnt);
- break;
- case UTRACE_DLCLOSE_STOP:
- printf("dlclose(%p) finished\n", ut->handle);
- break;
- case UTRACE_LOAD_OBJECT:
- printf("RTLD: loaded %p @ %p - %p (%s)\n", ut->handle,
- ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
- ut->name);
- break;
- case UTRACE_UNLOAD_OBJECT:
- printf("RTLD: unloaded %p @ %p - %p (%s)\n", ut->handle,
- ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
- ut->name);
- break;
- case UTRACE_ADD_RUNDEP:
- parent = ut->mapbase;
- printf("RTLD: %p now depends on %p (%s, %d)\n", parent,
- ut->handle, ut->name, ut->refcnt);
- break;
- case UTRACE_PRELOAD_FINISHED:
- printf("RTLD: LD_PRELOAD finished\n");
- break;
- case UTRACE_INIT_CALL:
- printf("RTLD: init %p for %p (%s)\n", ut->mapbase, ut->handle,
- ut->name);
- break;
- case UTRACE_FINI_CALL:
- printf("RTLD: fini %p for %p (%s)\n", ut->mapbase, ut->handle,
- ut->name);
- break;
- case UTRACE_DLSYM_START:
- printf("RTLD: dlsym(%p, %s)\n", ut->handle, ut->name);
- break;
- case UTRACE_DLSYM_STOP:
- printf("RTLD: %p = dlsym(%p, %s)\n", ut->mapbase, ut->handle,
- ut->name);
- break;
- default:
- cp = p;
- cp += 4;
- len -= 4;
- printf("RTLD: %d ", len);
- while (len--)
- if (decimal)
- printf(" %d", *cp++);
- else
- printf(" %02x", *cp++);
- printf("\n");
- }
-}
-
-struct utrace_malloc {
- void *p;
- size_t s;
- void *r;
-};
-
-void
-ktruser_malloc(void *p)
-{
- struct utrace_malloc *ut = p;
-
- if (ut->p == (void *)(intptr_t)(-1))
- printf("malloc_init()\n");
- else if (ut->s == 0)
- printf("free(%p)\n", ut->p);
- else if (ut->p == NULL)
- printf("%p = malloc(%zu)\n", ut->r, ut->s);
- else
- printf("%p = realloc(%p, %zu)\n", ut->r, ut->p, ut->s);
-}
-
void
ktruser(int len, void *p)
{
unsigned char *cp;
- if (len >= 8 && bcmp(p, "RTLD", 4) == 0) {
- ktruser_rtld(len, p);
- return;
- }
-
- if (len == sizeof(struct utrace_malloc)) {
- ktruser_malloc(p);
+ if (kdump_print_utrace(stdout, p, len, decimal)) {
+ printf("\n");
return;
}
diff --git a/usr.bin/kdump/utrace.c b/usr.bin/kdump/utrace.c
new file mode 100644
index 0000000..e719365
--- /dev/null
+++ b/usr.bin/kdump/utrace.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 1988, 1993
+ * 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/param.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <strings.h>
+
+int kdump_print_utrace(FILE *, void *, size_t, int);
+
+#define UTRACE_DLOPEN_START 1
+#define UTRACE_DLOPEN_STOP 2
+#define UTRACE_DLCLOSE_START 3
+#define UTRACE_DLCLOSE_STOP 4
+#define UTRACE_LOAD_OBJECT 5
+#define UTRACE_UNLOAD_OBJECT 6
+#define UTRACE_ADD_RUNDEP 7
+#define UTRACE_PRELOAD_FINISHED 8
+#define UTRACE_INIT_CALL 9
+#define UTRACE_FINI_CALL 10
+#define UTRACE_DLSYM_START 11
+#define UTRACE_DLSYM_STOP 12
+
+struct utrace_rtld {
+ char sig[4]; /* 'RTLD' */
+ int event;
+ void *handle;
+ void *mapbase;
+ size_t mapsize;
+ int refcnt;
+ char name[MAXPATHLEN];
+};
+
+static void
+print_utrace_rtld(FILE *fp, void *p, size_t len, int decimal)
+{
+ struct utrace_rtld *ut = p;
+ unsigned char *cp;
+ void *parent;
+ int mode;
+
+ switch (ut->event) {
+ case UTRACE_DLOPEN_START:
+ mode = ut->refcnt;
+ fprintf(fp, "dlopen(%s, ", ut->name);
+ switch (mode & RTLD_MODEMASK) {
+ case RTLD_NOW:
+ fprintf(fp, "RTLD_NOW");
+ break;
+ case RTLD_LAZY:
+ fprintf(fp, "RTLD_LAZY");
+ break;
+ default:
+ fprintf(fp, "%#x", mode & RTLD_MODEMASK);
+ }
+ if (mode & RTLD_GLOBAL)
+ fprintf(fp, " | RTLD_GLOBAL");
+ if (mode & RTLD_TRACE)
+ fprintf(fp, " | RTLD_TRACE");
+ if (mode & ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE))
+ fprintf(fp, " | %#x", mode &
+ ~(RTLD_MODEMASK | RTLD_GLOBAL | RTLD_TRACE));
+ fprintf(fp, ")");
+ break;
+ case UTRACE_DLOPEN_STOP:
+ fprintf(fp, "%p = dlopen(%s) ref %d", ut->handle, ut->name,
+ ut->refcnt);
+ break;
+ case UTRACE_DLCLOSE_START:
+ fprintf(fp, "dlclose(%p) (%s, %d)", ut->handle, ut->name,
+ ut->refcnt);
+ break;
+ case UTRACE_DLCLOSE_STOP:
+ fprintf(fp, "dlclose(%p) finished", ut->handle);
+ break;
+ case UTRACE_LOAD_OBJECT:
+ fprintf(fp, "RTLD: loaded %p @ %p - %p (%s)", ut->handle,
+ ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
+ ut->name);
+ break;
+ case UTRACE_UNLOAD_OBJECT:
+ fprintf(fp, "RTLD: unloaded %p @ %p - %p (%s)", ut->handle,
+ ut->mapbase, (char *)ut->mapbase + ut->mapsize - 1,
+ ut->name);
+ break;
+ case UTRACE_ADD_RUNDEP:
+ parent = ut->mapbase;
+ fprintf(fp, "RTLD: %p now depends on %p (%s, %d)", parent,
+ ut->handle, ut->name, ut->refcnt);
+ break;
+ case UTRACE_PRELOAD_FINISHED:
+ fprintf(fp, "RTLD: LD_PRELOAD finished");
+ break;
+ case UTRACE_INIT_CALL:
+ fprintf(fp, "RTLD: init %p for %p (%s)", ut->mapbase, ut->handle,
+ ut->name);
+ break;
+ case UTRACE_FINI_CALL:
+ fprintf(fp, "RTLD: fini %p for %p (%s)", ut->mapbase, ut->handle,
+ ut->name);
+ break;
+ case UTRACE_DLSYM_START:
+ fprintf(fp, "RTLD: dlsym(%p, %s)", ut->handle, ut->name);
+ break;
+ case UTRACE_DLSYM_STOP:
+ fprintf(fp, "RTLD: %p = dlsym(%p, %s)", ut->mapbase, ut->handle,
+ ut->name);
+ break;
+ default:
+ cp = p;
+ cp += 4;
+ len -= 4;
+ fprintf(fp, "RTLD: %zu ", len);
+ while (len--)
+ if (decimal)
+ fprintf(fp, " %d", *cp++);
+ else
+ fprintf(fp, " %02x", *cp++);
+ }
+}
+
+struct utrace_malloc {
+ void *p;
+ size_t s;
+ void *r;
+};
+
+static void
+print_utrace_malloc(FILE *fp, void *p)
+{
+ struct utrace_malloc *ut = p;
+
+ if (ut->p == (void *)(intptr_t)(-1))
+ fprintf(fp, "malloc_init()");
+ else if (ut->s == 0)
+ fprintf(fp, "free(%p)", ut->p);
+ else if (ut->p == NULL)
+ fprintf(fp, "%p = malloc(%zu)", ut->r, ut->s);
+ else
+ fprintf(fp, "%p = realloc(%p, %zu)", ut->r, ut->p, ut->s);
+}
+
+int
+kdump_print_utrace(FILE *fp, void *p, size_t len, int decimal)
+{
+
+ if (len >= 8 && bcmp(p, "RTLD", 4) == 0) {
+ print_utrace_rtld(fp, p, len, decimal);
+ return (1);
+ }
+
+ if (len == sizeof(struct utrace_malloc)) {
+ print_utrace_malloc(fp, p);
+ return (1);
+ }
+
+ return (0);
+}
diff --git a/usr.bin/truss/Makefile b/usr.bin/truss/Makefile
index 1cd0a9c..8c78196 100644
--- a/usr.bin/truss/Makefile
+++ b/usr.bin/truss/Makefile
@@ -10,6 +10,9 @@ SRCS+= ${MACHINE_ARCH}-fbsd.c
SRCS+= ${MACHINE_CPUARCH}-fbsd.c
.endif
+.PATH: ${.CURDIR:H}/kdump
+SRCS+= utrace.c
+
CFLAGS+= -I${.CURDIR} -I.
CLEANFILES= syscalls.master syscalls.h ioctl.c
diff --git a/usr.bin/truss/syscall.h b/usr.bin/truss/syscall.h
index 3e3a1b9..a870810 100644
--- a/usr.bin/truss/syscall.h
+++ b/usr.bin/truss/syscall.h
@@ -27,6 +27,7 @@
* Sigprocmask -- the first argument to sigprocmask(). Prints the name.
* Kevent -- a pointer to an array of struct kevents. Prints all elements.
* Pathconf -- the 2nd argument of pathconf().
+ * Utrace -- utrace(2) buffer.
*
* In addition, the pointer types (String, Ptr) may have OUT masked in --
* this means that the data is set on *return* from the system call -- or
@@ -43,7 +44,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, PipeFds, QuadHex };
+ Sysarch, ExecArgs, ExecEnv, PipeFds, QuadHex, Utrace };
#define ARG_MASK 0xff
#define OUT 0x100
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index 540138d..d14fa86 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -72,6 +72,9 @@ __FBSDID("$FreeBSD$");
#include "extern.h"
#include "syscall.h"
+/* usr.bin/kdump/utrace.c */
+int kdump_print_utrace(FILE *, void *, size_t, int);
+
/* 64-bit alignment on 32-bit platforms. */
#if !defined(__LP64__) && defined(__powerpc__)
#define QUAD_ALIGN 1
@@ -342,6 +345,8 @@ static struct syscall decoded_syscalls[] = {
{ Atflags, 3 } } },
{ .name = "utimes", .ret_type = 1, .nargs = 2,
.args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
+ { .name = "utrace", .ret_type = 1, .nargs = 1,
+ .args = { { Utrace, 0 } } },
{ .name = "wait4", .ret_type = 1, .nargs = 4,
.args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
{ Rusage | OUT, 3 } } },
@@ -860,6 +865,24 @@ print_kevent(FILE *fp, struct kevent *ke, int input)
fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
}
+static void
+print_utrace(FILE *fp, void *utrace_addr, size_t len)
+{
+ unsigned char *utrace_buffer;
+
+ fprintf(fp, "{ ");
+ if (kdump_print_utrace(fp, utrace_addr, len, 0)) {
+ fprintf(fp, " }");
+ return;
+ }
+
+ utrace_buffer = utrace_addr;
+ fprintf(fp, "%zu:", len);
+ while (len--)
+ fprintf(fp, " %02x", *utrace_buffer++);
+ fprintf(fp, " }");
+}
+
/*
* Converts a syscall argument into a string. Said string is
* allocated via malloc(), so needs to be free()'d. sc is
@@ -1601,6 +1624,20 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
retval[0] = 0;
break;
+ case Utrace: {
+ size_t len;
+ void *utrace_addr;
+
+ len = args[sc->offset + 1];
+ utrace_addr = calloc(1, len);
+ if (get_struct(pid, (void *)args[sc->offset],
+ (void *)utrace_addr, len) != -1)
+ print_utrace(fp, utrace_addr, len);
+ else
+ fprintf(fp, "0x%lx", args[sc->offset]);
+ free(utrace_addr);
+ break;
+ }
default:
errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
}
diff --git a/usr.bin/truss/truss.1 b/usr.bin/truss/truss.1
index 6a01451..7c148df 100644
--- a/usr.bin/truss/truss.1
+++ b/usr.bin/truss/truss.1
@@ -1,6 +1,6 @@
.\" $FreeBSD$
.\"
-.Dd May 12, 2009
+.Dd October 5, 2015
.Dt TRUSS 1
.Os
.Sh NAME
@@ -95,7 +95,8 @@ options are mutually exclusive.)
.Sh SEE ALSO
.Xr kdump 1 ,
.Xr ktrace 1 ,
-.Xr ptrace 2
+.Xr ptrace 2 ,
+.Xr utrace 2
.Sh HISTORY
The
.Nm
OpenPOWER on IntegriCloud