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

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

Add printing of file names and line numbers in stacktraces

Uses DWARF ¾/5 .debug_line section (originally intended
to only support DWARF 5, but GCC emits lower versioned sections
regardless of command line arguments on some platforms for some
reason, so generic support it is).

Also adds a whole lot of definitions for various DWARF constants
I expect to be useful in the future.

The quickest way to test this probably is to run test fault1
in kernel console.

  • Property mode set to 100644
File size: 7.8 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 "util.h"
30
31#include <stdio.h>
32#include <debug/sections.h>
33#include <debug/names.h>
34
35/* These declarations cause global definitions for the functions to be emitted
36 * in this compilation unit, so if the compiler decides not to inline some of
37 * them, only one external copy exists. See C99 inline rules.
38 */
39extern inline uint8_t read_byte(const uint8_t **, const uint8_t *);
40extern inline uint16_t read_uint16(const uint8_t **, const uint8_t *);
41extern inline uint32_t read_uint24(const uint8_t **, const uint8_t *);
42extern inline uint32_t read_uint32(const uint8_t **, const uint8_t *);
43extern inline uint64_t read_uint64(const uint8_t **, const uint8_t *);
44extern inline uint64_t read_uint(const uint8_t **, const uint8_t *, unsigned);
45extern inline uint64_t read_uleb128(const uint8_t **, const uint8_t *);
46extern inline int64_t read_sleb128(const uint8_t **, const uint8_t *);
47extern inline void skip_leb128(const uint8_t **, const uint8_t *);
48extern inline uint64_t read_initial_length(const uint8_t **, const uint8_t *, unsigned *);
49extern inline const char *read_string(const uint8_t **, const uint8_t *);
50extern inline void skip_string(const uint8_t **, const uint8_t *);
51extern inline void safe_increment(const uint8_t **, const uint8_t *, ptrdiff_t);
52
53extern inline void skip_format(const uint8_t **, const uint8_t *, unsigned);
54extern inline void skip_formatted_entry(const uint8_t **, const uint8_t *,
55 const uint8_t *, const uint8_t *, unsigned);
56extern inline void skip_formatted_list(const uint8_t **, const uint8_t *,
57 unsigned, const uint8_t *, const uint8_t *, unsigned);
58
59bool skip_data(unsigned form, const uint8_t **const data,
60 const uint8_t *data_end, unsigned width)
61{
62 // Skip data we don't care about reading.
63
64 size_t len;
65
66 switch (form) {
67 case DW_FORM_string:
68 skip_string(data, data_end);
69 break;
70
71 case DW_FORM_strp:
72 case DW_FORM_line_strp:
73 case DW_FORM_strp_sup:
74 case DW_FORM_sec_offset:
75 safe_increment(data, data_end, width);
76 break;
77
78 case DW_FORM_strx:
79 case DW_FORM_sdata:
80 case DW_FORM_udata:
81 skip_leb128(data, data_end);
82 break;
83
84 case DW_FORM_strx1:
85 case DW_FORM_data1:
86 case DW_FORM_flag:
87 safe_increment(data, data_end, 1);
88 break;
89
90 case DW_FORM_strx2:
91 case DW_FORM_data2:
92 safe_increment(data, data_end, 2);
93 break;
94
95 case DW_FORM_strx3:
96 safe_increment(data, data_end, 3);
97 break;
98
99 case DW_FORM_strx4:
100 case DW_FORM_data4:
101 safe_increment(data, data_end, 4);
102 break;
103
104 case DW_FORM_data8:
105 safe_increment(data, data_end, 8);
106 break;
107
108 case DW_FORM_data16:
109 safe_increment(data, data_end, 16);
110 break;
111
112 case DW_FORM_block:
113 len = read_uleb128(data, data_end);
114 safe_increment(data, data_end, len);
115 break;
116
117 case DW_FORM_block1:
118 len = read_byte(data, data_end);
119 safe_increment(data, data_end, len);
120 break;
121
122 case DW_FORM_block2:
123 len = read_uint16(data, data_end);
124 safe_increment(data, data_end, len);
125 break;
126
127 case DW_FORM_block4:
128 len = read_uint32(data, data_end);
129 safe_increment(data, data_end, len);
130 break;
131
132 default:
133 // Unknown FORM.
134 *data = data_end;
135 return false;
136 }
137
138 return true;
139}
140
141void print_format(const char *name, const uint8_t *format, const uint8_t *format_end)
142{
143 DEBUGF("%s: ", name);
144
145 while (format < format_end) {
146 uint64_t lnct = read_uleb128(&format, format_end);
147 uint64_t form = read_uleb128(&format, format_end);
148
149 const char *fname = dw_form_name(form);
150
151 if (fname)
152 DEBUGF("%s:%s, ", dw_lnct_name(lnct), fname);
153 else
154 DEBUGF("%s:unknown DW_FORM_(%" PRIu64 "), ", dw_lnct_name(lnct), form);
155 }
156
157 DEBUGF("\n");
158}
159
160void print_formatted_list(const char *name,
161 const uint8_t *data, const uint8_t *const data_end,
162 const uint8_t *format, const uint8_t *format_end,
163 unsigned width)
164{
165 DEBUGF("%s: ", name);
166
167 while (data < data_end) {
168 const uint8_t *old_data = data;
169 const uint8_t *format_ptr = format;
170
171 while (format_ptr < format_end) {
172 uint64_t lnct = read_uleb128(&format_ptr, format_end);
173 uint64_t form = read_uleb128(&format_ptr, format_end);
174
175 DEBUGF("%s:%s:", dw_lnct_name(lnct), dw_form_name(form));
176 print_formed_data(form, &data, data_end, width);
177 DEBUGF("\n");
178 }
179
180 if (data <= old_data)
181 break;
182 }
183
184 DEBUGF("\n");
185}
186
187void print_block(const uint8_t **const data,
188 const uint8_t *data_end, unsigned bytes)
189{
190 while (bytes > 0 && *data < data_end) {
191 DEBUGF("%02x ", **data);
192 (*data)++;
193 bytes--;
194 }
195}
196
197void print_formed_data(unsigned form, const uint8_t **const data,
198 const uint8_t *data_end, unsigned width)
199{
200 size_t len;
201 uint64_t offset;
202
203 switch (form) {
204 case DW_FORM_string:
205 DEBUGF("\"%s\"", read_string(data, data_end));
206 break;
207
208 case DW_FORM_strp:
209 case DW_FORM_strp_sup:
210 offset = read_uint(data, data_end, width);
211 if (offset >= debug_str_size)
212 DEBUGF("<out of range>");
213 else
214 DEBUGF("\"%s\"", debug_str + offset);
215 break;
216
217 case DW_FORM_line_strp:
218 offset = read_uint(data, data_end, width);
219 if (offset >= debug_line_str_size)
220 DEBUGF("<out of range>");
221 else
222 DEBUGF("\"%s\"", debug_line_str + offset);
223 break;
224
225 case DW_FORM_sec_offset:
226 if (width == 4)
227 DEBUGF("0x%08" PRIx64, read_uint(data, data_end, width));
228 else
229 DEBUGF("0x%016" PRIx64, read_uint(data, data_end, width));
230 break;
231
232 case DW_FORM_strx:
233 case DW_FORM_udata:
234 DEBUGF("%" PRIu64, read_uleb128(data, data_end));
235 break;
236
237 case DW_FORM_sdata:
238 DEBUGF("%" PRId64, read_sleb128(data, data_end));
239 break;
240
241 case DW_FORM_strx1:
242 case DW_FORM_data1:
243 case DW_FORM_flag:
244 DEBUGF("%u", read_byte(data, data_end));
245 break;
246
247 case DW_FORM_strx2:
248 case DW_FORM_data2:
249 DEBUGF("%u", read_uint16(data, data_end));
250 break;
251
252 case DW_FORM_strx3:
253 DEBUGF("%u", read_uint24(data, data_end));
254 break;
255
256 case DW_FORM_strx4:
257 case DW_FORM_data4:
258 DEBUGF("%u", read_uint32(data, data_end));
259 break;
260
261 case DW_FORM_data8:
262 DEBUGF("%" PRIu64, read_uint64(data, data_end));
263 break;
264
265 case DW_FORM_data16:
266 uint64_t data1 = read_uint64(data, data_end);
267 uint64_t data2 = read_uint64(data, data_end);
268 DEBUGF("0x%016"PRIx64"%016"PRIx64, data2, data1);
269 break;
270
271 case DW_FORM_block:
272 len = read_uleb128(data, data_end);
273 print_block(data, data_end, len);
274 break;
275
276 case DW_FORM_block1:
277 len = read_byte(data, data_end);
278 print_block(data, data_end, len);
279 break;
280
281 case DW_FORM_block2:
282 len = read_uint16(data, data_end);
283 print_block(data, data_end, len);
284 break;
285
286 case DW_FORM_block4:
287 len = read_uint32(data, data_end);
288 print_block(data, data_end, len);
289 break;
290
291 default:
292 DEBUGF("unexpected form");
293 *data = data_end;
294 }
295}
Note: See TracBrowser for help on using the repository browser.