1 /*
2  * Copyright 2024 Meta Platforms
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/debug/symtab.h>
8 #include <zephyr/ztest.h>
9 
10 const struct symtab_info *symtab;
11 
setup(void)12 static void *setup(void)
13 {
14 	symtab = symtab_get();
15 
16 	return NULL;
17 }
18 
19 ZTEST_SUITE(test_symtab, NULL, setup, NULL, NULL, NULL);
20 
ZTEST(test_symtab,test_size)21 ZTEST(test_symtab, test_size)
22 {
23 	zassert_true(symtab->length > 0);
24 }
25 
ZTEST(test_symtab,test_symtab_find_symbol_name)26 ZTEST(test_symtab, test_symtab_find_symbol_name)
27 {
28 	extern int main(void);
29 	const uintptr_t first_addr = symtab->first_addr;
30 	const uintptr_t last_addr = first_addr + symtab->entries[symtab->length - 1].offset;
31 	uint32_t offset;
32 	const char *symbol_name;
33 
34 	zassert_between_inclusive((uintptr_t)main, first_addr, last_addr,
35 				  "No valid address found for `main()`");
36 
37 	/* Find the name of functions with `symtab_find_symbol_name()` */
38 	offset = -1;
39 	symbol_name = symtab_find_symbol_name((uintptr_t)main, &offset);
40 	zassert_str_equal(symbol_name, "main");
41 	zassert_equal(offset, 0);
42 
43 	/* Do a few more just for fun */
44 	symbol_name = symtab_find_symbol_name((uintptr_t)strcmp, NULL);
45 	zassert_str_equal(symbol_name, "strcmp");
46 
47 	symbol_name = symtab_find_symbol_name((uintptr_t)symtab_find_symbol_name, NULL);
48 	zassert_str_equal(symbol_name, "symtab_find_symbol_name");
49 
50 	symbol_name = symtab_find_symbol_name((uintptr_t)test_main, NULL);
51 	zassert_str_equal(symbol_name, "test_main");
52 
53 	symbol_name = symtab_find_symbol_name((uintptr_t)setup, NULL);
54 	zassert_str_equal(symbol_name, "setup");
55 }
56 
57 /**
58  * This testsuite tests the following position in the symbol table
59  *
60  *
61  *                  [SYMBOL ADDR]       |      Name                   Offset
62  *     before first-->    .             |       "?"          (not found) 0x0
63  *            first-->  0x100           |   <first>                      0x0
64  *                      0x101           |   <first>                      0x1
65  *                        .             |
66  *                        .             |
67  *                        .             |
68  *             last-->  0x300           |    <last>                      0x0
69  *       after last-->  0x301           |    <last>                      0x1
70  *                        .             |
71  *                      0x310 (dummy)   |       "?"          (not found) 0x0
72  *                        .             |
73  *      after dummy-->  0x342           |       "?"          (not found) 0x0
74  */
75 
ZTEST(test_symtab,test_before_first)76 ZTEST(test_symtab, test_before_first)
77 {
78 	const uintptr_t first_addr = symtab->first_addr;
79 	const char *symbol_name;
80 	uint32_t offset;
81 
82 	/* No symbol should appear before first_addr, but make sure that first_addr != 0 */
83 	if (first_addr > 0) {
84 		offset = -1;
85 		symbol_name = symtab_find_symbol_name(first_addr - 1, &offset);
86 		zassert_str_equal(symbol_name, "?");
87 		zassert_equal(offset, 0);
88 	} else {
89 		ztest_test_skip();
90 	}
91 }
92 
ZTEST(test_symtab,test_first)93 ZTEST(test_symtab, test_first)
94 {
95 	const uintptr_t first_addr = symtab->first_addr;
96 	const char *symbol_name;
97 	uint32_t offset;
98 
99 	offset = -1;
100 	symbol_name = symtab_find_symbol_name(first_addr, &offset);
101 	zassert_str_equal(symbol_name, symtab->entries[0].name);
102 	zassert_equal(offset, 0);
103 
104 	if ((symtab->entries[0].offset + 1) != symtab->entries[1].offset) {
105 		offset = -1;
106 		symbol_name = symtab_find_symbol_name(first_addr + 1, &offset);
107 		zassert_str_equal(symbol_name, symtab->entries[0].name);
108 		zassert_equal(offset, 1);
109 	}
110 }
111 
ZTEST(test_symtab,test_last)112 ZTEST(test_symtab, test_last)
113 {
114 	const uintptr_t first_addr = symtab->first_addr;
115 	const int last_idx = symtab->length - 1;
116 	const uintptr_t last_addr = first_addr + symtab->entries[last_idx].offset;
117 	const char *symbol_name;
118 	uint32_t offset;
119 
120 	offset = -1;
121 	symbol_name = symtab_find_symbol_name(last_addr, &offset);
122 	zassert_str_equal(symbol_name, symtab->entries[last_idx].name);
123 	zassert_equal(offset, 0);
124 }
125 
ZTEST(test_symtab,test_after_last)126 ZTEST(test_symtab, test_after_last)
127 {
128 	const uintptr_t first_addr = symtab->first_addr;
129 	const uintptr_t last_offset = symtab->entries[symtab->length - 1].offset;
130 	const uintptr_t last_addr = first_addr + last_offset;
131 	const char *symbol_name;
132 	uint32_t offset;
133 
134 	/* Test `offset` output with last symbol */
135 	if (last_offset + 0x1 != symtab->entries[symtab->length].offset) {
136 		offset = -1;
137 		symbol_name = symtab_find_symbol_name(last_addr + 0x1, &offset);
138 		zassert_str_equal(symbol_name,
139 				  symtab->entries[symtab->length - 1].name);
140 		zassert_equal(offset, 0x1);
141 	} else {
142 		ztest_test_skip();
143 	}
144 }
145 
ZTEST(test_symtab,test_after_dummy)146 ZTEST(test_symtab, test_after_dummy)
147 {
148 	const uintptr_t first_addr = symtab->first_addr;
149 	const uintptr_t last_dummy_offset = symtab->entries[symtab->length].offset;
150 	const uintptr_t last_dummy_addr = first_addr + last_dummy_offset;
151 	const char *symbol_name;
152 	uint32_t offset;
153 
154 	/* Test `offset` output with dummy symbol (after last dymbol) */
155 	offset = -1;
156 	symbol_name = symtab_find_symbol_name(last_dummy_addr + 0x42, &offset);
157 	zassert_str_equal(symbol_name, "?");
158 	zassert_equal(offset, 0);
159 }
160