source: mainline/kernel/generic/src/debug/util.h

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