diff options
author | Robert Mustacchi <rm@fingolfin.org> | 2021-07-31 18:32:39 -0700 |
---|---|---|
committer | Robert Mustacchi <rm@fingolfin.org> | 2021-11-11 14:12:38 -0800 |
commit | 8e458de0baeb1fee50643403223bc7e909a48464 (patch) | |
tree | 56fb55c9127badcfdd124858bc930e1f7ba693a5 /usr/src/test | |
parent | 1dee82f4f45d5f7651c78ce447f9829386d9d9c5 (diff) | |
download | illumos-gate-8e458de0baeb1fee50643403223bc7e909a48464.tar.gz |
13925 core files should include DWARF
Reviewed by: Rich Lowe <richlowe@richlowe.net>
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Adam Leventhal <adam.leventhal@gmail.com>
Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/test')
18 files changed, 1100 insertions, 0 deletions
diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run index 4824a8328b..426433b7a5 100644 --- a/usr/src/test/os-tests/runfiles/default.run +++ b/usr/src/test/os-tests/runfiles/default.run @@ -126,3 +126,8 @@ post = ksensor_fini [/opt/os-tests/tests/stackalign] tests = ['stackalign.32', 'stackalign.64'] + +[/opt/os-tests/tests/cores] +user = root +pre = core_prereqs +tests = ['coretests'] diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile index fdb8fe302c..059fc2ddd8 100644 --- a/usr/src/test/os-tests/tests/Makefile +++ b/usr/src/test/os-tests/tests/Makefile @@ -19,6 +19,7 @@ SUBDIRS_i386 = i386 imc SUBDIRS = \ + cores \ ddi_ufm \ file-locking \ ksensor \ diff --git a/usr/src/test/os-tests/tests/cores/Makefile b/usr/src/test/os-tests/tests/cores/Makefile new file mode 100644 index 0000000000..dccb694ae9 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/Makefile @@ -0,0 +1,22 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +.PARALLEL: $(SUBDIRS) + +SUBDIRS = libdumper dumper scripts secmapper + +include $(SRC)/test/Makefile.com + +dumper: libdumper diff --git a/usr/src/test/os-tests/tests/cores/Makefile.com b/usr/src/test/os-tests/tests/cores/Makefile.com new file mode 100644 index 0000000000..daf8207a43 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/Makefile.com @@ -0,0 +1,17 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +ROOTOPTDIR = $(ROOT)/opt/os-tests/tests +ROOTOPTCORE = $(ROOTOPTDIR)/cores diff --git a/usr/src/test/os-tests/tests/cores/Makefile.targ b/usr/src/test/os-tests/tests/cores/Makefile.targ new file mode 100644 index 0000000000..9511df96ff --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/Makefile.targ @@ -0,0 +1,48 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +$(ROOTOPTDIR): + $(INS.dir) + +$(ROOTOPTCORE): $(ROOTOPTDIR) + $(INS.dir) + +$(ROOTOPTCORE)/%: % + $(INS.file) + +$(ROOTOPTCORE)/%: %.ksh + $(INS.rename) + +%.32.o: %.c + $(COMPILE.c) $< -o $@ + $(POST_PROCESS_O) + +%.64.o: %.c + $(COMPILE64.c) $< -o $@ + $(POST_PROCESS_O) + +%.64: %.64.o + $(LINK64.c) -o $@ $< $(LDLIBS64) + $(POST_PROCESS) + +%.32: %.32.o + $(LINK.c) -o $@ $< $(LDLIBS) + $(POST_PROCESS) + +clobber: clean + $(RM) $(PROGS32) $(PROGS64) + +clean: + $(RM) $(ALLOBJS) diff --git a/usr/src/test/os-tests/tests/cores/dumper/Makefile b/usr/src/test/os-tests/tests/cores/dumper/Makefile new file mode 100644 index 0000000000..4e193e1193 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/dumper/Makefile @@ -0,0 +1,57 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +PROGS = dumper + +PROGS32 = $(PROGS:%=%.32) +PROGS64 = $(PROGS:%=%.64) +ALLOBJS = $(PROGS32:%=%.o) $(PROGS64:%=%.o) + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/Makefile.ctf +include ../Makefile.com + +ROOTOPTPROGS = $(PROGS32:%=$(ROOTOPTCORE)/%) \ + $(PROGS64:%=$(ROOTOPTCORE)/%) + +LDLIBS += -lproc -L$(ROOTOPTCORE) -ldumper -R\$$ORIGIN +LDLIBS64 += -lproc -L$(ROOTOPTCORE)/$(MACH64) -ldumper -R\$$ORIGIN/$(MACH64) + +# +# We need to explicitly set the objects for some of our programs with +# CTF so that way we can make sure that we have what we need. +# +dumper.32 := OBJS = dumper.32.o +dumper.64 := OBJS = dumper.32.o + +# +# This is admittedly, a bit gross. In particular we need to make sure +# that we have debug information in the following programs. +# +STRIP_STABS = /bin/true + +.KEEP_STATE: + +all: $(PROGS32) $(PROGS64) + +install: $(ROOTOPTPROGS) + +clean: + +$(ROOTOPTPROGS): $(PROGS32) $(PROGS64) $(ROOTOPTCORE) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/test/os-tests/tests/cores/dumper/dumper.c b/usr/src/test/os-tests/tests/cores/dumper/dumper.c new file mode 100644 index 0000000000..9539220139 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/dumper/dumper.c @@ -0,0 +1,64 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Oxide Computer Company + */ + +/* + * This program is meant to be a victim process. It will set up its core content + * and location into the specific place we indicate in its arguments and then + * sleep until we gcore and ABRT it. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/corectl.h> +#include <libproc.h> +#include <signal.h> + +extern int which_ff(uint32_t, uint32_t); + +int +main(int argc, char *argv[]) +{ + pid_t me = getpid(); + core_content_t content; + sigset_t set = { 0 }; + + if (argc != 3) { + errx(EXIT_FAILURE, "<content> <dump path>"); + } + + if (proc_str2content(argv[1], &content) != 0) { + err(EXIT_FAILURE, "failed to parse content %s", argv[1]); + } + + if (core_set_process_content(&content, me) != 0) { + err(EXIT_FAILURE, "failed to set core content to %s", argv[1]); + } + + if (core_set_process_path(argv[2], strlen(argv[2]) + 1, me) != 0) { + err(EXIT_FAILURE, "failed to set core path to %s", argv[2]); + } + + /* + * Call our library function to make sure it's present before we go and + * sleep. + */ + (void) which_ff(6, 10); + + for (;;) { + (void) sigsuspend(&set); + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/cores/libdumper/Makefile b/usr/src/test/os-tests/tests/cores/libdumper/Makefile new file mode 100644 index 0000000000..b807402808 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/libdumper/Makefile @@ -0,0 +1,41 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +install := TARGET = install + +.KEEP_STATE: + +all clean clobber: $(SUBDIRS) + +install: $(SUBDIRS) + +install_h: + +check: $(CHECKHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/test/os-tests/tests/cores/libdumper/Makefile.com b/usr/src/test/os-tests/tests/cores/libdumper/Makefile.com new file mode 100644 index 0000000000..3a985d3965 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/libdumper/Makefile.com @@ -0,0 +1,44 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +LIBRARY = libdumper.a +VERS = .1 +OBJECTS = libdumper.o + +include $(SRC)/lib/Makefile.lib +include ../../Makefile.com + +ROOTLIBDIR = $(ROOTOPTCORE) +ROOTLIBDIR64 = $(ROOTOPTCORE)/$(MACH64) + +LIBS = $(DYNLIB) +LDLIBS += -lc +SRCDIR = ../common + +# +# This program needs to deliver DWARF data for debug purposes. Therefore +# we override the strip to make sure that we can get that. +# +STRIP_STABS = /bin/true + + +$(ROOTLIBDIR64): $(ROOTLIBDIR) + $(INS.dir) + +.KEEP_STATE: + +all: $(LIBS) + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/test/os-tests/tests/cores/libdumper/amd64/Makefile b/usr/src/test/os-tests/tests/cores/libdumper/amd64/Makefile new file mode 100644 index 0000000000..09690cb7b3 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/libdumper/amd64/Makefile @@ -0,0 +1,19 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +install: all $(ROOTLIBDIR64) .WAIT $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/test/os-tests/tests/cores/libdumper/common/libdumper.c b/usr/src/test/os-tests/tests/cores/libdumper/common/libdumper.c new file mode 100644 index 0000000000..027095a471 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/libdumper/common/libdumper.c @@ -0,0 +1,36 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Oxide Computer Company + */ + +/* + * This is a dummy library that basically ensures we have yet another thing with + * CTF and DWARF data when we're testing core dumps. + */ + +#include <err.h> +#include <inttypes.h> +#include <stdlib.h> + +const char *message_in_a_bottle = "Here's something that hopefully is rodata"; + +int +which_ff(uint32_t a, uint32_t b) +{ + if (a == 6 && b == 7) { + warnx("some debates are best left to forums"); + abort(); + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/cores/libdumper/common/mapfile-vers b/usr/src/test/os-tests/tests/cores/libdumper/common/mapfile-vers new file mode 100644 index 0000000000..e02f876869 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/libdumper/common/mapfile-vers @@ -0,0 +1,44 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +$mapfile_version 2 + +SYMBOL_VERSION ILLUMOSprivate { + global: + message_in_a_bottle { + ASSERT = { + TYPE = OBJECT; + SIZE = addrsize; + }; + }; + + which_ff; + local: + *; +}; diff --git a/usr/src/test/os-tests/tests/cores/libdumper/i386/Makefile b/usr/src/test/os-tests/tests/cores/libdumper/i386/Makefile new file mode 100644 index 0000000000..0af99e030c --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/libdumper/i386/Makefile @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide computer Company +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) diff --git a/usr/src/test/os-tests/tests/cores/scripts/Makefile b/usr/src/test/os-tests/tests/cores/scripts/Makefile new file mode 100644 index 0000000000..2e222b41c2 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/scripts/Makefile @@ -0,0 +1,36 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +SCRIPTS = core_prereqs coretests + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/Makefile.ctf +include ../Makefile.com + +ROOTOPTPROGS = $(SCRIPTS:%=$(ROOTOPTCORE)/%) + +.KEEP_STATE: + +all: $(PROGS32) $(PROGS64) + +install: $(ROOTOPTPROGS) + +$(ROOTOPTPROGS): $(ROOTOPTCORE) + +clean: + +FRC: + +include ../Makefile.targ diff --git a/usr/src/test/os-tests/tests/cores/scripts/core_prereqs.ksh b/usr/src/test/os-tests/tests/cores/scripts/core_prereqs.ksh new file mode 100644 index 0000000000..490c47e205 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/scripts/core_prereqs.ksh @@ -0,0 +1,31 @@ +#!/usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +# +# The core tests require that we have per-process core dumps enabled. +# This script is used as the pre-requisite in the test runner to verify +# that fact. +# + +set -o pipefail + +if coreadm | grep -q 'per-process core dumps: enabled'; then + exit 0 +fi + +echo "per -process core dumps are not enabled, skipping test" >&2 +exit 1 diff --git a/usr/src/test/os-tests/tests/cores/scripts/coretests.ksh b/usr/src/test/os-tests/tests/cores/scripts/coretests.ksh new file mode 100644 index 0000000000..9e7f524070 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/scripts/coretests.ksh @@ -0,0 +1,135 @@ +#!/usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +# +# The goal of this test suite is to test certain aspects of core dump +# generation and different core contents being specified. The +# 'dumper.32' and 'dumper.64' programs are designed to be told what to +# set a core content and path to, after which point we use both gcore +# and the kernel to generate a core dump for the file and verify that it +# has what we expect. The verification is done by the secmapper program. +# + +unalias -a +set -o pipefail + +core_arg0="$(basename $0)" +core_dir="$(dirname $0)" +core_dumper32="$core_dir/dumper.32" +core_dumper64="$core_dir/dumper.64" +core_checker="$core_dir/secmapper" + +core_tmpdir="/tmp/coretest.$$" +core_exit=0 + +# +# This array describes the different types of core contents that we're +# going to try and generate and check against. +# +core_contents="none +ctf +debug +symtab +ctf+debug+symtab +anon+data+ctf+debug+symtab +default +default-ctf-debug-symtab +default+debug +default-symtab" + +warn() +{ + typeset msg="$*" + echo "TEST FAILED: $msg" >&2 + core_exit=1 +} + +core_dump_one() +{ + typeset prog="$1" + typeset pbase=$(basename $prog) + typeset cont="$2" + typeset kpath="$3" + typeset gpath="$4" + typeset pid= + + $prog "$cont" "$kpath" & + pid=$! + if (( $? != 0 )); then + warn "failed to spawn $core_dumper32: $cont $kpath" + return 1 + fi + + # + # This is racy, but probably should be a reasonable amount of + # time for dumper to be ready. + # + for ((i = 0; i < 10; i++)) { + if pstack $pid | grep -q 'fsigsuspend'; then + break + fi + } + + if ! gcore -o "$gpath" -c "$cont" $pid >/dev/null; then + warn "failed to gcore $pid: $prog $cont $kpath" + fi + + kill -ABRT $pid + fg %1 + + # + # Since we have the pid, go through and check this now. + # + if $core_checker $core_tmpdir/*.kernel.$c.$pid $c; then + printf "TEST PASSED: kernel %s %s\n" "$pbase" "$c" + else + warn "checker failed for kernel $c" + fi + + if $core_checker $core_tmpdir/*.gcore.$c.$pid $c; then + printf "TEST PASSED: gcore %s %s\n" "$pbase" "$c" + else + warn "checker failed for gcore of $c" + fi +} + +if [[ ! -x "$core_dumper32" || ! -x "$core_dumper64" || \ + ! -f "$core_checker" ]]; then + warn "missing expected files" + exit $core_exit +fi + +if ! mkdir "$core_tmpdir"; then + warn "failed to create temporary directory: $core_tmpdir" + exit $core_exit +fi + +for c in $core_contents; do + kpattern="$core_tmpdir/%f.kernel.$c.%p" + gpattern="$core_tmpdir/%f.gcore.$c" + + core_dump_one "$core_dumper32" "$c" "$kpattern" "$gpattern" + core_dump_one "$core_dumper64" "$c" "$kpattern" "$gpattern" + +done + +if (( core_exit == 0 )); then + printf "All tests passed successfully\n" +fi + +rm -rf $core_tmpdir +exit $core_exit diff --git a/usr/src/test/os-tests/tests/cores/secmapper/Makefile b/usr/src/test/os-tests/tests/cores/secmapper/Makefile new file mode 100644 index 0000000000..84a28a56b8 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/secmapper/Makefile @@ -0,0 +1,48 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +PROG = secmapper +OBJS = secmapper.o + +# +# These are so the common makefile targets will clean things up. +# +ALLOBJS = $(OBJS) +PROGS64 = $(PROG) + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/Makefile.cmd.64 +include ../Makefile.com + +ROOTOPTPROGS = $(PROG:%=$(ROOTOPTCORE)/%) + +LDLIBS += -lproc -lelf +CSTD = $(GNU_C99) + +.KEEP_STATE: + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) -o $(PROG) $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +install: $(ROOTOPTPROGS) + +$(ROOTOPTPROGS): $(PROG) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/test/os-tests/tests/cores/secmapper/secmapper.c b/usr/src/test/os-tests/tests/cores/secmapper/secmapper.c new file mode 100644 index 0000000000..87800a5352 --- /dev/null +++ b/usr/src/test/os-tests/tests/cores/secmapper/secmapper.c @@ -0,0 +1,434 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Oxide Computer Company + */ + +/* + * Check that a given core dump generated as part of our test framework has the + * sections that we'd expect. We have here the dumper binary. In that, we expect + * to find the following libraries and sections: + * + * a.out: symtab, ctf, .debug_* (dwarf) + * ld.so.1: symtab + * libc.so: symtab, ctf + * libproc.so: symtab, ctf + * libdumper.so: symtab, ctf, .debug_* (dwarf) + * + * Note, there will also be additional libraries and things here can change over + * time (e.g. deps of libproc, etc.), but we try to ignore them generally + * speaking if we can know enough to do so. + */ + +#include <err.h> +#include <stdlib.h> +#include <libproc.h> +#include <gelf.h> +#include <libelf.h> +#include <limits.h> +#include <string.h> +#include <libgen.h> + +typedef enum { + SECMAP_CTF, + SECMAP_SYMTAB, + SECMAP_DEBUG, + SECMAP_MAX +} secmap_type_t; + +typedef struct secmap_data { + core_content_t sd_content; + const char *sd_name; +} secmap_data_t; + +secmap_data_t secmap_data[SECMAP_MAX] = { + { CC_CONTENT_CTF, ".SUNW_ctf" }, + { CC_CONTENT_SYMTAB, ".symtab" }, + { CC_CONTENT_DEBUG, ".debug_" } +}; + +typedef struct { + uint64_t sm_addr; + char sm_obj[PATH_MAX]; + size_t sm_nfound[SECMAP_MAX]; + Elf *sm_elf; + GElf_Ehdr sm_ehdr; + boolean_t sm_ctf; + boolean_t sm_debug; + boolean_t sm_symtab; +} secmap_t; + +static secmap_t *secmaps; +static size_t secmap_count; +static core_content_t secmap_content; + +static int secmap_exit = EXIT_SUCCESS; + +static void +secmap_fail(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); + secmap_exit = EXIT_FAILURE; +} + + +static void +check_content(core_content_t content, struct ps_prochandle *Pr) +{ + secmap_content = Pcontent(Pr); + + if (secmap_content == CC_CONTENT_INVALID) { + secmap_fail("TEST FAILED: failed to get core content"); + return; + } + + if (secmap_content != content) { + secmap_fail("TEST FAILED: core file contains different " + "content than expected, found 0x%x, expected 0x%x", + secmap_content, content); + } +} + +static secmap_t * +secmap_find(uint64_t addr) +{ + for (size_t i = 0; i < secmap_count; i++) { + if (secmaps[i].sm_addr == addr) { + return (&secmaps[i]); + } + } + + return (NULL); +} + +static void +secmap_matches_content(secmap_type_t type) +{ + boolean_t exist = (secmap_data[type].sd_content & secmap_content) != 0; + boolean_t found = B_FALSE; + + /* + * Dumping CTF data implies that some symbol tables will exist for CTF. + */ + if (type == SECMAP_SYMTAB && (secmap_content & CC_CONTENT_CTF) != 0) { + exist = B_TRUE; + } + + for (size_t i = 0; i < secmap_count; i++) { + if (secmaps[i].sm_nfound[type] != 0) { + found = B_TRUE; + } + } + + if (exist != found) { + secmap_fail("content type mismatch for %s: expected %s, but " + "found %s", secmap_data[type].sd_name, + exist ? "some" : "none", + found ? "some" : "none"); + } +} + +static secmap_t * +secmap_alloc(struct ps_prochandle *Pr, uint64_t addr) +{ + int fd; + secmap_t *sm; + char *base; + + sm = recallocarray(secmaps, secmap_count, secmap_count + 1, + sizeof (secmap_t)); + if (sm == NULL) { + err(EXIT_FAILURE, "TEST FAILED: failed to allocate memory for " + "secmap %zu", secmap_count + 1); + } + + secmaps = sm; + sm = &secmaps[secmap_count]; + sm->sm_addr = addr; + secmap_count++; + + /* + * We also have some tests that we don't expect to have anything here + * because we only include the relevant sections. Experimentally, we + * know that libproc needs both anon and data mappings for this to work. + * So if we don't have both, then we'll not warn on that. + */ + if (Pobjname(Pr, addr, sm->sm_obj, sizeof (sm->sm_obj)) == NULL) { + core_content_t need = CC_CONTENT_ANON | CC_CONTENT_DATA; + + if ((secmap_content & need) == need) { + secmap_fail("TEST FAILURE: object at address 0x%lx " + "has no name", addr); + } + + return (sm); + } + + /* + * Since we have a name, we should be able to open this elf object and + * identify it as well. + */ + fd = open(sm->sm_obj, O_RDONLY); + if (fd < 0) { + err(EXIT_FAILURE, "failed to open object %s", sm->sm_obj); + } + + sm->sm_elf = elf_begin(fd, ELF_C_READ, NULL); + if (sm->sm_elf == NULL) { + err(EXIT_FAILURE, "failed to find open elf object %s: %s", + sm->sm_obj, elf_errmsg(elf_errno())); + } + + if (gelf_getehdr(sm->sm_elf, &sm->sm_ehdr) == NULL) { + err(EXIT_FAILURE, "failed to get ehdr for %s: %s", + sm->sm_obj, elf_errmsg(elf_errno())); + } + + base = basename(sm->sm_obj); + if (strcmp(base, "dumper.32") == 0 || strcmp(base, "dumper.64") == 0) { + sm->sm_debug = sm->sm_symtab = sm->sm_ctf = B_TRUE; + } else if (strcmp(base, "libc.so.1") == 0) { + sm->sm_symtab = sm->sm_ctf = B_TRUE; + } else if (strcmp(base, "ld.so.1") == 0) { + sm->sm_symtab = B_TRUE; + } else if (strcmp(base, "libproc.so.1") == 0) { + sm->sm_symtab = sm->sm_ctf = B_TRUE; + } else if (strcmp(base, "libdumper.so.1") == 0) { + sm->sm_debug = sm->sm_symtab = sm->sm_ctf = B_TRUE; + } else { + sm->sm_symtab = B_TRUE; + } + + return (sm); +} + +static void +secmap_data_cmp(secmap_t *sm, const char *sname, Elf_Scn *scn, GElf_Shdr *shdr) +{ + for (Elf_Scn *comp_scn = elf_nextscn(sm->sm_elf, NULL); + comp_scn != NULL; comp_scn = elf_nextscn(sm->sm_elf, comp_scn)) { + GElf_Shdr comp_shdr; + const char *comp_name; + Elf_Data *src_data, *comp_data; + + if (gelf_getshdr(comp_scn, &comp_shdr) == NULL) { + secmap_fail("failed to load section header from %s " + "during data comparison", sm->sm_obj); + return; + } + + comp_name = elf_strptr(sm->sm_elf, sm->sm_ehdr.e_shstrndx, + comp_shdr.sh_name); + if (comp_name == NULL) { + secmap_fail("failed to load section name from %s " + "with index %lu", sm->sm_obj, comp_shdr.sh_name); + return; + } + + if (strcmp(comp_name, sname) != 0) + continue; + + if (comp_shdr.sh_type != shdr->sh_type || + comp_shdr.sh_addralign != shdr->sh_addralign || + comp_shdr.sh_size != shdr->sh_size || + comp_shdr.sh_entsize != shdr->sh_entsize) { + continue; + } + + if ((src_data = elf_getdata(scn, NULL)) == NULL) { + secmap_fail("failed to load section data from " + "source to compare to %s %s", sm->sm_obj, sname); + return; + } + + if ((comp_data = elf_getdata(comp_scn, NULL)) == NULL) { + secmap_fail("failed to load section data from " + "source to compare to %s %s", sm->sm_obj, sname); + return; + } + + if (comp_data->d_size != src_data->d_size) { + secmap_fail("data size mismatch for %s: %s, core: " + "%zu, file: %zu", sm->sm_obj, sname, + src_data->d_size, comp_data->d_size); + return; + } + + if (memcmp(comp_data->d_buf, src_data->d_buf, + comp_data->d_size) != 0) { + secmap_fail("data mismatch between core and source " + "in %s: %s", sm->sm_obj, sname); + return; + } + + return; + } + + secmap_fail("failed to find matching section for %s in %s", + sname, sm->sm_obj); +} + +static void +secmap_file_check(secmap_t *sm) +{ + if (sm->sm_ctf && (secmap_content & CC_CONTENT_CTF) != 0 && + sm->sm_nfound[SECMAP_CTF] == 0) { + secmap_fail("expected object %s to have CTF, but it doesn't", + sm->sm_obj); + } + + if (sm->sm_symtab && (secmap_content & CC_CONTENT_SYMTAB) != 0 && + sm->sm_nfound[SECMAP_SYMTAB] == 0) { + secmap_fail("expected object %s to have a symbol table, " + "but it doesn't", sm->sm_obj); + } + + if (sm->sm_debug && (secmap_content & CC_CONTENT_DEBUG) != 0 && + sm->sm_nfound[SECMAP_DEBUG] == 0) { + secmap_fail("expected object %s to have debug sections, " + "but it doesn't", sm->sm_obj); + } +} + +int +main(int argc, char *argv[]) +{ + core_content_t content; + struct ps_prochandle *Pr; + int perr, fd; + Elf *elf; + Elf_Scn *scn; + GElf_Ehdr ehdr; + + if (argc != 3) { + warnx("missing required file and core content"); + (void) fprintf(stderr, "Usage: secmapper file content\n"); + exit(EXIT_FAILURE); + } + + if (elf_version(EV_CURRENT) == EV_NONE) { + errx(EXIT_FAILURE, "failed to init libelf"); + } + + Pr = Pgrab_core(argv[1], NULL, PGRAB_RDONLY, &perr); + if (Pr == NULL) { + errx(EXIT_FAILURE, "failed to open %s: %s", argv[1], + Pgrab_error(perr)); + } + + if ((fd = open(argv[1], O_RDONLY)) < 0) { + err(EXIT_FAILURE, "failed to open %s\n", argv[1]); + } + + if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { + errx(EXIT_FAILURE, "failed to open elf file %s: %s", argv[1], + elf_errmsg(elf_errno())); + } + + if (proc_str2content(argv[2], &content) != 0) { + err(EXIT_FAILURE, "failed to parse content %s", argv[2]); + } + + if (gelf_getehdr(elf, &ehdr) == NULL) { + errx(EXIT_FAILURE, "failed to get edr: %s", + elf_errmsg(elf_errno())); + } + + /* + * Before we go futher, make sure that we have the content in this file + * that we expect. + */ + check_content(content, Pr); + + for (scn = elf_nextscn(elf, NULL); scn != NULL; + scn = elf_nextscn(elf, scn)) { + const char *sname; + GElf_Shdr shdr; + size_t index; + secmap_t *secmap; + + index = elf_ndxscn(scn); + if (gelf_getshdr(scn, &shdr) == NULL) { + errx(EXIT_FAILURE, "failed to get section header for " + "shdr %zu: %s", index, elf_errmsg(elf_errno())); + } + + /* + * Skip the strtab. + */ + if (shdr.sh_type == SHT_STRTAB) { + continue; + } + + sname = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); + if (sname == NULL) { + secmap_fail("TEST FAILURE: string name missing for " + "shdr %zu", index); + continue; + } + + /* + * Find or cons up a new secmap for this object. + */ + secmap = secmap_find(shdr.sh_addr); + if (secmap == NULL) { + secmap = secmap_alloc(Pr, shdr.sh_addr); + } + + if (strcmp(sname, ".symtab") == 0) { + secmap->sm_nfound[SECMAP_SYMTAB]++; + } else if (strcmp(sname, ".SUNW_ctf") == 0) { + secmap->sm_nfound[SECMAP_CTF]++; + } else if (strncmp(sname, ".debug_", strlen(".debug_")) == 0) { + secmap->sm_nfound[SECMAP_DEBUG]++; + } else { + continue; + } + + /* + * For one of our three primary sections, make sure that the + * data that is in the core file that we find in it actually + * matches the underlying object. That is, if the secmap + * actually has something here. + */ + if (secmap->sm_elf != NULL) { + secmap_data_cmp(secmap, sname, scn, &shdr); + } + } + + /* + * Now that we have iterated over all of these sections, check and make + * sure certain things are true of them. In particular, go through some + * of the various types of data and make sure it exists at all or + * doesn't based on our core content. + */ + secmap_matches_content(SECMAP_CTF); + secmap_matches_content(SECMAP_SYMTAB); + secmap_matches_content(SECMAP_DEBUG); + + /* + * Finally, if we have enough information to know that we've found + * a file that we know it should at least have a given type of data, + * check for it. Here, it is OK for data to be present we don't expect + * (assuming the core content allows it). This makes this test less + * prone to broader changes in the system. + */ + for (size_t i = 0; i < secmap_count; i++) { + secmap_file_check(&secmaps[i]); + } + + return (secmap_exit); +} |