summaryrefslogtreecommitdiff
path: root/zephyr/test/drivers/panic_output
diff options
context:
space:
mode:
authorTristan Honscheid <honscheid@google.com>2022-10-31 15:52:50 -0600
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-11-30 23:10:45 +0000
commit91893ee143fed8e99da15f8b3b522e7750b5a1dd (patch)
tree747c1794d23d541eebcf72d58f8282fdeaa0ad1a /zephyr/test/drivers/panic_output
parentb6e76ee80d897db61684668978450207a7184367 (diff)
downloadchrome-ec-91893ee143fed8e99da15f8b3b522e7750b5a1dd.tar.gz
zephyr: test: Test `crash` console command
Test various `crash` subcommands that cause different types of fatal errors. Not all were possible to test due to limitations with running these on a PC. Also had to make a tweak to the busy loops in the watchdog and hang subcommands so that they don't interfere with the simulated sys clock in native_posix. Add a public wrapper function for calling the crash command outside of the shell interface so we don't mess up its internal state when the command doesn't return. BUG=None BRANCH=None TEST=./twister Signed-off-by: Tristan Honscheid <honscheid@google.com> Change-Id: I393e26441d44c0a5edaf1359413efe6280703add Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4053360 Reviewed-by: Keith Short <keithshort@chromium.org> Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Diffstat (limited to 'zephyr/test/drivers/panic_output')
-rw-r--r--zephyr/test/drivers/panic_output/CMakeLists.txt8
-rw-r--r--zephyr/test/drivers/panic_output/src/panic_output_crash_cmd.c167
2 files changed, 175 insertions, 0 deletions
diff --git a/zephyr/test/drivers/panic_output/CMakeLists.txt b/zephyr/test/drivers/panic_output/CMakeLists.txt
new file mode 100644
index 0000000000..79cf21fc5f
--- /dev/null
+++ b/zephyr/test/drivers/panic_output/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright 2022 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Add source files
+target_sources(app PRIVATE
+ src/panic_output_crash_cmd.c
+)
diff --git a/zephyr/test/drivers/panic_output/src/panic_output_crash_cmd.c b/zephyr/test/drivers/panic_output/src/panic_output_crash_cmd.c
new file mode 100644
index 0000000000..9608869609
--- /dev/null
+++ b/zephyr/test/drivers/panic_output/src/panic_output_crash_cmd.c
@@ -0,0 +1,167 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdint.h>
+#include <signal.h>
+#include <stdio.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/ztest.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest_assert.h>
+
+#include "console.h"
+#include "panic.h"
+#include "test/drivers/test_state.h"
+
+/* Special return codes for run_crash_command() */
+#define RETURN_CODE_CRASHED (-1)
+#define RETURN_CODE_TIMEOUT (-2)
+
+/** Create a new thread for running the `crash` console command. As its name
+ * suggests, this command causes a number of fatal errors (e.g. divide by zero).
+ * Run it in a separate thread so that we can observe these crashes without
+ * causing the ztest thread that runs the test functions to get aborted.
+ */
+static struct k_thread crash_thread;
+
+/* Create a stack for the crash thread */
+K_THREAD_STACK_DEFINE(crash_thread_stack, 1024);
+
+/** Captures the last signal number received by `handle_signal()`. */
+static int signal_received;
+
+/**
+ * @brief Handler for signals sent to the process. Log the signal number and
+ * abort the crash test.
+ *
+ * @param sig Signal number, from signal.h
+ */
+void handle_signal(int sig)
+{
+ signal_received = sig;
+
+ k_thread_abort(&crash_thread);
+}
+
+/**
+ * @brief Worker function for the crash thread that calls the `crash` console
+ * command.
+ *
+ * @param a The value of `argc` (forced as a pointer type).
+ * @param b `argv` pointer.
+ * @param c Pointer to location to write the return value.
+ */
+static void crash_thread_worker(void *a, void *b, void *c)
+{
+ int argc = (int)a;
+ const char **argv = (const char **)b;
+ int *return_val = c;
+
+ /* If the return value remains RETURN_CODE_CRASHED, then the command
+ * did not return.
+ */
+ *return_val = RETURN_CODE_CRASHED;
+ signal_received = 0;
+
+ *return_val = test_command_crash(argc, argv);
+}
+
+/**
+ * @brief Helper function to spawn a new thread that runs the `crash` console
+ * command. Waits for the command to exit/fail.
+ *
+ * @param argc Number of elements in `argv`
+ * @param argv CLI arguments to pass to command. Include the command name.
+ * @param timeout Time to wait for the thread to exit, in milliseconds.
+ * @return int Console command's return value, or RETURN_CODE_CRASHED if caused
+ * a fatal error, or RETURN_CODE_TIMEOUT if it hung.
+ */
+static int run_crash_command(int argc, const char **argv, k_timeout_t timeout)
+{
+ static int return_val;
+
+ k_thread_create(&crash_thread, crash_thread_stack,
+ K_THREAD_STACK_SIZEOF(crash_thread_stack),
+ (k_thread_entry_t)crash_thread_worker, (void *)argc,
+ argv, &return_val, CONFIG_ZTEST_THREAD_PRIORITY + 1,
+ K_INHERIT_PERMS, K_NO_WAIT);
+
+ if (k_thread_join(&crash_thread, timeout) == -EAGAIN) {
+ k_thread_abort(&crash_thread);
+ return RETURN_CODE_TIMEOUT;
+ }
+
+ return return_val;
+}
+
+ZTEST(panic_output, test_console_cmd__unaligned)
+{
+ int rv;
+ const char *cmd[] = { "crash", "unaligned" };
+
+ rv = run_crash_command(2, cmd, K_FOREVER);
+
+ zassert_equal(RETURN_CODE_CRASHED, rv,
+ "Command returned %d but shouldn't have exited", rv);
+ zassert_equal(SIGSEGV, signal_received);
+}
+
+ZTEST(panic_output, test_console_cmd__watchdog)
+{
+ /* Note: this does not verify that the watchdog fired, but that is
+ * covered in a different test suite.
+ */
+
+ int rv;
+ const char *cmd[] = { "crash", "watchdog" };
+
+ rv = run_crash_command(2, cmd, K_MSEC(100));
+
+ zassert_equal(RETURN_CODE_TIMEOUT, rv,
+ "Command returned %d but shouldn't have exited", rv);
+}
+
+ZTEST(panic_output, test_console_cmd__hang)
+{
+ int rv;
+ const char *cmd[] = { "crash", "hang" };
+
+ rv = run_crash_command(2, cmd, K_MSEC(100));
+
+ zassert_equal(RETURN_CODE_TIMEOUT, rv,
+ "Command returned %d but shouldn't have exited", rv);
+}
+
+ZTEST(panic_output, test_console_cmd__bad_param)
+{
+ int rv;
+ const char *cmd[] = { "crash", "xyz" };
+
+ rv = run_crash_command(2, cmd, K_FOREVER);
+
+ zassert_equal(EC_ERROR_PARAM1, rv, "Command returned %d", rv);
+}
+
+ZTEST(panic_output, test_console_cmd__no_param)
+{
+ int rv;
+ const char *cmd[] = { "crash" };
+
+ rv = run_crash_command(1, cmd, K_FOREVER);
+
+ zassert_equal(EC_ERROR_PARAM1, rv, "Command returned %d", rv);
+}
+
+static void reset(void *data)
+{
+ ARG_UNUSED(data);
+
+ signal(SIGSEGV, handle_signal);
+ signal(SIGFPE, handle_signal);
+ signal_received = 0;
+}
+
+ZTEST_SUITE(panic_output, drivers_predicate_post_main, NULL, reset, reset,
+ NULL);