source: mainline/kernel/generic/src/debug/sections.c@ 2fbb42f

topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2fbb42f was da13982, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 months ago

Read symbol table from ELF sections

Instead of the currently broken data generated using genmap.py,
read the ELF symbol table for stack traces and symbol names.
In addition to that, prepare ground for accessing DWARF debug
sections.

Because neither .symtab, nor .debug_* sections are
normally part of the program image, these have to be provided
externally. Instead of the previous way of relinking kernel
to bake in the symbol data, we now only link kernel once
and the extra debug data is loaded as part of the initrd image.

  • Property mode set to 100644
File size: 5.6 KB
RevLine 
[da13982]1/*
2 * Copyright (c) 2023 Jiří Zárevúcky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <debug/sections.h>
30#include <debug/register.h>
31
32#include <stdio.h>
33#include <str.h>
34
35const void *debug_aranges = NULL;
36size_t debug_aranges_size = 0;
37
38const void *debug_info = NULL;
39size_t debug_info_size = 0;
40
41const void *debug_abbrev = NULL;
42size_t debug_abbrev_size = 0;
43
44const void *debug_line = NULL;
45size_t debug_line_size = 0;
46
47const char *debug_str = NULL;
48size_t debug_str_size = 0;
49
50const char *debug_line_str = NULL;
51size_t debug_line_str_size = 0;
52
53const void *debug_rnglists = NULL;
54size_t debug_rnglists_size = 0;
55
56// TODO: get this from the program image
57const void *eh_frame_hdr = NULL;
58size_t eh_frame_hdr_size = 0;
59
60const void *eh_frame = NULL;
61size_t eh_frame_size = 0;
62
63const elf_symbol_t *symtab = NULL;
64size_t symtab_size = 0;
65
66const char *strtab = NULL;
67size_t strtab_size = 0;
68
69struct section_manifest {
70 const char *name;
71 const void **address_field;
72 size_t *size_field;
73};
74
75#define section(name) { "." #name, (const void **)&name, &name##_size }
76
77static const struct section_manifest manifest[] = {
78 section(debug_aranges),
79 section(debug_info),
80 section(debug_abbrev),
81 section(debug_line),
82 section(debug_str),
83 section(debug_line_str),
84 section(debug_rnglists),
85 section(eh_frame_hdr),
86 section(eh_frame),
87 section(symtab),
88 section(strtab),
89};
90
91#undef section
92
93static const size_t manifest_len = sizeof(manifest) / sizeof(struct section_manifest);
94
95void register_debug_data(const void *data, size_t data_size)
96{
97 const void *data_end = data + data_size;
98
99 /*
100 * While this data is technically "trusted", insofar as it is provided
101 * by the bootloader, it's not critical, so we try to make sure malformed or
102 * misconfigured debug data doesn't crash the kernel.
103 */
104
105 if (data_size < sizeof(elf_header_t)) {
106 printf("bad debug data: too short\n");
107 return;
108 }
109
110 if (((uintptr_t) data) % 8 != 0) {
111 printf("bad debug data: unaligned input\n");
112 return;
113 }
114
115 const elf_header_t *hdr = data;
116
117 if (hdr->e_ident[0] != ELFMAG0 || hdr->e_ident[1] != ELFMAG1 ||
118 hdr->e_ident[2] != ELFMAG2 || hdr->e_ident[3] != ELFMAG3) {
119 printf("bad debug data: wrong ELF magic bytes\n");
120 return;
121 }
122
123 if (hdr->e_shentsize != sizeof(elf_section_header_t)) {
124 printf("bad debug data: wrong e_shentsize\n");
125 return;
126 }
127
128 /* Get section header table. */
129 const elf_section_header_t *shdr = data + hdr->e_shoff;
130 size_t shdr_len = hdr->e_shnum;
131
132 if ((void *) &shdr[shdr_len] > data_end) {
133 printf("bad debug data: truncated section header table\n");
134 return;
135 }
136
137 if (hdr->e_shstrndx >= shdr_len) {
138 printf("bad debug data: string table index out of range\n");
139 return;
140 }
141
142 /* Get data on section name string table. */
143 const elf_section_header_t *shstr = &shdr[hdr->e_shstrndx];
144 const char *shstrtab = data + shstr->sh_offset;
145 size_t shstrtab_size = shstr->sh_size;
146
147 if ((void *) shstrtab + shstrtab_size > data_end) {
148 printf("bad debug data: truncated string table\n");
149 return;
150 }
151
152 /* Check NUL-terminator. */
153 while (shstrtab_size > 0 && shstrtab[shstrtab_size - 1] != 0) {
154 shstrtab_size--;
155 }
156
157 if (shstrtab_size == 0) {
158 printf("bad debug data: empty or non-null-terminated string table\n");
159 return;
160 }
161
162 /* List all present sections. */
163 for (size_t i = 0; i < shdr_len; i++) {
164 if (shdr[i].sh_type == SHT_NULL || shdr[i].sh_type == SHT_NOBITS)
165 continue;
166
167 if (shdr[i].sh_name >= shstrtab_size) {
168 printf("bad debug data: string table index out of range\n");
169 return;
170 }
171
172 const char *name = shstrtab + shdr[i].sh_name;
173 size_t offset = shdr[i].sh_offset;
174 size_t size = shdr[i].sh_size;
175
176 printf("section '%s': offset %zd (%zd bytes)\n", name, offset, size);
177
178 if (data + offset + size > data_end) {
179 printf("bad debug data: truncated section %s\n", name);
180 continue;
181 }
182
183 for (size_t i = 0; i < manifest_len; i++) {
184 if (str_cmp(manifest[i].name, name) == 0) {
185 *manifest[i].address_field = data + offset;
186 *manifest[i].size_field = size;
187 break;
188 }
189 }
190 }
191
192 /* Check NUL-terminator in .strtab, .debug_str and .debug_line_str */
193 while (strtab_size > 0 && strtab[strtab_size - 1] != 0) {
194 strtab_size--;
195 }
196
197 while (debug_str_size > 0 && debug_str[debug_str_size - 1] != 0) {
198 debug_str_size--;
199 }
200
201 while (debug_line_str_size > 0 && debug_str[debug_line_str_size - 1] != 0) {
202 debug_line_str_size--;
203 }
204}
Note: See TracBrowser for help on using the repository browser.