source: mainline/kernel/generic/src/debug/util.h@ 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: 6.6 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#ifndef DEBUG_UTIL_H_
30#define DEBUG_UTIL_H_
31
32#include <assert.h>
33#include <stdint.h>
34#include <debug/constants.h>
35#include <debug.h>
36
37#define DEBUGF dummy_printf
38
39extern bool skip_data(unsigned, const uint8_t **const, const uint8_t *, unsigned);
40extern void print_format(const char *, const uint8_t *, const uint8_t *);
41extern void print_formatted_list(const char *, const uint8_t *, const uint8_t *,
42 const uint8_t *, const uint8_t *, unsigned);
43
44extern void print_block(const uint8_t **, const uint8_t *, unsigned);
45extern void print_formed_data(unsigned, const uint8_t **const, const uint8_t *, unsigned);
46
47inline uint8_t read_byte(const uint8_t **data, const uint8_t *data_end)
48{
49 if (*data >= data_end) {
50 return 0;
51 } else {
52 return *((*data)++);
53 }
54}
55
56inline uint16_t read_uint16(const uint8_t **data, const uint8_t *data_end)
57{
58 /* Casting to these structures allows us to read unaligned integers safely. */
59 struct u16 {
60 uint16_t val;
61 } __attribute__((packed));
62
63 if (*data + 2 > data_end) {
64 /* Safe exit path for malformed input. */
65 *data = data_end;
66 return 0;
67 }
68
69 uint16_t v = ((struct u16 *) *data)->val;
70 *data += 2;
71 return v;
72}
73
74inline uint32_t read_uint24(const uint8_t **data, const uint8_t *data_end)
75{
76 if (*data + 3 > data_end) {
77 /* Safe exit path for malformed input. */
78 *data = data_end;
79 return 0;
80 }
81
82#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
83 uint32_t v = (*data)[0] | (*data)[1] << 8 | (*data)[2] << 16;
84#else
85 uint32_t v = (*data)[2] | (*data)[1] << 8 | (*data)[0] << 16;
86#endif
87
88 *data += 3;
89 return v;
90}
91
92inline uint32_t read_uint32(const uint8_t **data, const uint8_t *data_end)
93{
94 struct u32 {
95 uint32_t val;
96 } __attribute__((packed));
97
98 if (*data + 4 > data_end) {
99 /* Safe exit path for malformed input. */
100 *data = data_end;
101 return 0;
102 }
103
104 uint32_t v = ((struct u32 *) *data)->val;
105 *data += 4;
106 return v;
107}
108
109inline uint64_t read_uint64(const uint8_t **data, const uint8_t *data_end)
110{
111 struct u64 {
112 uint64_t val;
113 } __attribute__((packed));
114
115 if (*data + 8 > data_end) {
116 /* Safe exit path for malformed input. */
117 *data = data_end;
118 return 0;
119 }
120
121 uint64_t v = ((struct u64 *) *data)->val;
122 *data += 8;
123 return v;
124}
125
126inline uint64_t read_uint(const uint8_t **data, const uint8_t *data_end, unsigned bytes)
127{
128 switch (bytes) {
129 case 1:
130 return read_byte(data, data_end);
131 case 2:
132 return read_uint16(data, data_end);
133 case 4:
134 return read_uint32(data, data_end);
135 case 8:
136 return read_uint64(data, data_end);
137 default:
138 panic("unimplemented");
139 }
140}
141
142inline uint64_t read_uleb128(const uint8_t **data, const uint8_t *data_end)
143{
144 uint64_t result = 0;
145 unsigned shift = 0;
146
147 while (*data < data_end) {
148 uint8_t byte = *((*data)++);
149 result |= (byte & 0x7f) << shift;
150 shift += 7;
151
152 if ((byte & 0x80) == 0)
153 break;
154 }
155
156 return result;
157}
158
159inline int64_t read_sleb128(const uint8_t **data, const uint8_t *data_end)
160{
161 uint64_t result = 0;
162 unsigned shift = 0;
163
164 while (*data < data_end) {
165 uint8_t byte = *((*data)++);
166 result |= (byte & 0x7f) << shift;
167 shift += 7;
168
169 if ((byte & 0x80) == 0) {
170 if (shift < 64 && (byte & 0x40) != 0) {
171 /* sign extend */
172 result |= -(1 << shift);
173 }
174 break;
175 }
176 }
177
178 return (int64_t) result;
179}
180
181inline void skip_leb128(const uint8_t **data, const uint8_t *data_end)
182{
183 while (*data < data_end) {
184 uint8_t byte = *((*data)++);
185 if ((byte & 0x80) == 0)
186 break;
187 }
188}
189
190inline uint64_t read_initial_length(const uint8_t **data, const uint8_t *data_end, unsigned *width)
191{
192 uint32_t initial = read_uint32(data, data_end);
193 if (initial == 0xffffffffu) {
194 *width = 8;
195 return read_uint64(data, data_end);
196 } else {
197 *width = 4;
198 return initial;
199 }
200}
201
202inline const char *read_string(const uint8_t **data, const uint8_t *data_end)
203{
204 const char *start = (const char *) *data;
205
206 // NUL-terminated string.
207 while (*data < data_end && **data != 0)
208 (*data)++;
209
210 if (*data < data_end) {
211 // Skip the terminating zero.
212 (*data)++;
213 return start;
214 } else {
215 // No terminating zero, we can't use this.
216 return NULL;
217 }
218}
219
220inline void skip_string(const uint8_t **data, const uint8_t *data_end)
221{
222 (void) read_string(data, data_end);
223}
224
225inline void safe_increment(const uint8_t **data,
226 const uint8_t *data_end, ptrdiff_t increment)
227{
228 assert(data_end >= *data);
229
230 if (increment >= data_end - *data) {
231 *data = data_end;
232 } else {
233 (*data) += increment;
234 }
235}
236
237inline void skip_format(const uint8_t **data, const uint8_t *const data_end,
238 unsigned count)
239{
240 for (unsigned i = 0; i < count; i++) {
241 (void) read_uleb128(data, data_end);
242 (void) read_uleb128(data, data_end);
243 }
244}
245
246inline void skip_formatted_entry(const uint8_t **data, const uint8_t *const data_end,
247 const uint8_t *format, const uint8_t *format_end, unsigned width)
248{
249 while (format < format_end) {
250 /* Ignore content type code */
251 (void) read_uleb128(&format, format_end);
252
253 uint64_t form = read_uleb128(&format, format_end);
254 skip_data(form, data, data_end, width);
255 }
256}
257
258inline void skip_formatted_list(const uint8_t **data, const uint8_t *const data_end,
259 unsigned count, const uint8_t *format, const uint8_t *format_end,
260 unsigned width)
261{
262 for (unsigned i = 0; i < count; i++) {
263 skip_formatted_entry(data, data_end, format, format_end, width);
264 }
265}
266
267#endif /* DEBUG_UTIL_H_ */
Note: See TracBrowser for help on using the repository browser.