Skip to content

Commit 21a0e8a

Browse files
committed
shell: kernel: add command to unwind a thread
Add a shell command to unwind a thread using its thread id. uart:~$ kernel threads Scheduler: 11 since last call Threads: *0x80017138 shell_uart options: 0x0, priority: 14 timeout: 0 state: queued, entry: 0x800029ac stack size 3072, unused 1316, usage 1756 / 3072 (57 %) 0x80017ca8 sysworkq options: 0x1, priority: -1 timeout: 0 state: pending, entry: 0x80006842 stack size 1024, unused 644, usage 380 / 1024 (37 %) 0x800177e0 idle options: 0x1, priority: 15 timeout: 0 state: , entry: 0x800065ae stack size 512, unused 180, usage 332 / 512 (64 %) 0x80017950 main options: 0x1, priority: 0 timeout: 13 state: suspended, entry: 0x80006326 stack size 4096, unused 3604, usage 492 / 4096 (12 %) uart:~$ kernel unwind 0x80017ca8 Unwinding 0x80017ca8 sysworkq ra: 0x80007114 [z_swap+0x58] ra: 0x80007ae8 [z_sched_wait+0x10] ra: 0x8000689a [work_queue_main+0x58] ra: 0x800006de [z_thread_entry+0x2e] Signed-off-by: Yong Cong Sin <[email protected]>
1 parent c919034 commit 21a0e8a

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

subsys/shell/modules/kernel_service.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#if defined(CONFIG_LOG_RUNTIME_FILTERING)
2525
#include <zephyr/logging/log_ctrl.h>
2626
#endif
27+
#include <zephyr/debug/symtab.h>
2728

2829
#if defined(CONFIG_THREAD_MAX_NAME_LEN)
2930
#define THREAD_MAX_NAM_LEN CONFIG_THREAD_MAX_NAME_LEN
@@ -203,6 +204,66 @@ static int cmd_kernel_threads(const struct shell *sh,
203204
return 0;
204205
}
205206

207+
#if defined(CONFIG_ARCH_HAS_STACKWALK)
208+
209+
static bool print_trace_address(void *arg, unsigned long ra)
210+
{
211+
const struct shell *sh = arg;
212+
#ifdef CONFIG_SYMTAB
213+
uint32_t offset = 0;
214+
const char *name = symtab_find_symbol_name(ra, &offset);
215+
216+
shell_print(sh, "ra: %p [%s+0x%x]", (void *)ra, name, offset);
217+
#else
218+
shell_print(sh, "ra: %p", (void *)ra);
219+
#endif
220+
221+
return true;
222+
}
223+
224+
struct unwind_entry {
225+
const struct k_thread *const thread;
226+
bool valid;
227+
};
228+
229+
static void is_valid_thread(const struct k_thread *cthread, void *user_data)
230+
{
231+
struct unwind_entry *entry = user_data;
232+
233+
if (cthread == entry->thread) {
234+
entry->valid = true;
235+
}
236+
}
237+
238+
static int cmd_kernel_unwind(const struct shell *sh, size_t argc, char **argv)
239+
{
240+
struct k_thread *thread;
241+
242+
if (argc == 1) {
243+
thread = _current;
244+
} else {
245+
thread = UINT_TO_POINTER(strtoll(argv[1], NULL, 16));
246+
struct unwind_entry entry = {
247+
.thread = thread,
248+
.valid = false,
249+
};
250+
251+
k_thread_foreach_unlocked(is_valid_thread, &entry);
252+
253+
if (!entry.valid) {
254+
shell_error(sh, "Invalid thread id %p", (void *)thread);
255+
return -EINVAL;
256+
}
257+
}
258+
shell_print(sh, "Unwinding %p %s", (void *)thread, thread->name);
259+
260+
arch_stack_walk(print_trace_address, (void *)sh, thread, NULL);
261+
262+
return 0;
263+
}
264+
265+
#endif /* CONFIG_ARCH_HAS_STACKWALK */
266+
206267
static void shell_stack_dump(const struct k_thread *thread, void *user_data)
207268
{
208269
const struct shell *sh = (const struct shell *)user_data;
@@ -397,6 +458,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_kernel,
397458
defined(CONFIG_THREAD_MONITOR)
398459
SHELL_CMD(stacks, NULL, "List threads stack usage.", cmd_kernel_stacks),
399460
SHELL_CMD(threads, NULL, "List kernel threads.", cmd_kernel_threads),
461+
#if defined(CONFIG_ARCH_HAS_STACKWALK)
462+
SHELL_CMD_ARG(unwind, NULL, "Unwind a thread.", cmd_kernel_unwind, 1, 1),
463+
#endif /* CONFIG_ARCH_HAS_STACKWALK */
400464
#endif
401465
#if defined(CONFIG_SYS_HEAP_RUNTIME_STATS) && (K_HEAP_MEM_POOL_SIZE > 0)
402466
SHELL_CMD(heap, NULL, "System heap usage statistics.", cmd_kernel_heap),

0 commit comments

Comments
 (0)