2009-04-13 16:22:38 +00:00
|
|
|
/*-
|
2017-11-18 14:26:50 +00:00
|
|
|
* SPDX-License-Identifier: BSD-4-Clause
|
|
|
|
*
|
2010-03-10 20:31:30 +00:00
|
|
|
* Copyright 1997 Sean Eric Fagan
|
1997-12-20 18:40:43 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by Sean Eric Fagan
|
|
|
|
* 4. Neither the name of the author may be used to endorse or promote
|
|
|
|
* products derived from this software without specific prior written
|
|
|
|
* permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
|
|
|
*/
|
|
|
|
|
2003-09-07 15:50:43 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
1998-01-05 07:30:26 +00:00
|
|
|
|
1997-12-06 05:23:12 +00:00
|
|
|
/*
|
|
|
|
* Various setup functions for truss. Not the cleanest-written code,
|
|
|
|
* I'm afraid.
|
|
|
|
*/
|
|
|
|
|
2007-04-10 04:03:34 +00:00
|
|
|
#include <sys/ptrace.h>
|
2015-09-30 19:13:32 +00:00
|
|
|
#include <sys/sysctl.h>
|
Make timespecadd(3) and friends public
The timespecadd(3) family of macros were imported from NetBSD back in
r35029. However, they were initially guarded by #ifdef _KERNEL. In the
meantime, we have grown at least 28 syscalls that use timespecs in some
way, leading many programs both inside and outside of the base system to
redefine those macros. It's better just to make the definitions public.
Our kernel currently defines two-argument versions of timespecadd and
timespecsub. NetBSD, OpenBSD, and FreeDesktop.org's libbsd, however, define
three-argument versions. Solaris also defines a three-argument version, but
only in its kernel. This revision changes our definition to match the
common three-argument version.
Bump _FreeBSD_version due to the breaking KPI change.
Discussed with: cem, jilles, ian, bde
Differential Revision: https://reviews.freebsd.org/D14725
2018-07-30 15:46:40 +00:00
|
|
|
#include <sys/time.h>
|
2001-10-22 02:02:00 +00:00
|
|
|
#include <sys/wait.h>
|
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
#include <assert.h>
|
1998-01-05 07:30:26 +00:00
|
|
|
#include <err.h>
|
2009-12-13 03:14:06 +00:00
|
|
|
#include <errno.h>
|
1998-01-05 07:30:26 +00:00
|
|
|
#include <signal.h>
|
Move mksubr from kdump into libsysdecode.
Restructure this script so that it generates a header of tables instead
of a source file. The tables are included in a flags.c source file which
provides functions to decode various system call arguments.
For functions that decode an enumeration, the function returns a pointer
to a string for known values and NULL for unknown values.
For functions that do more complex decoding (typically of a bitmask), the
function accepts a pointer to a FILE object (open_memstream() can be used
as a string builder) to which decoded values are written. If the
function operates on a bitmask, the function returns true if any bits
were decoded or false if the entire value was valid. Additionally, the
third argument accepts a pointer to a value to which any undecoded bits
are stored. This pointer can be NULL if the caller doesn't care about
remaining bits.
Convert kdump over to using decoder functions from libsysdecode instead of
mksubr. truss also uses decoders from libsysdecode instead of private
lookup tables, though lookup tables for objects not decoded by kdump remain
in truss for now. Eventually most of these tables should move into
libsysdecode as the automated table generation approach from mksubr is
less stale than the static tables in truss.
Some changes have been made to truss and kdump output:
- The flags passed to open() are now properly decoded in that one of
O_RDONLY, O_RDWR, O_WRONLY, or O_EXEC is always included in a decoded
mask.
- Optional arguments to open(), openat(), and fcntl() are only printed
in kdump if they exist (e.g. the mode is only printed for open() if
O_CREAT is set in the flags).
- Print argument to F_GETLK/SETLK/SETLKW in kdump as a pointer, not int.
- Include all procctl() commands.
- Correctly decode pipe2() flags in truss by not assuming full
open()-like flags with O_RDONLY, etc.
- Decode file flags passed to *chflags() as file flags (UF_* and SF_*)
rather than as a file mode.
- Fix decoding of quotactl() commands by splitting out the two command
components instead of assuming the raw command value matches the
primary command component.
In addition, truss and kdump now build without triggering any warnings.
All of the sysdecode manpages now include the required headers in the
synopsis.
Reviewed by: kib (several older versions), wblock (manpages)
MFC after: 2 months
Differential Revision: https://reviews.freebsd.org/D7847
2016-10-17 22:37:07 +00:00
|
|
|
#include <stdbool.h>
|
2015-09-30 19:13:32 +00:00
|
|
|
#include <stdint.h>
|
1997-12-06 05:23:12 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2009-12-13 03:14:06 +00:00
|
|
|
#include <string.h>
|
2016-01-26 19:07:09 +00:00
|
|
|
#include <sysdecode.h>
|
2009-12-13 03:14:06 +00:00
|
|
|
#include <time.h>
|
1997-12-06 05:23:12 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2002-08-04 00:46:48 +00:00
|
|
|
#include "truss.h"
|
2015-09-30 19:13:32 +00:00
|
|
|
#include "syscall.h"
|
2001-12-11 23:34:02 +00:00
|
|
|
#include "extern.h"
|
|
|
|
|
2019-07-16 22:59:15 +00:00
|
|
|
struct procabi_table {
|
|
|
|
const char *name;
|
|
|
|
struct procabi *abi;
|
|
|
|
};
|
2015-09-30 19:13:32 +00:00
|
|
|
|
2012-09-12 13:06:57 +00:00
|
|
|
static sig_atomic_t detaching;
|
1997-12-06 05:23:12 +00:00
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
static void enter_syscall(struct trussinfo *, struct threadinfo *,
|
|
|
|
struct ptrace_lwpinfo *);
|
|
|
|
static void new_proc(struct trussinfo *, pid_t, lwpid_t);
|
2015-09-30 19:13:32 +00:00
|
|
|
|
2019-07-16 22:59:15 +00:00
|
|
|
|
|
|
|
static struct procabi freebsd = {
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
.type = "FreeBSD",
|
|
|
|
.abi = SYSDECODE_ABI_FREEBSD,
|
|
|
|
.pointer_size = sizeof(void *),
|
|
|
|
.extra_syscalls = STAILQ_HEAD_INITIALIZER(freebsd.extra_syscalls),
|
|
|
|
.syscalls = { NULL }
|
2019-07-16 22:59:15 +00:00
|
|
|
};
|
|
|
|
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
#if !defined(__SIZEOF_POINTER__)
|
|
|
|
#error "Use a modern compiler."
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if __SIZEOF_POINTER__ > 4
|
2019-07-16 22:59:15 +00:00
|
|
|
static struct procabi freebsd32 = {
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
.type = "FreeBSD32",
|
|
|
|
.abi = SYSDECODE_ABI_FREEBSD32,
|
|
|
|
.pointer_size = sizeof(uint32_t),
|
2021-05-11 09:52:56 +00:00
|
|
|
.compat_prefix = "freebsd32_",
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
.extra_syscalls = STAILQ_HEAD_INITIALIZER(freebsd32.extra_syscalls),
|
|
|
|
.syscalls = { NULL }
|
2019-07-16 22:59:15 +00:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct procabi linux = {
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
.type = "Linux",
|
|
|
|
.abi = SYSDECODE_ABI_LINUX,
|
|
|
|
.pointer_size = sizeof(void *),
|
|
|
|
.extra_syscalls = STAILQ_HEAD_INITIALIZER(linux.extra_syscalls),
|
|
|
|
.syscalls = { NULL }
|
2019-07-16 22:59:15 +00:00
|
|
|
};
|
|
|
|
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
#if __SIZEOF_POINTER__ > 4
|
2019-07-16 22:59:15 +00:00
|
|
|
static struct procabi linux32 = {
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
.type = "Linux32",
|
|
|
|
.abi = SYSDECODE_ABI_LINUX32,
|
|
|
|
.pointer_size = sizeof(uint32_t),
|
|
|
|
.extra_syscalls = STAILQ_HEAD_INITIALIZER(linux32.extra_syscalls),
|
|
|
|
.syscalls = { NULL }
|
2019-07-16 22:59:15 +00:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct procabi_table abis[] = {
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
#if __SIZEOF_POINTER__ == 4
|
|
|
|
{ "FreeBSD ELF32", &freebsd },
|
|
|
|
#elif __SIZEOF_POINTER__ == 8
|
2019-07-16 22:59:15 +00:00
|
|
|
{ "FreeBSD ELF64", &freebsd },
|
|
|
|
{ "FreeBSD ELF32", &freebsd32 },
|
|
|
|
#else
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
#error "Unsupported pointer size"
|
2019-07-16 22:59:15 +00:00
|
|
|
#endif
|
|
|
|
#if defined(__powerpc64__)
|
|
|
|
{ "FreeBSD ELF64 V2", &freebsd },
|
|
|
|
#endif
|
|
|
|
#if defined(__amd64__)
|
|
|
|
{ "FreeBSD a.out", &freebsd32 },
|
|
|
|
#endif
|
|
|
|
#if defined(__i386__)
|
|
|
|
{ "FreeBSD a.out", &freebsd },
|
|
|
|
#endif
|
truss: improved support for decoding compat32 arguments
Currently running `truss -a -e` does not decode any
argument values for freebsd32_* syscalls (open/readlink/etc.)
This change checks whether a syscall starts with freebsd{32,64}_ and if
so strips that prefix when looking up the syscall information. To ensure
that the truss logs include the real syscall name we create a copy of
the syscall information struct with the updated.
The other problem is that when reading string array values, truss
naively iterates over an array of char* and fetches the pointer value.
This will result in arguments not being loaded if the pointer is not
aligned to sizeof(void*), which can happens in the compat32 case. If it
happens to be aligned, we would end up printing every other value.
To fix this problem, this changes adds a pointer_size member to the
procabi struct and uses that to correctly read indirect arguments
as 64/32 bit addresses in the the compat32 case (and also compat64 on
CheriBSD).
The motivating use-case for this change is using truss for 64-bit
programs on a CHERI system, but most of the diff also applies to 32-bit
compat on a 64-bit system, so I'm upstreaming this instead of keeping it
as a local CheriBSD patch.
Output of `truss -aef ldd32 /usr/bin/ldd32` before:
39113: freebsd32_mmap(0x0,0x1000,0x3,0x1002,0xffffffff,0x0,0x0) = 543440896 (0x20644000)
39113: freebsd32_ioctl(0x1,0x402c7413,0xffffd2a0) = 0 (0x0)
/usr/bin/ldd32:
39113: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
39113: fork() = 39114 (0x98ca)
39114: <new process>
39114: freebsd32_execve(0xffffd97e,0xffffd680,0x20634000) EJUSTRETURN
39114: freebsd32_mmap(0x0,0x20000,0x3,0x1002,0xffffffff,0x0,0x0) = 541237248 (0x2042a000)
39114: freebsd32_mprotect(0x20427000,0x1000,0x1) = 0 (0x0)
39114: issetugid() = 0 (0x0)
39114: openat(AT_FDCWD,"/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
39114: openat(AT_FDCWD,"/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
39114: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0#\0\0\0\0"...,128) = 128 (0x80)
39114: freebsd32_fstat(0x3,0xffffbd98) = 0 (0x0)
39114: freebsd32_pread(0x3,0x2042f000,0x23,0x80,0x0) = 35 (0x23)
39114: close(3) = 0 (0x0)
39114: openat(AT_FDCWD,"/usr/lib32/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
39114: freebsd32_fstat(0x3,0xffffc7d0) = 0 (0x0)
39114: freebsd32_mmap(0x0,0x1000,0x1,0x40002,0x3,0x0,0x0) = 541368320 (0x2044a000)
After:
783: freebsd32_mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 543543296 (0x2065d000)
783: freebsd32_ioctl(1,TIOCGETA,0xffffd7b0) = 0 (0x0)
/usr/bin/ldd32:
783: write(1,"/usr/bin/ldd32:\n",16) = 16 (0x10)
784: <new process>
783: fork() = 784 (0x310)
784: freebsd32_execve("/usr/bin/ldd32",[ "(null)" ],[ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_TRACE_LOADED_OBJECTS_PROGNAME=/usr/bin/ldd32", "LD_32_TRACE_LOADED_OBJECTS=yes", "LD_TRACE_LOADED_OBJECTS=yes", "USER=root", "LOGNAME=root", "HOME=/root", "SHELL=/bin/csh", "BLOCKSIZE=K", "MAIL=/var/mail/root", "MM_CHARSET=UTF-8", "LANG=C.UTF-8", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin", "TERM=vt100", "HOSTTYPE=FreeBSD", "VENDOR=amd", "OSTYPE=FreeBSD", "MACHTYPE=x86_64", "SHLVL=1", "PWD=/root", "GROUP=wheel", "HOST=freebsd-amd64", "EDITOR=vi", "PAGER=less" ]) EJUSTRETURN
784: freebsd32_mmap(0x0,135168,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 541212672 (0x20424000)
784: freebsd32_mprotect(0x20421000,4096,PROT_READ) = 0 (0x0)
784: issetugid() = 0 (0x0)
784: sigfastblock(0x1,0x204234fc) = 0 (0x0)
784: open("/etc/libmap32.conf",O_RDONLY|O_CLOEXEC,00) ERR#2 'No such file or directory'
784: open("/var/run/ld-elf32.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
784: read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\v\0\0\0"...,128) = 128 (0x80)
784: freebsd32_fstat(3,{ mode=-r--r--r-- ,inode=18680,size=32768,blksize=0 }) = 0 (0x0)
784: freebsd32_pread(3,"/usr/lib32\0",11,0x80) = 11 (0xb)
Reviewed By: jhb
Differential Revision: https://reviews.freebsd.org/D27625
2021-03-25 11:12:17 +00:00
|
|
|
#if __SIZEOF_POINTER__ >= 8
|
2019-07-16 22:59:15 +00:00
|
|
|
{ "Linux ELF64", &linux },
|
|
|
|
{ "Linux ELF32", &linux32 },
|
|
|
|
#else
|
2021-01-21 01:54:12 +00:00
|
|
|
{ "Linux ELF32", &linux },
|
2019-07-16 22:59:15 +00:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
1997-12-06 05:23:12 +00:00
|
|
|
/*
|
|
|
|
* setup_and_wait() is called to start a process. All it really does
|
2015-09-30 19:13:32 +00:00
|
|
|
* 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.
|
1997-12-06 05:23:12 +00:00
|
|
|
*/
|
2015-09-30 19:13:32 +00:00
|
|
|
void
|
|
|
|
setup_and_wait(struct trussinfo *info, char *command[])
|
2005-03-27 12:47:04 +00:00
|
|
|
{
|
2012-08-21 14:58:51 +00:00
|
|
|
pid_t pid;
|
2005-03-27 12:47:04 +00:00
|
|
|
|
2007-04-10 04:03:34 +00:00
|
|
|
pid = vfork();
|
2012-09-02 11:03:18 +00:00
|
|
|
if (pid == -1)
|
2005-03-27 12:47:04 +00:00
|
|
|
err(1, "fork failed");
|
|
|
|
if (pid == 0) { /* Child */
|
2007-04-10 04:03:34 +00:00
|
|
|
ptrace(PT_TRACE_ME, 0, 0, 0);
|
2005-03-27 12:47:04 +00:00
|
|
|
execvp(command[0], command);
|
2007-04-10 04:03:34 +00:00
|
|
|
err(1, "execvp %s", command[0]);
|
2005-03-27 12:47:04 +00:00
|
|
|
}
|
2012-09-02 11:03:18 +00:00
|
|
|
|
2005-03-27 12:47:04 +00:00
|
|
|
/* Only in the parent here */
|
2012-09-11 16:30:26 +00:00
|
|
|
if (waitpid(pid, NULL, 0) < 0)
|
2007-04-10 04:03:34 +00:00
|
|
|
err(1, "unexpect stop in waitpid");
|
2005-03-27 12:47:04 +00:00
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
new_proc(info, pid, 0);
|
1997-12-06 05:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2015-09-30 19:13:32 +00:00
|
|
|
* start_tracing is called to attach to an existing process.
|
1997-12-06 05:23:12 +00:00
|
|
|
*/
|
2015-09-30 19:13:32 +00:00
|
|
|
void
|
|
|
|
start_tracing(struct trussinfo *info, pid_t pid)
|
2005-03-27 12:47:04 +00:00
|
|
|
{
|
2012-09-11 16:30:26 +00:00
|
|
|
int ret, retry;
|
2007-04-10 04:03:34 +00:00
|
|
|
|
2012-09-02 11:03:18 +00:00
|
|
|
retry = 10;
|
2007-04-10 04:03:34 +00:00
|
|
|
do {
|
|
|
|
ret = ptrace(PT_ATTACH, pid, NULL, 0);
|
|
|
|
usleep(200);
|
2012-09-02 11:03:18 +00:00
|
|
|
} while (ret && retry-- > 0);
|
2007-04-10 04:03:34 +00:00
|
|
|
if (ret)
|
|
|
|
err(1, "can not attach to target process");
|
|
|
|
|
2012-09-11 16:30:26 +00:00
|
|
|
if (waitpid(pid, NULL, 0) < 0)
|
2007-04-10 04:03:34 +00:00
|
|
|
err(1, "Unexpect stop in waitpid");
|
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
new_proc(info, pid, 0);
|
1997-12-06 05:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Restore a process back to it's pre-truss state.
|
|
|
|
* Called for SIGINT, SIGTERM, SIGQUIT. This only
|
|
|
|
* applies if truss was told to monitor an already-existing
|
|
|
|
* process.
|
|
|
|
*/
|
|
|
|
void
|
2007-04-10 04:03:34 +00:00
|
|
|
restore_proc(int signo __unused)
|
2012-09-12 13:06:57 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
detaching = 1;
|
|
|
|
}
|
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
static void
|
2012-09-12 13:06:57 +00:00
|
|
|
detach_proc(pid_t pid)
|
2007-04-10 04:03:34 +00:00
|
|
|
{
|
2022-01-12 08:21:19 +00:00
|
|
|
int sig, status;
|
1997-12-06 05:23:12 +00:00
|
|
|
|
2022-01-12 08:21:19 +00:00
|
|
|
/*
|
|
|
|
* Stop the child so that we can detach. Filter out possible
|
|
|
|
* lingering SIGTRAP events buffered in the threads.
|
|
|
|
*/
|
2012-09-12 13:06:57 +00:00
|
|
|
kill(pid, SIGSTOP);
|
2022-01-12 08:21:19 +00:00
|
|
|
for (;;) {
|
|
|
|
if (waitpid(pid, &status, 0) < 0)
|
|
|
|
err(1, "Unexpected error in waitpid");
|
|
|
|
sig = WIFSTOPPED(status) ? WSTOPSIG(status) : 0;
|
|
|
|
if (sig == SIGSTOP)
|
|
|
|
break;
|
|
|
|
if (sig == SIGTRAP)
|
|
|
|
sig = 0;
|
|
|
|
if (ptrace(PT_CONTINUE, pid, (caddr_t)1, sig) < 0)
|
|
|
|
err(1, "Can not continue for detach");
|
|
|
|
}
|
2007-04-10 04:03:34 +00:00
|
|
|
|
2012-09-12 13:06:57 +00:00
|
|
|
if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
|
2007-04-10 04:03:34 +00:00
|
|
|
err(1, "Can not detach the process");
|
2012-09-02 11:03:18 +00:00
|
|
|
|
2012-09-12 13:06:57 +00:00
|
|
|
kill(pid, SIGCONT);
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine the ABI. This is called after every exec, and when
|
|
|
|
* a process is first monitored.
|
|
|
|
*/
|
|
|
|
static struct procabi *
|
|
|
|
find_abi(pid_t pid)
|
|
|
|
{
|
|
|
|
size_t len;
|
2019-07-16 22:59:15 +00:00
|
|
|
unsigned int i;
|
2015-09-30 19:13:32 +00:00
|
|
|
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");
|
|
|
|
|
2019-07-16 22:59:15 +00:00
|
|
|
for (i = 0; i < nitems(abis); i++) {
|
|
|
|
if (strcmp(abis[i].name, progt) == 0)
|
|
|
|
return (abis[i].abi);
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
|
|
|
warnx("ABI %s for pid %ld is not supported", progt, (long)pid);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
static struct threadinfo *
|
|
|
|
new_thread(struct procinfo *p, lwpid_t lwpid)
|
|
|
|
{
|
|
|
|
struct threadinfo *nt;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this happens it means there is a bug in truss. Unfortunately
|
|
|
|
* this will kill any processes truss is attached to.
|
|
|
|
*/
|
|
|
|
LIST_FOREACH(nt, &p->threadlist, entries) {
|
|
|
|
if (nt->tid == lwpid)
|
|
|
|
errx(1, "Duplicate thread for LWP %ld", (long)lwpid);
|
|
|
|
}
|
|
|
|
|
|
|
|
nt = calloc(1, sizeof(struct threadinfo));
|
|
|
|
if (nt == NULL)
|
|
|
|
err(1, "calloc() failed");
|
|
|
|
nt->proc = p;
|
|
|
|
nt->tid = lwpid;
|
|
|
|
LIST_INSERT_HEAD(&p->threadlist, nt, entries);
|
|
|
|
return (nt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_thread(struct threadinfo *t)
|
|
|
|
{
|
|
|
|
|
|
|
|
LIST_REMOVE(t, entries);
|
|
|
|
free(t);
|
|
|
|
}
|
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
static void
|
2016-03-09 18:45:41 +00:00
|
|
|
add_threads(struct trussinfo *info, struct procinfo *p)
|
|
|
|
{
|
|
|
|
struct ptrace_lwpinfo pl;
|
|
|
|
struct threadinfo *t;
|
|
|
|
lwpid_t *lwps;
|
|
|
|
int i, nlwps;
|
|
|
|
|
|
|
|
nlwps = ptrace(PT_GETNUMLWPS, p->pid, NULL, 0);
|
|
|
|
if (nlwps == -1)
|
|
|
|
err(1, "Unable to fetch number of LWPs");
|
|
|
|
assert(nlwps > 0);
|
|
|
|
lwps = calloc(nlwps, sizeof(*lwps));
|
|
|
|
nlwps = ptrace(PT_GETLWPLIST, p->pid, (caddr_t)lwps, nlwps);
|
|
|
|
if (nlwps == -1)
|
|
|
|
err(1, "Unable to fetch LWP list");
|
|
|
|
for (i = 0; i < nlwps; i++) {
|
|
|
|
t = new_thread(p, lwps[i]);
|
|
|
|
if (ptrace(PT_LWPINFO, lwps[i], (caddr_t)&pl, sizeof(pl)) == -1)
|
|
|
|
err(1, "ptrace(PT_LWPINFO)");
|
2016-08-02 22:47:06 +00:00
|
|
|
if (pl.pl_flags & PL_FLAG_SCE) {
|
|
|
|
info->curthread = t;
|
2016-03-09 18:45:41 +00:00
|
|
|
enter_syscall(info, t, &pl);
|
2016-08-02 22:47:06 +00:00
|
|
|
}
|
2016-03-09 18:45:41 +00:00
|
|
|
}
|
|
|
|
free(lwps);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
|
2015-09-30 19:13:32 +00:00
|
|
|
{
|
|
|
|
struct procinfo *np;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this happens it means there is a bug in truss. Unfortunately
|
2016-03-09 18:45:41 +00:00
|
|
|
* this will kill any processes truss is attached to.
|
2015-09-30 19:13:32 +00:00
|
|
|
*/
|
|
|
|
LIST_FOREACH(np, &info->proclist, entries) {
|
|
|
|
if (np->pid == pid)
|
|
|
|
errx(1, "Duplicate process for pid %ld", (long)pid);
|
|
|
|
}
|
2012-09-12 13:06:57 +00:00
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
if (info->flags & FOLLOWFORKS)
|
|
|
|
if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1)
|
|
|
|
err(1, "Unable to follow forks for pid %ld", (long)pid);
|
2016-03-09 18:45:41 +00:00
|
|
|
if (ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1)
|
|
|
|
err(1, "Unable to enable LWP events for pid %ld", (long)pid);
|
2015-09-30 19:13:32 +00:00
|
|
|
np = calloc(1, sizeof(struct procinfo));
|
|
|
|
np->pid = pid;
|
|
|
|
np->abi = find_abi(pid);
|
2016-03-09 18:45:41 +00:00
|
|
|
LIST_INIT(&np->threadlist);
|
2015-09-30 19:13:32 +00:00
|
|
|
LIST_INSERT_HEAD(&info->proclist, np, entries);
|
2016-03-09 18:45:41 +00:00
|
|
|
|
|
|
|
if (lwpid != 0)
|
|
|
|
new_thread(np, lwpid);
|
|
|
|
else
|
|
|
|
add_threads(info, np);
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_proc(struct procinfo *p)
|
|
|
|
{
|
|
|
|
struct threadinfo *t, *t2;
|
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
LIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) {
|
2015-09-30 19:13:32 +00:00
|
|
|
free(t);
|
|
|
|
}
|
|
|
|
LIST_REMOVE(p, entries);
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
1997-12-06 05:23:12 +00:00
|
|
|
}
|
2007-04-10 04:03:34 +00:00
|
|
|
|
|
|
|
/*
|
2015-09-30 19:13:32 +00:00
|
|
|
* Change curthread member based on (pid, lwpid).
|
2007-04-10 04:03:34 +00:00
|
|
|
*/
|
|
|
|
static void
|
2015-09-30 19:13:32 +00:00
|
|
|
find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
|
2007-04-10 04:03:34 +00:00
|
|
|
{
|
2015-09-30 19:13:32 +00:00
|
|
|
struct procinfo *np;
|
|
|
|
struct threadinfo *nt;
|
2012-09-02 11:03:18 +00:00
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
np = find_proc(info, pid);
|
|
|
|
assert(np != NULL);
|
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
LIST_FOREACH(nt, &np->threadlist, entries) {
|
2015-09-30 19:13:32 +00:00
|
|
|
if (nt->tid == lwpid) {
|
|
|
|
info->curthread = nt;
|
2012-09-02 11:03:18 +00:00
|
|
|
return;
|
2007-04-10 04:03:34 +00:00
|
|
|
}
|
|
|
|
}
|
2016-03-09 18:45:41 +00:00
|
|
|
errx(1, "could not find thread");
|
2007-04-10 04:03:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-03-09 18:45:41 +00:00
|
|
|
* When a process exits, it should have exactly one thread left.
|
|
|
|
* All of the other threads should have reported thread exit events.
|
2007-04-10 04:03:34 +00:00
|
|
|
*/
|
2015-09-30 19:13:32 +00:00
|
|
|
static void
|
|
|
|
find_exit_thread(struct trussinfo *info, pid_t pid)
|
2007-04-10 04:03:34 +00:00
|
|
|
{
|
2016-03-09 18:45:41 +00:00
|
|
|
struct procinfo *p;
|
2015-09-30 19:13:32 +00:00
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
p = find_proc(info, pid);
|
|
|
|
assert(p != NULL);
|
2015-09-30 19:13:32 +00:00
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
info->curthread = LIST_FIRST(&p->threadlist);
|
|
|
|
assert(info->curthread != NULL);
|
|
|
|
assert(LIST_NEXT(info->curthread, entries) == NULL);
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
2012-09-02 11:03:18 +00:00
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
static void
|
|
|
|
alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl)
|
|
|
|
{
|
|
|
|
u_int i;
|
|
|
|
|
|
|
|
assert(t->in_syscall == 0);
|
|
|
|
assert(t->cs.number == 0);
|
2016-12-06 00:39:00 +00:00
|
|
|
assert(t->cs.sc == NULL);
|
2015-09-30 19:13:32 +00:00
|
|
|
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;
|
|
|
|
}
|
2007-04-10 04:03:34 +00:00
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
static void
|
|
|
|
free_syscall(struct threadinfo *t)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-03-09 18:45:41 +00:00
|
|
|
enter_syscall(struct trussinfo *info, struct threadinfo *t,
|
|
|
|
struct ptrace_lwpinfo *pl)
|
2015-09-30 19:13:32 +00:00
|
|
|
{
|
|
|
|
struct syscall *sc;
|
|
|
|
u_int i, narg;
|
|
|
|
|
|
|
|
alloc_syscall(t, pl);
|
|
|
|
narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args));
|
2019-07-16 22:59:15 +00:00
|
|
|
if (narg != 0 && ptrace(PT_GET_SC_ARGS, t->tid, (caddr_t)t->cs.args,
|
|
|
|
sizeof(t->cs.args)) != 0) {
|
2015-09-30 19:13:32 +00:00
|
|
|
free_syscall(t);
|
2012-09-12 13:06:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-12-06 00:39:00 +00:00
|
|
|
sc = get_syscall(t, t->cs.number, narg);
|
|
|
|
if (sc->unknown)
|
2015-09-30 19:13:32 +00:00
|
|
|
fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n",
|
|
|
|
t->proc->abi->type, t->cs.number);
|
|
|
|
|
2021-03-04 18:28:25 +00:00
|
|
|
t->cs.nargs = sc->decode.nargs;
|
|
|
|
assert(sc->decode.nargs <= nitems(t->cs.s_args));
|
2012-09-02 11:03:18 +00:00
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
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 DEBUG
|
2016-12-06 00:39:00 +00:00
|
|
|
fprintf(stderr, "syscall %s(", sc->name);
|
2015-09-30 19:13:32 +00:00
|
|
|
#endif
|
2016-12-06 00:39:00 +00:00
|
|
|
for (i = 0; i < t->cs.nargs; i++) {
|
2015-09-30 19:13:32 +00:00
|
|
|
#if DEBUG
|
2021-03-04 18:28:25 +00:00
|
|
|
fprintf(stderr, "0x%lx%s",
|
|
|
|
t->cs.args[sc->decode.args[i].offset],
|
2016-12-06 00:39:00 +00:00
|
|
|
i < (t->cs.nargs - 1) ? "," : "");
|
2015-09-30 19:13:32 +00:00
|
|
|
#endif
|
2021-03-04 18:28:25 +00:00
|
|
|
if (!(sc->decode.args[i].type & OUT)) {
|
|
|
|
t->cs.s_args[i] = print_arg(&sc->decode.args[i],
|
2019-07-16 22:59:15 +00:00
|
|
|
t->cs.args, NULL, info);
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
2016-12-06 00:39:00 +00:00
|
|
|
}
|
2015-09-30 19:13:32 +00:00
|
|
|
#if DEBUG
|
2016-12-06 00:39:00 +00:00
|
|
|
fprintf(stderr, ")\n");
|
2015-09-30 19:13:32 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &t->before);
|
|
|
|
}
|
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
/*
|
|
|
|
* When a thread exits voluntarily (including when a thread calls
|
|
|
|
* exit() to trigger a process exit), the thread's internal state
|
|
|
|
* holds the arguments passed to the exit system call. When the
|
|
|
|
* thread's exit is reported, log that system call without a return
|
|
|
|
* value.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
thread_exit_syscall(struct trussinfo *info)
|
|
|
|
{
|
|
|
|
struct threadinfo *t;
|
|
|
|
|
|
|
|
t = info->curthread;
|
|
|
|
if (!t->in_syscall)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &t->after);
|
|
|
|
|
|
|
|
print_syscall_ret(info, 0, NULL);
|
|
|
|
free_syscall(t);
|
|
|
|
}
|
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
static void
|
|
|
|
exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
|
|
|
|
{
|
|
|
|
struct threadinfo *t;
|
|
|
|
struct procinfo *p;
|
|
|
|
struct syscall *sc;
|
2019-07-16 22:59:15 +00:00
|
|
|
struct ptrace_sc_ret psr;
|
2015-09-30 19:13:32 +00:00
|
|
|
u_int i;
|
|
|
|
|
|
|
|
t = info->curthread;
|
|
|
|
if (!t->in_syscall)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &t->after);
|
|
|
|
p = t->proc;
|
2019-07-16 22:59:15 +00:00
|
|
|
if (ptrace(PT_GET_SC_RET, t->tid, (caddr_t)&psr, sizeof(psr)) != 0) {
|
2015-09-30 19:13:32 +00:00
|
|
|
free_syscall(t);
|
2007-04-10 04:03:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-09-30 19:13:32 +00:00
|
|
|
|
|
|
|
sc = t->cs.sc;
|
2015-10-05 18:08:35 +00:00
|
|
|
/*
|
|
|
|
* Here, we only look for arguments that have OUT masked in --
|
|
|
|
* otherwise, they were handled in enter_syscall().
|
|
|
|
*/
|
2021-03-04 18:28:25 +00:00
|
|
|
for (i = 0; i < sc->decode.nargs; i++) {
|
2015-10-05 18:08:35 +00:00
|
|
|
char *temp;
|
|
|
|
|
2021-03-04 18:28:25 +00:00
|
|
|
if (sc->decode.args[i].type & OUT) {
|
2015-10-05 18:08:35 +00:00
|
|
|
/*
|
|
|
|
* If an error occurred, then don't bother
|
|
|
|
* getting the data; it may not be valid.
|
|
|
|
*/
|
2019-07-16 22:59:15 +00:00
|
|
|
if (psr.sr_error != 0) {
|
2015-10-05 18:08:35 +00:00
|
|
|
asprintf(&temp, "0x%lx",
|
2022-03-28 18:43:03 +00:00
|
|
|
(long)t->cs.args[sc->decode.args[i].offset]);
|
2015-10-05 18:08:35 +00:00
|
|
|
} else {
|
2021-03-04 18:28:25 +00:00
|
|
|
temp = print_arg(&sc->decode.args[i],
|
2019-07-16 22:59:15 +00:00
|
|
|
t->cs.args, psr.sr_retval, info);
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
2015-10-05 18:08:35 +00:00
|
|
|
t->cs.s_args[i] = temp;
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-16 22:59:15 +00:00
|
|
|
print_syscall_ret(info, psr.sr_error, psr.sr_retval);
|
2015-09-30 19:13:32 +00:00
|
|
|
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) {
|
2016-03-09 18:45:41 +00:00
|
|
|
assert(LIST_NEXT(LIST_FIRST(&p->threadlist), entries) == NULL);
|
2015-09-30 19:13:32 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-23 19:56:29 +00:00
|
|
|
int
|
|
|
|
print_line_prefix(struct trussinfo *info)
|
2015-09-30 19:13:32 +00:00
|
|
|
{
|
|
|
|
struct timespec timediff;
|
2016-02-23 19:56:29 +00:00
|
|
|
struct threadinfo *t;
|
|
|
|
int len;
|
2015-09-30 19:13:32 +00:00
|
|
|
|
2016-02-23 19:56:29 +00:00
|
|
|
len = 0;
|
|
|
|
t = info->curthread;
|
|
|
|
if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) {
|
|
|
|
if (info->flags & FOLLOWFORKS)
|
|
|
|
len += fprintf(info->outfile, "%5d", t->proc->pid);
|
|
|
|
if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) ==
|
|
|
|
(FOLLOWFORKS | DISPLAYTIDS))
|
|
|
|
len += fprintf(info->outfile, " ");
|
|
|
|
if (info->flags & DISPLAYTIDS)
|
|
|
|
len += fprintf(info->outfile, "%6d", t->tid);
|
|
|
|
len += fprintf(info->outfile, ": ");
|
|
|
|
}
|
2015-09-30 19:13:32 +00:00
|
|
|
if (info->flags & ABSOLUTETIMESTAMPS) {
|
Make timespecadd(3) and friends public
The timespecadd(3) family of macros were imported from NetBSD back in
r35029. However, they were initially guarded by #ifdef _KERNEL. In the
meantime, we have grown at least 28 syscalls that use timespecs in some
way, leading many programs both inside and outside of the base system to
redefine those macros. It's better just to make the definitions public.
Our kernel currently defines two-argument versions of timespecadd and
timespecsub. NetBSD, OpenBSD, and FreeDesktop.org's libbsd, however, define
three-argument versions. Solaris also defines a three-argument version, but
only in its kernel. This revision changes our definition to match the
common three-argument version.
Bump _FreeBSD_version due to the breaking KPI change.
Discussed with: cem, jilles, ian, bde
Differential Revision: https://reviews.freebsd.org/D14725
2018-07-30 15:46:40 +00:00
|
|
|
timespecsub(&t->after, &info->start_time, &timediff);
|
2016-02-23 19:56:29 +00:00
|
|
|
len += fprintf(info->outfile, "%jd.%09ld ",
|
|
|
|
(intmax_t)timediff.tv_sec, timediff.tv_nsec);
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
|
|
|
if (info->flags & RELATIVETIMESTAMPS) {
|
Make timespecadd(3) and friends public
The timespecadd(3) family of macros were imported from NetBSD back in
r35029. However, they were initially guarded by #ifdef _KERNEL. In the
meantime, we have grown at least 28 syscalls that use timespecs in some
way, leading many programs both inside and outside of the base system to
redefine those macros. It's better just to make the definitions public.
Our kernel currently defines two-argument versions of timespecadd and
timespecsub. NetBSD, OpenBSD, and FreeDesktop.org's libbsd, however, define
three-argument versions. Solaris also defines a three-argument version, but
only in its kernel. This revision changes our definition to match the
common three-argument version.
Bump _FreeBSD_version due to the breaking KPI change.
Discussed with: cem, jilles, ian, bde
Differential Revision: https://reviews.freebsd.org/D14725
2018-07-30 15:46:40 +00:00
|
|
|
timespecsub(&t->after, &t->before, &timediff);
|
2016-02-23 19:56:29 +00:00
|
|
|
len += fprintf(info->outfile, "%jd.%09ld ",
|
|
|
|
(intmax_t)timediff.tv_sec, timediff.tv_nsec);
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
2016-02-23 19:56:29 +00:00
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
2016-03-09 18:45:41 +00:00
|
|
|
static void
|
|
|
|
report_thread_death(struct trussinfo *info)
|
|
|
|
{
|
|
|
|
struct threadinfo *t;
|
|
|
|
|
|
|
|
t = info->curthread;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &t->after);
|
|
|
|
print_line_prefix(info);
|
|
|
|
fprintf(info->outfile, "<thread %ld exited>\n", (long)t->tid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
report_thread_birth(struct trussinfo *info)
|
|
|
|
{
|
|
|
|
struct threadinfo *t;
|
|
|
|
|
|
|
|
t = info->curthread;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &t->after);
|
|
|
|
t->before = t->after;
|
|
|
|
print_line_prefix(info);
|
|
|
|
fprintf(info->outfile, "<new thread %ld>\n", (long)t->tid);
|
|
|
|
}
|
|
|
|
|
2016-02-23 19:56:29 +00:00
|
|
|
static void
|
|
|
|
report_exit(struct trussinfo *info, siginfo_t *si)
|
|
|
|
{
|
|
|
|
struct threadinfo *t;
|
|
|
|
|
|
|
|
t = info->curthread;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &t->after);
|
|
|
|
print_line_prefix(info);
|
2015-09-30 19:13:32 +00:00
|
|
|
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
|
2016-02-23 19:56:29 +00:00
|
|
|
report_new_child(struct trussinfo *info)
|
2015-09-30 19:13:32 +00:00
|
|
|
{
|
2016-02-23 19:56:29 +00:00
|
|
|
struct threadinfo *t;
|
2015-09-30 19:13:32 +00:00
|
|
|
|
2016-02-23 19:56:29 +00:00
|
|
|
t = info->curthread;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &t->after);
|
|
|
|
t->before = t->after;
|
|
|
|
print_line_prefix(info);
|
2015-09-30 19:13:32 +00:00
|
|
|
fprintf(info->outfile, "<new process>\n");
|
|
|
|
}
|
|
|
|
|
2017-08-30 15:45:23 +00:00
|
|
|
void
|
2017-08-28 02:42:20 +00:00
|
|
|
decode_siginfo(FILE *fp, siginfo_t *si)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
fprintf(fp, " code=");
|
|
|
|
str = sysdecode_sigcode(si->si_signo, si->si_code);
|
|
|
|
if (str == NULL)
|
|
|
|
fprintf(fp, "%d", si->si_code);
|
|
|
|
else
|
|
|
|
fprintf(fp, "%s", str);
|
|
|
|
switch (si->si_code) {
|
|
|
|
case SI_NOINFO:
|
|
|
|
break;
|
|
|
|
case SI_QUEUE:
|
|
|
|
fprintf(fp, " value=%p", si->si_value.sival_ptr);
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case SI_USER:
|
|
|
|
case SI_LWP:
|
|
|
|
fprintf(fp, " pid=%jd uid=%jd", (intmax_t)si->si_pid,
|
|
|
|
(intmax_t)si->si_uid);
|
|
|
|
break;
|
|
|
|
case SI_TIMER:
|
|
|
|
fprintf(fp, " value=%p", si->si_value.sival_ptr);
|
|
|
|
fprintf(fp, " timerid=%d", si->si_timerid);
|
|
|
|
fprintf(fp, " overrun=%d", si->si_overrun);
|
|
|
|
if (si->si_errno != 0)
|
|
|
|
fprintf(fp, " errno=%d", si->si_errno);
|
|
|
|
break;
|
|
|
|
case SI_ASYNCIO:
|
|
|
|
fprintf(fp, " value=%p", si->si_value.sival_ptr);
|
|
|
|
break;
|
|
|
|
case SI_MESGQ:
|
|
|
|
fprintf(fp, " value=%p", si->si_value.sival_ptr);
|
|
|
|
fprintf(fp, " mqd=%d", si->si_mqd);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
switch (si->si_signo) {
|
|
|
|
case SIGILL:
|
|
|
|
case SIGFPE:
|
|
|
|
case SIGSEGV:
|
|
|
|
case SIGBUS:
|
|
|
|
fprintf(fp, " trapno=%d", si->si_trapno);
|
|
|
|
fprintf(fp, " addr=%p", si->si_addr);
|
|
|
|
break;
|
|
|
|
case SIGCHLD:
|
|
|
|
fprintf(fp, " pid=%jd uid=%jd", (intmax_t)si->si_pid,
|
|
|
|
(intmax_t)si->si_uid);
|
|
|
|
fprintf(fp, " status=%d", si->si_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
report_signal(struct trussinfo *info, siginfo_t *si, struct ptrace_lwpinfo *pl)
|
2015-09-30 19:13:32 +00:00
|
|
|
{
|
2016-02-23 19:56:29 +00:00
|
|
|
struct threadinfo *t;
|
Move mksubr from kdump into libsysdecode.
Restructure this script so that it generates a header of tables instead
of a source file. The tables are included in a flags.c source file which
provides functions to decode various system call arguments.
For functions that decode an enumeration, the function returns a pointer
to a string for known values and NULL for unknown values.
For functions that do more complex decoding (typically of a bitmask), the
function accepts a pointer to a FILE object (open_memstream() can be used
as a string builder) to which decoded values are written. If the
function operates on a bitmask, the function returns true if any bits
were decoded or false if the entire value was valid. Additionally, the
third argument accepts a pointer to a value to which any undecoded bits
are stored. This pointer can be NULL if the caller doesn't care about
remaining bits.
Convert kdump over to using decoder functions from libsysdecode instead of
mksubr. truss also uses decoders from libsysdecode instead of private
lookup tables, though lookup tables for objects not decoded by kdump remain
in truss for now. Eventually most of these tables should move into
libsysdecode as the automated table generation approach from mksubr is
less stale than the static tables in truss.
Some changes have been made to truss and kdump output:
- The flags passed to open() are now properly decoded in that one of
O_RDONLY, O_RDWR, O_WRONLY, or O_EXEC is always included in a decoded
mask.
- Optional arguments to open(), openat(), and fcntl() are only printed
in kdump if they exist (e.g. the mode is only printed for open() if
O_CREAT is set in the flags).
- Print argument to F_GETLK/SETLK/SETLKW in kdump as a pointer, not int.
- Include all procctl() commands.
- Correctly decode pipe2() flags in truss by not assuming full
open()-like flags with O_RDONLY, etc.
- Decode file flags passed to *chflags() as file flags (UF_* and SF_*)
rather than as a file mode.
- Fix decoding of quotactl() commands by splitting out the two command
components instead of assuming the raw command value matches the
primary command component.
In addition, truss and kdump now build without triggering any warnings.
All of the sysdecode manpages now include the required headers in the
synopsis.
Reviewed by: kib (several older versions), wblock (manpages)
MFC after: 2 months
Differential Revision: https://reviews.freebsd.org/D7847
2016-10-17 22:37:07 +00:00
|
|
|
const char *signame;
|
2015-09-30 19:13:32 +00:00
|
|
|
|
2016-02-23 19:56:29 +00:00
|
|
|
t = info->curthread;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &t->after);
|
|
|
|
print_line_prefix(info);
|
Move mksubr from kdump into libsysdecode.
Restructure this script so that it generates a header of tables instead
of a source file. The tables are included in a flags.c source file which
provides functions to decode various system call arguments.
For functions that decode an enumeration, the function returns a pointer
to a string for known values and NULL for unknown values.
For functions that do more complex decoding (typically of a bitmask), the
function accepts a pointer to a FILE object (open_memstream() can be used
as a string builder) to which decoded values are written. If the
function operates on a bitmask, the function returns true if any bits
were decoded or false if the entire value was valid. Additionally, the
third argument accepts a pointer to a value to which any undecoded bits
are stored. This pointer can be NULL if the caller doesn't care about
remaining bits.
Convert kdump over to using decoder functions from libsysdecode instead of
mksubr. truss also uses decoders from libsysdecode instead of private
lookup tables, though lookup tables for objects not decoded by kdump remain
in truss for now. Eventually most of these tables should move into
libsysdecode as the automated table generation approach from mksubr is
less stale than the static tables in truss.
Some changes have been made to truss and kdump output:
- The flags passed to open() are now properly decoded in that one of
O_RDONLY, O_RDWR, O_WRONLY, or O_EXEC is always included in a decoded
mask.
- Optional arguments to open(), openat(), and fcntl() are only printed
in kdump if they exist (e.g. the mode is only printed for open() if
O_CREAT is set in the flags).
- Print argument to F_GETLK/SETLK/SETLKW in kdump as a pointer, not int.
- Include all procctl() commands.
- Correctly decode pipe2() flags in truss by not assuming full
open()-like flags with O_RDONLY, etc.
- Decode file flags passed to *chflags() as file flags (UF_* and SF_*)
rather than as a file mode.
- Fix decoding of quotactl() commands by splitting out the two command
components instead of assuming the raw command value matches the
primary command component.
In addition, truss and kdump now build without triggering any warnings.
All of the sysdecode manpages now include the required headers in the
synopsis.
Reviewed by: kib (several older versions), wblock (manpages)
MFC after: 2 months
Differential Revision: https://reviews.freebsd.org/D7847
2016-10-17 22:37:07 +00:00
|
|
|
signame = sysdecode_signal(si->si_status);
|
|
|
|
if (signame == NULL)
|
|
|
|
signame = "?";
|
2017-08-28 02:42:20 +00:00
|
|
|
fprintf(info->outfile, "SIGNAL %u (%s)", si->si_status, signame);
|
|
|
|
if (pl->pl_event == PL_EVENT_SIGNAL && pl->pl_flags & PL_FLAG_SI)
|
|
|
|
decode_siginfo(info->outfile, &pl->pl_siginfo);
|
|
|
|
fprintf(info->outfile, "\n");
|
|
|
|
|
2015-09-30 19:13:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
2016-03-09 18:45:41 +00:00
|
|
|
if ((info->flags & COUNTONLY) == 0) {
|
|
|
|
if (si.si_code == CLD_EXITED)
|
|
|
|
thread_exit_syscall(info);
|
2015-09-30 19:13:32 +00:00
|
|
|
report_exit(info, &si);
|
2016-03-09 18:45:41 +00:00
|
|
|
}
|
2015-09-30 19:13:32 +00:00
|
|
|
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) {
|
2016-03-09 18:45:41 +00:00
|
|
|
new_proc(info, si.si_pid, pl.pl_lwpid);
|
2015-09-30 19:13:32 +00:00
|
|
|
assert(LIST_FIRST(&info->proclist)->abi !=
|
|
|
|
NULL);
|
2016-03-09 18:45:41 +00:00
|
|
|
} else if (pl.pl_flags & PL_FLAG_BORN)
|
|
|
|
new_thread(find_proc(info, si.si_pid),
|
|
|
|
pl.pl_lwpid);
|
2015-09-30 19:13:32 +00:00
|
|
|
find_thread(info, si.si_pid, pl.pl_lwpid);
|
|
|
|
|
2015-10-05 21:39:07 +00:00
|
|
|
if (si.si_status == SIGTRAP &&
|
2016-03-09 18:45:41 +00:00
|
|
|
(pl.pl_flags & (PL_FLAG_BORN|PL_FLAG_EXITED|
|
|
|
|
PL_FLAG_SCE|PL_FLAG_SCX)) != 0) {
|
|
|
|
if (pl.pl_flags & PL_FLAG_BORN) {
|
|
|
|
if ((info->flags & COUNTONLY) == 0)
|
|
|
|
report_thread_birth(info);
|
|
|
|
} else if (pl.pl_flags & PL_FLAG_EXITED) {
|
|
|
|
if ((info->flags & COUNTONLY) == 0)
|
|
|
|
report_thread_death(info);
|
|
|
|
free_thread(info->curthread);
|
|
|
|
info->curthread = NULL;
|
|
|
|
} else if (pl.pl_flags & PL_FLAG_SCE)
|
|
|
|
enter_syscall(info, info->curthread, &pl);
|
2015-09-30 19:13:32 +00:00
|
|
|
else if (pl.pl_flags & PL_FLAG_SCX)
|
|
|
|
exit_syscall(info, &pl);
|
|
|
|
pending_signal = 0;
|
|
|
|
} else if (pl.pl_flags & PL_FLAG_CHILD) {
|
|
|
|
if ((info->flags & COUNTONLY) == 0)
|
2016-02-23 19:56:29 +00:00
|
|
|
report_new_child(info);
|
2015-09-30 19:13:32 +00:00
|
|
|
pending_signal = 0;
|
|
|
|
} else {
|
|
|
|
if ((info->flags & NOSIGS) == 0)
|
2017-08-28 02:42:20 +00:00
|
|
|
report_signal(info, &si, &pl);
|
2015-09-30 19:13:32 +00:00
|
|
|
pending_signal = si.si_status;
|
2011-12-04 18:43:09 +00:00
|
|
|
}
|
2015-09-30 19:13:32 +00:00
|
|
|
ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1,
|
|
|
|
pending_signal);
|
|
|
|
break;
|
|
|
|
case CLD_STOPPED:
|
|
|
|
errx(1, "waitid reported CLD_STOPPED");
|
|
|
|
case CLD_CONTINUED:
|
2007-04-10 04:03:34 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|