Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/tests/lib/libc/sys Add a test for verifying procinfo note in...
details: https://anonhg.NetBSD.org/src/rev/76e6d975c49e
branches: trunk
changeset: 1000027:76e6d975c49e
user: mgorny <mgorny%NetBSD.org@localhost>
date: Sun Jun 30 21:20:04 2019 +0000
description:
Add a test for verifying procinfo note inside coredumps.
Add a first test for triggering a core dump in the debugged process
(via PT_DUMPCORE) and verifying it. The test finds procinfo note
and checks its contents.
The core dump is processed through libelf. However, it only provides
for finding all note segments (or sections?). I had to implement
finding and processing individual notes myself. I've added
a core_find_note() function that will be reused in future tests.
Reviewed by kamil.
diffstat:
tests/lib/libc/sys/Makefile | 14 +-
tests/lib/libc/sys/t_ptrace_wait.c | 185 ++++++++++++++++++++++++++++++++++++-
2 files changed, 190 insertions(+), 9 deletions(-)
diffs (258 lines):
diff -r 0117171639c8 -r 76e6d975c49e tests/lib/libc/sys/Makefile
--- a/tests/lib/libc/sys/Makefile Sun Jun 30 19:57:23 2019 +0000
+++ b/tests/lib/libc/sys/Makefile Sun Jun 30 21:20:04 2019 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.56 2019/04/26 20:41:10 maya Exp $
+# $NetBSD: Makefile,v 1.57 2019/06/30 21:20:04 mgorny Exp $
MKMAN= no
@@ -88,12 +88,12 @@
LDADD.t_getpid+= -lpthread
-LDADD.t_ptrace_wait+= -pthread -lm
-LDADD.t_ptrace_wait3+= -pthread -lm
-LDADD.t_ptrace_wait4+= -pthread -lm
-LDADD.t_ptrace_wait6+= -pthread -lm
-LDADD.t_ptrace_waitid+= -pthread -lm
-LDADD.t_ptrace_waitpid+= -pthread -lm
+LDADD.t_ptrace_wait+= -pthread -lm -lelf
+LDADD.t_ptrace_wait3+= -pthread -lm -lelf
+LDADD.t_ptrace_wait4+= -pthread -lm -lelf
+LDADD.t_ptrace_wait6+= -pthread -lm -lelf
+LDADD.t_ptrace_waitid+= -pthread -lm -lelf
+LDADD.t_ptrace_waitpid+= -pthread -lm -lelf
.if (${MKRUMP} != "no") && !defined(BSD_MK_COMPAT_FILE)
CPPFLAGS.t_posix_fadvise.c += -D_KERNTYPES
diff -r 0117171639c8 -r 76e6d975c49e tests/lib/libc/sys/t_ptrace_wait.c
--- a/tests/lib/libc/sys/t_ptrace_wait.c Sun Jun 30 19:57:23 2019 +0000
+++ b/tests/lib/libc/sys/t_ptrace_wait.c Sun Jun 30 21:20:04 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_wait.c,v 1.129 2019/06/26 12:30:13 mgorny Exp $ */
+/* $NetBSD: t_ptrace_wait.c,v 1.130 2019/06/30 21:20:04 mgorny Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -27,10 +27,11 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.129 2019/06/26 12:30:13 mgorny Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.130 2019/06/30 21:20:04 mgorny Exp $");
#include <sys/param.h>
#include <sys/types.h>
+#include <sys/exec_elf.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
@@ -43,6 +44,7 @@
#include <elf.h>
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <lwp.h>
#include <pthread.h>
#include <sched.h>
@@ -66,6 +68,9 @@
#include <x86/specialreg.h>
#endif
+#include <libelf.h>
+#include <gelf.h>
+
#include <atf-c.h>
#include "h_macros.h"
@@ -7639,6 +7644,180 @@
/// ----------------------------------------------------------------------------
+/*
+ * Parse the core file and find the requested note. If the reading or parsing
+ * fails, the test is failed. If the note is found, it is read onto buf, up to
+ * buf_len. The actual length of the note is returned (which can be greater
+ * than buf_len, indicating that it has been truncated). If the note is not
+ * found, -1 is returned.
+ */
+static ssize_t core_find_note(const char *core_path,
+ const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
+{
+ int core_fd;
+ Elf *core_elf;
+ size_t core_numhdr, i;
+ ssize_t ret = -1;
+ /* note: we assume note name will be null-terminated */
+ size_t name_len = strlen(note_name) + 1;
+
+ SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
+ SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
+ SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
+
+ SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
+ for (i = 0; i < core_numhdr && ret == -1; i++) {
+ GElf_Phdr core_hdr;
+ size_t offset;
+ SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
+ if (core_hdr.p_type != PT_NOTE)
+ continue;
+
+ for (offset = core_hdr.p_offset;
+ offset < core_hdr.p_offset + core_hdr.p_filesz;) {
+ Elf64_Nhdr note_hdr;
+ char name_buf[64];
+
+ switch (gelf_getclass(core_elf)) {
+ case ELFCLASS64:
+ SYSCALL_REQUIRE(pread(core_fd, ¬e_hdr,
+ sizeof(note_hdr), offset)
+ == sizeof(note_hdr));
+ offset += sizeof(note_hdr);
+ break;
+ case ELFCLASS32:
+ {
+ Elf32_Nhdr tmp_hdr;
+ SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
+ sizeof(tmp_hdr), offset)
+ == sizeof(tmp_hdr));
+ offset += sizeof(tmp_hdr);
+ note_hdr.n_namesz = tmp_hdr.n_namesz;
+ note_hdr.n_descsz = tmp_hdr.n_descsz;
+ note_hdr.n_type = tmp_hdr.n_type;
+ }
+ break;
+ }
+
+ /* indicates end of notes */
+ if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
+ break;
+ if (note_hdr.n_namesz == name_len &&
+ note_hdr.n_namesz <= sizeof(name_buf)) {
+ SYSCALL_REQUIRE(pread(core_fd, name_buf,
+ note_hdr.n_namesz, offset)
+ == note_hdr.n_namesz);
+
+ if (!strncmp(note_name, name_buf, name_len) &&
+ note_hdr.n_type == note_type)
+ ret = note_hdr.n_descsz;
+ }
+
+ offset += note_hdr.n_namesz;
+ /* fix to alignment */
+ offset = ((offset + core_hdr.p_align - 1)
+ / core_hdr.p_align) * core_hdr.p_align;
+
+ /* if name & type matched above */
+ if (ret != -1) {
+ ssize_t read_len = MIN(buf_len,
+ note_hdr.n_descsz);
+ SYSCALL_REQUIRE(pread(core_fd, buf,
+ read_len, offset) == read_len);
+ break;
+ }
+
+ offset += note_hdr.n_descsz;
+ }
+ }
+
+ elf_end(core_elf);
+ close(core_fd);
+
+ return ret;
+}
+
+ATF_TC(core_dump_procinfo);
+ATF_TC_HEAD(core_dump_procinfo, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Trigger a core dump and verify its contents.");
+}
+
+ATF_TC_BODY(core_dump_procinfo, tc)
+{
+ const int exitval = 5;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ const int sigval = SIGTRAP;
+ int status;
+#endif
+ char core_path[] = "/tmp/core.XXXXXX";
+ int core_fd;
+ struct netbsd_elfcore_procinfo procinfo;
+
+ DPRINTF("Before forking process PID=%d\n", getpid());
+ SYSCALL_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ DPRINTF("Before triggering SIGTRAP\n");
+ trigger_trap();
+
+ DPRINTF("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
+ close(core_fd);
+
+ DPRINTF("Call DUMPCORE for the child process\n");
+ SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
+ != -1);
+
+ DPRINTF("Read core file\n");
+ ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
+ ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
+ sizeof(procinfo));
+
+ ATF_CHECK_EQ(procinfo.cpi_version, 1);
+ ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
+ ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
+ ATF_CHECK_EQ(procinfo.cpi_pid, child);
+ ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
+ ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
+ ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
+ ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
+ ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
+ ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
+ ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
+ ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
+ ATF_CHECK_EQ(procinfo.cpi_siglwp, 1);
+
+ unlink(core_path);
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+/// ----------------------------------------------------------------------------
+
#include "t_ptrace_amd64_wait.h"
#include "t_ptrace_i386_wait.h"
#include "t_ptrace_x86_wait.h"
@@ -8130,6 +8309,8 @@
ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
+ ATF_TP_ADD_TC(tp, core_dump_procinfo);
+
ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
Home |
Main Index |
Thread Index |
Old Index