1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  * Copyright (c) 2016 Intel Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include "kernel_shell.h"
9 
10 #include <string.h>
11 
12 #include <kernel_internal.h>
13 
14 #include <zephyr/kernel.h>
15 
16 #if defined(CONFIG_THREAD_MAX_NAME_LEN)
17 #define THREAD_MAX_NAM_LEN CONFIG_THREAD_MAX_NAME_LEN
18 #else
19 #define THREAD_MAX_NAM_LEN 10
20 #endif
21 
shell_stack_dump(const struct k_thread * thread,void * user_data)22 static void shell_stack_dump(const struct k_thread *thread, void *user_data)
23 {
24 	const struct shell *sh = (const struct shell *)user_data;
25 	unsigned int pcnt;
26 	size_t unused;
27 	size_t size = thread->stack_info.size;
28 	const char *tname;
29 	int ret;
30 
31 	ret = k_thread_stack_space_get(thread, &unused);
32 	if (ret) {
33 		shell_print(sh,
34 			    "Unable to determine unused stack size (%d)\n",
35 			    ret);
36 		return;
37 	}
38 
39 	tname = k_thread_name_get((struct k_thread *)thread);
40 
41 	/* Calculate the real size reserved for the stack */
42 	pcnt = ((size - unused) * 100U) / size;
43 
44 	shell_print(sh,
45 		    "%p %-" STRINGIFY(THREAD_MAX_NAM_LEN) "s "
46 		    "(real size %4zu):\tunused %4zu\tusage %4zu / %4zu (%2u %%)",
47 		    thread, tname ? tname : "NA", size, unused, size - unused, size, pcnt);
48 }
49 
50 K_KERNEL_STACK_ARRAY_DECLARE(z_interrupt_stacks, CONFIG_MP_MAX_NUM_CPUS,
51 			     CONFIG_ISR_STACK_SIZE);
52 
cmd_kernel_thread_stacks(const struct shell * sh,size_t argc,char ** argv)53 static int cmd_kernel_thread_stacks(const struct shell *sh, size_t argc, char **argv)
54 {
55 	ARG_UNUSED(argc);
56 	ARG_UNUSED(argv);
57 	char pad[THREAD_MAX_NAM_LEN] = { 0 };
58 
59 	memset(pad, ' ', MAX((THREAD_MAX_NAM_LEN - strlen("IRQ 00")), 1));
60 
61 	/*
62 	 * Use the unlocked version as the callback itself might call
63 	 * arch_irq_unlock.
64 	 */
65 	k_thread_foreach_unlocked(shell_stack_dump, (void *)sh);
66 
67 	/* Placeholder logic for interrupt stack until we have better
68 	 * kernel support, including dumping arch-specific exception-related
69 	 * stack buffers.
70 	 */
71 	unsigned int num_cpus = arch_num_cpus();
72 
73 	for (int i = 0; i < num_cpus; i++) {
74 		size_t unused;
75 		const uint8_t *buf = K_KERNEL_STACK_BUFFER(z_interrupt_stacks[i]);
76 		size_t size = K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[i]);
77 		int err = z_stack_space_get(buf, size, &unused);
78 
79 		(void)err;
80 		__ASSERT_NO_MSG(err == 0);
81 
82 		shell_print(sh,
83 			    "%p IRQ %02d %s(real size %4zu):\tunused %4zu\tusage %4zu / %4zu (%2zu %%)",
84 			    &z_interrupt_stacks[i], i, pad, size, unused, size - unused, size,
85 			    ((size - unused) * 100U) / size);
86 	}
87 
88 	return 0;
89 }
90 
91 KERNEL_THREAD_CMD_ADD(stacks, NULL, "List threads stack usage.", cmd_kernel_thread_stacks);
92