summaryrefslogtreecommitdiff
path: root/tests/kernel
diff options
context:
space:
mode:
authorkamil <kamil@NetBSD.org>2018-05-22 04:32:56 +0000
committerkamil <kamil@NetBSD.org>2018-05-22 04:32:56 +0000
commitcf6baef81b97fdf2170656581ed4f0d03d3b52b2 (patch)
treec3961108a79ad5cd5aa6e706d577604e2b7ff939 /tests/kernel
parent21e5503840dd2175d4a2497e804ad151f6a89008 (diff)
Extend ATF tests in t_trapsignal.sh to verify software breakpoint traps
There are at least four types of SIGTRAP events: - software/hardware single step (trace trap) - software breakpoint - hardware breakpoint/watchpoint - kernel event (exec, fork, vfork, vfork-done, lwp-create, lwp-exit) A program can execute software breakpoint without the context of being traced and this is a regular crash signal emitting SIGTRAP (TRAP_BRKPT). Rename original trap_* tests (trap_simple, trap_handle, trap_mask, trap_handle_recurse and trap_ignore) to segv_* tests and restrict them for SIGSEGV. Add new tests: trap_* testing the same scenarios as segv_ ones, however verifying the software breakpoint trap (SIGTRAP). Keep the original name of h_segv.c, and extend it for software breakpoint events. The purpose of these tests is to verify SIGTRAP kernel paths without the ptrace(2) context. All tests pass. Sponsored by <The NetBSD Foundation>
Diffstat (limited to 'tests/kernel')
-rw-r--r--tests/kernel/h_segv.c57
-rw-r--r--tests/kernel/t_trapsignal.sh110
2 files changed, 138 insertions, 29 deletions
diff --git a/tests/kernel/h_segv.c b/tests/kernel/h_segv.c
index d3f1137bdb5..f07dcf4b7a7 100644
--- a/tests/kernel/h_segv.c
+++ b/tests/kernel/h_segv.c
@@ -1,4 +1,4 @@
-/* $NetBSD: h_segv.c,v 1.3 2018/05/21 08:49:03 kamil Exp $ */
+/* $NetBSD: h_segv.c,v 1.4 2018/05/22 04:32:56 kamil Exp $ */
/*-
* Copyright (c) 2017 The NetBSD Foundation, Inc.
@@ -29,8 +29,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: h_segv.c,v 1.3 2018/05/21 08:49:03 kamil Exp $");
+__RCSID("$NetBSD: h_segv.c,v 1.4 2018/05/22 04:32:56 kamil Exp $");
+#include <sys/types.h>
+#include <sys/ptrace.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -57,21 +59,41 @@ static struct {
{ "ignore", F_IGNORE }
};
+static int sig;
+static struct {
+ const char *n;
+ int v;
+} sn[] = {
+ { "segv", SIGSEGV },
+ { "trap", SIGTRAP }
+};
+
static void
foo(int s)
{
char buf[64];
int i = snprintf(buf, sizeof(buf), "got %d\n", s);
write(2, buf, i);
- if (flags & F_RECURSE)
- *p = 0;
+ if (flags & F_RECURSE) {
+ if (sig == SIGSEGV)
+ *p = 0;
+ else if (sig == SIGTRAP) {
+#ifdef PTRACE_BREAKPOINT_ASM
+ PTRACE_BREAKPOINT_ASM;
+#else
+ /* port me */
+#endif
+ }
+ }
exit(EXIT_SUCCESS);
}
static __dead void
usage(void)
{
- fprintf(stderr, "Usage: %s recurse|mask|handle ...\n", getprogname());
+ const char *pname = getprogname();
+
+ fprintf(stderr, "Usage: %s recurse|mask|handle|ignore ...\n", pname);
exit(EXIT_FAILURE);
}
@@ -83,16 +105,21 @@ main(int argc, char *argv[])
for (int i = 1; i < argc; i++) {
size_t j;
- for (j = 0; j < __arraycount(nv); j++)
+ for (j = 0; j < __arraycount(nv); j++) {
if (strcmp(nv[j].n, argv[i]) == 0) {
flags |= nv[j].v;
break;
}
+ if (strcmp(sn[j].n, argv[i]) == 0) {
+ sig = sn[j].v;
+ break;
+ }
+ }
if (j == __arraycount(nv))
usage();
}
- if (flags == 0)
+ if (flags == 0 || sig == 0)
usage();
if (flags & F_HANDLE) {
@@ -101,7 +128,7 @@ main(int argc, char *argv[])
sa.sa_flags = SA_RESTART;
sa.sa_handler = foo;
sigemptyset(&sa.sa_mask);
- if (sigaction(SIGSEGV, &sa, NULL) == -1)
+ if (sigaction(sig, &sa, NULL) == -1)
err(EXIT_FAILURE, "sigaction");
}
@@ -109,7 +136,7 @@ main(int argc, char *argv[])
sigset_t set;
sigemptyset(&set);
- sigaddset(&set, SIGSEGV);
+ sigaddset(&set, sig);
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
err(EXIT_FAILURE, "sigprocmask");
}
@@ -120,10 +147,18 @@ main(int argc, char *argv[])
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
- if (sigaction(SIGSEGV, &sa, NULL) == -1)
+ if (sigaction(sig, &sa, NULL) == -1)
err(EXIT_FAILURE, "sigaction");
}
- *p = 1;
+ if (sig == SIGSEGV)
+ *p = 1;
+ else if (sig == SIGTRAP) {
+#ifdef PTRACE_BREAKPOINT_ASM
+ PTRACE_BREAKPOINT_ASM;
+#else
+ /* port me */
+#endif
+ }
return EXIT_SUCCESS;
}
diff --git a/tests/kernel/t_trapsignal.sh b/tests/kernel/t_trapsignal.sh
index fce565fc626..13850a7a8fc 100644
--- a/tests/kernel/t_trapsignal.sh
+++ b/tests/kernel/t_trapsignal.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_trapsignal.sh,v 1.2 2018/05/21 08:49:03 kamil Exp $
+# $NetBSD: t_trapsignal.sh,v 1.3 2018/05/22 04:32:56 kamil Exp $
#
# Copyright (c) 2017 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -29,60 +29,128 @@
#
HELPER=$(atf_get_srcdir)/h_segv
+atf_test_case segv_simple
+segv_simple()
+{
+ atf_set "descr" "Test unhandled SIGSEGV with the right exit code"
+}
+segv_simple_body()
+{
+ atf_check -s signal:11 -o "inline:" -e "inline:" \
+ ${HELPER} segv recurse
+}
+
+atf_test_case segv_handle
+segv_handle()
+{
+ atf_set "descr" "Test handled SIGSEGV traps call the signal handler"
+}
+segv_handle_body()
+{
+ atf_check -s exit:0 -o "inline:" -e "inline:got 11\n" \
+ ${HELPER} segv handle
+}
+
+atf_test_case segv_mask
+segv_mask()
+{
+ atf_set "descr" "Test that masking SIGSEGV get reset"
+}
+segv_mask_body()
+{
+ atf_check -s signal:11 -o "inline:" -e "inline:" \
+ ${HELPER} segv mask
+}
+
+atf_test_case segv_handle_mask
+segv_handle_mask()
+{
+ atf_set "descr" "Test handled and masked SIGSEGV traps get reset"
+}
+segv_handle_mask_body()
+{
+ atf_check -s signal:11 -o "inline:" -e "inline:" \
+ ${HELPER} segv mask handle
+}
+
+atf_test_case segv_handle_recurse
+segv_handle_recurse()
+{
+ atf_set "descr" "Test that receiving SIGSEGV in the handler resets"
+}
+
+segv_handle_recurse_body()
+{
+ atf_check -s signal:11 -o "inline:" -e "inline:got 11\n" \
+ ${HELPER} segv handle recurse
+}
+
+atf_test_case segv_ignore
+segv_ignore()
+{
+ atf_set "descr" "Test ignored SIGSEGV trap with right exit code"
+}
+
+segv_ignore_body()
+{
+ atf_check -s signal:11 -o "inline:" -e "inline:" \
+ ${HELPER} segv ignore
+}
+
atf_test_case trap_simple
trap_simple()
{
- atf_set "descr" "Test unhandled traps exit with the right exit code"
+ atf_set "descr" "Test unhandled SIGTRAP with the right exit code"
}
trap_simple_body()
{
- atf_check -s signal:11 -o "inline:" -e "inline:" \
- ${HELPER} recurse
+ atf_check -s signal:5 -o "inline:" -e "inline:" \
+ ${HELPER} trap recurse
}
atf_test_case trap_handle
trap_handle()
{
- atf_set "descr" "Test handled traps call the signal handler"
+ atf_set "descr" "Test handled SIGTRAP traps call the signal handler"
}
trap_handle_body()
{
- atf_check -s exit:0 -o "inline:" -e "inline:got 11\n" \
- ${HELPER} handle
+ atf_check -s exit:0 -o "inline:" -e "inline:got 5\n" \
+ ${HELPER} trap handle
}
atf_test_case trap_mask
trap_mask()
{
- atf_set "descr" "Test that masking the trapped signal get reset"
+ atf_set "descr" "Test that masking the trapped SIGTRAP signal get reset"
}
trap_mask_body()
{
- atf_check -s signal:11 -o "inline:" -e "inline:" \
- ${HELPER} mask
+ atf_check -s signal:5 -o "inline:" -e "inline:" \
+ ${HELPER} trap mask
}
atf_test_case trap_handle_mask
trap_handle_mask()
{
- atf_set "descr" "Test handled and masked traps get reset"
+ atf_set "descr" "Test handled and masked SIGTRAP traps get reset"
}
trap_handle_mask_body()
{
- atf_check -s signal:11 -o "inline:" -e "inline:" \
- ${HELPER} mask handle
+ atf_check -s signal:5 -o "inline:" -e "inline:" \
+ ${HELPER} trap mask handle
}
atf_test_case trap_handle_recurse
trap_handle_recurse()
{
- atf_set "descr" "Test that receiving the trap in the handler resets"
+ atf_set "descr" "Test that receiving SIGTRAP in the handler resets"
}
trap_handle_recurse_body()
{
- atf_check -s signal:11 -o "inline:" -e "inline:got 11\n" \
- ${HELPER} handle recurse
+ atf_check -s signal:5 -o "inline:" -e "inline:got 5\n" \
+ ${HELPER} trap handle recurse
}
atf_test_case trap_ignore
@@ -93,12 +161,18 @@ trap_ignore()
trap_ignore_body()
{
- atf_check -s signal:11 -o "inline:" -e "inline:" \
- ${HELPER} ignore
+ atf_check -s signal:5 -o "inline:" -e "inline:" \
+ ${HELPER} trap ignore
}
atf_init_test_cases()
{
+ atf_add_test_case segv_simple
+ atf_add_test_case segv_handle
+ atf_add_test_case segv_mask
+ atf_add_test_case segv_handle_recurse
+ atf_add_test_case segv_ignore
+
atf_add_test_case trap_simple
atf_add_test_case trap_handle
atf_add_test_case trap_mask