source: mainline/kernel/generic/src/debug/sections.c

Last change on this file was 40eab9f, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 months ago

Print symbol names and line numbers in stacktraces for init tasks

Only useful in select few situations, but useful nonetheless.

  • Property mode set to 100644
File size: 5.2 KB
Line 
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#include <debug.h>
32
33#include <stdio.h>
34#include <str.h>
35
36#define DEBUGF dummy_printf
37
38debug_sections_t kernel_sections;
39
40struct section_manifest {
41 const char *name;
42 const void **address_field;
43 size_t *size_field;
44};
45
46static void _check_string_section(const char *section, size_t *section_size)
47{
48 while (*section_size > 0 && section[*section_size - 1] != 0) {
49 (*section_size)--;
50 }
51}
52
53debug_sections_t get_debug_sections(const void *elf, size_t elf_size)
54{
55 debug_sections_t out = { };
56
57#define section(name) { "." #name, (const void **)&out.name, &out.name##_size }
58
59 const struct section_manifest manifest[] = {
60 section(debug_aranges),
61 section(debug_info),
62 section(debug_abbrev),
63 section(debug_line),
64 section(debug_str),
65 section(debug_line_str),
66 section(debug_rnglists),
67 section(eh_frame_hdr),
68 section(eh_frame),
69 section(symtab),
70 section(strtab),
71 };
72
73 const size_t manifest_len = sizeof(manifest) / sizeof(struct section_manifest);
74
75 const void *data_end = elf + elf_size;
76
77 /*
78 * While this data is technically "trusted", insofar as it is provided
79 * by the bootloader, it's not critical, so we try to make sure malformed or
80 * misconfigured debug data doesn't crash the kernel.
81 */
82
83 if (elf_size < sizeof(elf_header_t)) {
84 printf("bad debug data: too short\n");
85 return out;
86 }
87
88 if (((uintptr_t) elf) % 8 != 0) {
89 printf("bad debug data: unaligned input\n");
90 return out;
91 }
92
93 const elf_header_t *hdr = elf;
94
95 if (hdr->e_ident[0] != ELFMAG0 || hdr->e_ident[1] != ELFMAG1 ||
96 hdr->e_ident[2] != ELFMAG2 || hdr->e_ident[3] != ELFMAG3) {
97 printf("bad debug data: wrong ELF magic bytes\n");
98 return out;
99 }
100
101 if (hdr->e_shentsize != sizeof(elf_section_header_t)) {
102 printf("bad debug data: wrong e_shentsize\n");
103 return out;
104 }
105
106 /* Get section header table. */
107 const elf_section_header_t *shdr = elf + hdr->e_shoff;
108 size_t shdr_len = hdr->e_shnum;
109
110 if ((void *) &shdr[shdr_len] > data_end) {
111 printf("bad debug data: truncated section header table\n");
112 return out;
113 }
114
115 if (hdr->e_shstrndx >= shdr_len) {
116 printf("bad debug data: string table index out of range\n");
117 return out;
118 }
119
120 /* Get data on section name string table. */
121 const elf_section_header_t *shstr = &shdr[hdr->e_shstrndx];
122 const char *shstrtab = elf + shstr->sh_offset;
123 size_t shstrtab_size = shstr->sh_size;
124
125 if ((void *) shstrtab + shstrtab_size > data_end) {
126 printf("bad debug data: truncated string table\n");
127 return out;
128 }
129
130 /* Check NUL-terminator. */
131 _check_string_section(shstrtab, &shstrtab_size);
132
133 if (shstrtab_size == 0) {
134 printf("bad debug data: empty or non-null-terminated string table\n");
135 return out;
136 }
137
138 /* List all present sections. */
139 for (size_t i = 0; i < shdr_len; i++) {
140 if (shdr[i].sh_type == SHT_NULL || shdr[i].sh_type == SHT_NOBITS)
141 continue;
142
143 if (shdr[i].sh_name >= shstrtab_size) {
144 printf("bad debug data: string table index out of range\n");
145 continue;
146 }
147
148 const char *name = shstrtab + shdr[i].sh_name;
149 size_t offset = shdr[i].sh_offset;
150 size_t size = shdr[i].sh_size;
151
152 DEBUGF("section '%s': offset %zd (%zd bytes)\n", name, offset, size);
153
154 if (elf + offset + size > data_end) {
155 printf("bad debug data: truncated section %s\n", name);
156 continue;
157 }
158
159 for (size_t i = 0; i < manifest_len; i++) {
160 if (str_cmp(manifest[i].name, name) == 0) {
161 *manifest[i].address_field = elf + offset;
162 *manifest[i].size_field = size;
163 break;
164 }
165 }
166 }
167
168 /* Check NUL-terminator in .strtab, .debug_str and .debug_line_str */
169 _check_string_section(out.strtab, &out.strtab_size);
170 _check_string_section(out.debug_str, &out.debug_str_size);
171 _check_string_section(out.debug_line_str, &out.debug_line_str_size);
172
173 return out;
174}
175
176void register_debug_data(const void *elf, size_t elf_size)
177{
178 kernel_sections = get_debug_sections(elf, elf_size);
179}
Note: See TracBrowser for help on using the repository browser.