Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/ddb/db_pprint.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2022 Bojan Novković <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. 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
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/systm.h>
30
#include <sys/ctype.h>
31
#include <sys/linker.h>
32
#include <sys/stdarg.h>
33
34
#include <ddb/ddb.h>
35
#include <ddb/db_ctf.h>
36
#include <ddb/db_lex.h>
37
#include <ddb/db_sym.h>
38
#include <ddb/db_access.h>
39
40
#define DB_PPRINT_DEFAULT_DEPTH 1
41
42
static void db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type,
43
u_int depth);
44
45
static u_int max_depth = DB_PPRINT_DEFAULT_DEPTH;
46
static struct db_ctf_sym_data sym_data;
47
static const char *asteriskstr = "*****";
48
49
/*
50
* Pretty-prints a CTF_INT type.
51
*/
52
static inline void
53
db_pprint_int(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
54
{
55
uint32_t data;
56
size_t type_struct_size;
57
58
type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ?
59
sizeof(struct ctf_type_v3) :
60
sizeof(struct ctf_stype_v3);
61
62
data = db_get_value((db_expr_t)type + type_struct_size,
63
sizeof(uint32_t), 0);
64
u_int bits = CTF_INT_BITS(data);
65
boolean_t sign = !!(CTF_INT_ENCODING(data) & CTF_INT_SIGNED);
66
67
if (db_pager_quit) {
68
return;
69
}
70
if (bits > 64) {
71
db_printf("Invalid size '%d' found for integer type\n", bits);
72
return;
73
}
74
db_printf("0x%lx",
75
(long)db_get_value(addr, (bits / 8) ? (bits / 8) : 1, sign));
76
}
77
78
/*
79
* Pretty-prints a struct. Nested structs are pretty-printed up 'depth' nested
80
* levels.
81
*/
82
static inline void
83
db_pprint_struct(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
84
{
85
size_t type_struct_size;
86
size_t struct_size;
87
struct ctf_type_v3 *mtype;
88
const char *mname;
89
db_addr_t maddr;
90
u_int vlen;
91
92
type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ?
93
sizeof(struct ctf_type_v3) :
94
sizeof(struct ctf_stype_v3);
95
struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ?
96
CTF_TYPE_LSIZE(type) :
97
type->ctt_size);
98
vlen = CTF_V3_INFO_VLEN(type->ctt_info);
99
100
if (db_pager_quit) {
101
return;
102
}
103
if (depth > max_depth) {
104
db_printf("{ ... }");
105
return;
106
}
107
db_printf("{\n");
108
109
if (struct_size < CTF_V3_LSTRUCT_THRESH) {
110
struct ctf_member_v3 *mp, *endp;
111
112
mp = (struct ctf_member_v3 *)((db_addr_t)type +
113
type_struct_size);
114
endp = mp + vlen;
115
for (; mp < endp; mp++) {
116
if (db_pager_quit) {
117
return;
118
}
119
mtype = db_ctf_typeid_to_type(&sym_data, mp->ctm_type);
120
maddr = addr + (mp->ctm_offset / NBBY);
121
mname = db_ctf_stroff_to_str(&sym_data, mp->ctm_name);
122
db_indent = depth;
123
if (mname != NULL) {
124
db_iprintf("%s = ", mname);
125
} else {
126
db_iprintf("");
127
}
128
129
db_pprint_type(maddr, mtype, depth + 1);
130
db_printf(",\n");
131
}
132
} else {
133
struct ctf_lmember_v3 *mp, *endp;
134
135
mp = (struct ctf_lmember_v3 *)((db_addr_t)type +
136
type_struct_size);
137
endp = mp + vlen;
138
for (; mp < endp; mp++) {
139
if (db_pager_quit) {
140
return;
141
}
142
mtype = db_ctf_typeid_to_type(&sym_data, mp->ctlm_type);
143
maddr = addr + (CTF_LMEM_OFFSET(mp) / NBBY);
144
mname = db_ctf_stroff_to_str(&sym_data, mp->ctlm_name);
145
db_indent = depth;
146
if (mname != NULL) {
147
db_iprintf("%s = ", mname);
148
} else {
149
db_iprintf("");
150
}
151
152
db_pprint_type(maddr, mtype, depth + 1);
153
db_printf(",");
154
}
155
}
156
db_indent = depth - 1;
157
db_iprintf("}");
158
}
159
160
/*
161
* Pretty-prints an array. Each array member is printed out in a separate line
162
* indented with 'depth' spaces.
163
*/
164
static inline void
165
db_pprint_arr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
166
{
167
struct ctf_type_v3 *elem_type;
168
struct ctf_array_v3 *arr;
169
db_addr_t elem_addr, end;
170
size_t type_struct_size;
171
size_t elem_size;
172
173
type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ?
174
sizeof(struct ctf_type_v3) :
175
sizeof(struct ctf_stype_v3);
176
arr = (struct ctf_array_v3 *)((db_addr_t)type + type_struct_size);
177
elem_type = db_ctf_typeid_to_type(&sym_data, arr->cta_contents);
178
elem_size = ((elem_type->ctt_size == CTF_V3_LSIZE_SENT) ?
179
CTF_TYPE_LSIZE(elem_type) :
180
elem_type->ctt_size);
181
elem_addr = addr;
182
end = addr + (arr->cta_nelems * elem_size);
183
184
db_indent = depth;
185
db_printf("[\n");
186
/* Loop through and print individual elements. */
187
for (; elem_addr < end; elem_addr += elem_size) {
188
if (db_pager_quit) {
189
return;
190
}
191
db_iprintf("");
192
db_pprint_type(elem_addr, elem_type, depth);
193
if ((elem_addr + elem_size) < end) {
194
db_printf(",\n");
195
}
196
}
197
db_printf("\n");
198
db_indent = depth - 1;
199
db_iprintf("]");
200
}
201
202
/*
203
* Pretty-prints an enum value. Also prints out symbolic name of value, if any.
204
*/
205
static inline void
206
db_pprint_enum(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
207
{
208
struct ctf_enum *ep, *endp;
209
size_t type_struct_size;
210
const char *valname;
211
db_expr_t val;
212
u_int vlen;
213
214
type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ?
215
sizeof(struct ctf_type_v3) :
216
sizeof(struct ctf_stype_v3);
217
vlen = CTF_V3_INFO_VLEN(type->ctt_info);
218
val = db_get_value(addr, sizeof(int), 0);
219
220
if (db_pager_quit) {
221
return;
222
}
223
ep = (struct ctf_enum *)((db_addr_t)type + type_struct_size);
224
endp = ep + vlen;
225
for (; ep < endp; ep++) {
226
if (val == ep->cte_value) {
227
valname = db_ctf_stroff_to_str(&sym_data, ep->cte_name);
228
if (valname != NULL) {
229
db_printf("%s (0x%lx)", valname, (long)val);
230
break;
231
}
232
}
233
}
234
if (ep == endp)
235
db_printf("0x%lx", (long)val);
236
}
237
238
/*
239
* Pretty-prints a pointer. If the 'depth' parameter is less than the
240
* 'max_depth' global var, the pointer is "dereference", i.e. the contents of
241
* the memory it points to are also printed. The value of the pointer is printed
242
* otherwise.
243
*/
244
static inline void
245
db_pprint_ptr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
246
{
247
struct ctf_type_v3 *ref_type;
248
const char *qual = "";
249
const char *name;
250
db_addr_t val;
251
uint32_t tid;
252
u_int kind;
253
int ptrcnt;
254
255
ptrcnt = 1;
256
tid = type->ctt_type;
257
again:
258
ref_type = db_ctf_typeid_to_type(&sym_data, tid);
259
kind = CTF_V3_INFO_KIND(ref_type->ctt_info);
260
switch (kind) {
261
case CTF_K_STRUCT:
262
qual = "struct ";
263
break;
264
case CTF_K_VOLATILE:
265
qual = "volatile ";
266
tid = ref_type->ctt_type;
267
goto again;
268
case CTF_K_CONST:
269
qual = "const ";
270
tid = ref_type->ctt_type;
271
goto again;
272
case CTF_K_RESTRICT:
273
qual = "restrict ";
274
tid = ref_type->ctt_type;
275
goto again;
276
case CTF_K_POINTER:
277
ptrcnt++;
278
tid = ref_type->ctt_type;
279
goto again;
280
case CTF_K_TYPEDEF:
281
tid = ref_type->ctt_type;
282
goto again;
283
default:
284
break;
285
}
286
287
ptrcnt = min(ptrcnt, strlen(asteriskstr));
288
val = (addr != 0) ? db_get_value(addr, sizeof(db_addr_t), false) : 0;
289
if (depth < max_depth && (val != 0)) {
290
/* Print contents of memory pointed to by this pointer. */
291
db_pprint_type(val, ref_type, depth + 1);
292
} else {
293
name = db_ctf_stroff_to_str(&sym_data, ref_type->ctt_name);
294
db_indent = depth;
295
if (name != NULL)
296
db_printf("(%s%s %.*s) 0x%lx", qual, name, ptrcnt,
297
asteriskstr, (long)val);
298
else
299
db_printf("(%s %.*s) 0x%lx", qual, ptrcnt, asteriskstr,
300
(long)val);
301
}
302
}
303
304
/*
305
* Pretty-print dispatching function.
306
*/
307
static void
308
db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
309
{
310
311
if (db_pager_quit) {
312
return;
313
}
314
if (type == NULL) {
315
db_printf("unknown type");
316
return;
317
}
318
319
switch (CTF_V3_INFO_KIND(type->ctt_info)) {
320
case CTF_K_INTEGER:
321
db_pprint_int(addr, type, depth);
322
break;
323
case CTF_K_UNION:
324
case CTF_K_STRUCT:
325
db_pprint_struct(addr, type, depth);
326
break;
327
case CTF_K_FUNCTION:
328
case CTF_K_FLOAT:
329
db_indent = depth;
330
db_iprintf("0x%lx", (long)addr);
331
break;
332
case CTF_K_POINTER:
333
db_pprint_ptr(addr, type, depth);
334
break;
335
case CTF_K_TYPEDEF:
336
case CTF_K_VOLATILE:
337
case CTF_K_RESTRICT:
338
case CTF_K_CONST: {
339
struct ctf_type_v3 *ref_type = db_ctf_typeid_to_type(&sym_data,
340
type->ctt_type);
341
db_pprint_type(addr, ref_type, depth);
342
break;
343
}
344
case CTF_K_ENUM:
345
db_pprint_enum(addr, type, depth);
346
break;
347
case CTF_K_ARRAY:
348
db_pprint_arr(addr, type, depth);
349
break;
350
case CTF_K_UNKNOWN:
351
case CTF_K_FORWARD:
352
default:
353
break;
354
}
355
}
356
357
/*
358
* Symbol pretty-printing command.
359
* Syntax: pprint [/d depth] <sym_name>
360
*/
361
static void
362
db_pprint_symbol_cmd(const char *name)
363
{
364
db_addr_t addr;
365
int db_indent_old;
366
const char *type_name = NULL;
367
struct ctf_type_v3 *type = NULL;
368
369
if (db_pager_quit) {
370
return;
371
}
372
/* Clear symbol and CTF info */
373
memset(&sym_data, 0, sizeof(struct db_ctf_sym_data));
374
if (db_ctf_find_symbol(name, &sym_data) != 0) {
375
db_error("Symbol not found\n");
376
}
377
if (ELF_ST_TYPE(sym_data.sym->st_info) != STT_OBJECT) {
378
db_error("Symbol is not a variable\n");
379
}
380
addr = sym_data.sym->st_value;
381
type = db_ctf_sym_to_type(&sym_data);
382
if (type == NULL) {
383
db_error("Can't find CTF type info\n");
384
}
385
type_name = db_ctf_stroff_to_str(&sym_data, type->ctt_name);
386
if (type_name != NULL)
387
db_printf("%s ", type_name);
388
db_printf("%s = ", name);
389
390
db_indent_old = db_indent;
391
db_pprint_type(addr, type, 0);
392
db_indent = db_indent_old;
393
}
394
395
/*
396
* Command for pretty-printing arbitrary addresses.
397
* Syntax: pprint [/d depth] struct <struct_name> <addr>
398
*/
399
static void
400
db_pprint_struct_cmd(db_expr_t addr, const char *struct_name)
401
{
402
int db_indent_old;
403
struct ctf_type_v3 *type = NULL;
404
405
type = db_ctf_find_typename(&sym_data, struct_name);
406
if (type == NULL) {
407
db_error("Can't find CTF type info\n");
408
return;
409
}
410
411
db_printf("struct %s ", struct_name);
412
db_printf("%p = ", (void *)addr);
413
414
db_indent_old = db_indent;
415
db_pprint_type(addr, type, 0);
416
db_indent = db_indent_old;
417
}
418
419
/*
420
* Pretty print an address or a symbol.
421
*/
422
void
423
db_pprint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
424
{
425
int t = 0;
426
const char *name;
427
428
/* Set default depth */
429
max_depth = DB_PPRINT_DEFAULT_DEPTH;
430
/* Parse print modifiers */
431
t = db_read_token();
432
if (t == tSLASH) {
433
t = db_read_token();
434
if (t != tIDENT) {
435
db_error("Invalid flag passed\n");
436
}
437
/* Parse desired depth level */
438
if (strcmp(db_tok_string, "d") == 0) {
439
t = db_read_token();
440
if (t != tNUMBER) {
441
db_error("Invalid depth provided\n");
442
}
443
max_depth = db_tok_number;
444
} else {
445
db_error("Invalid flag passed\n");
446
}
447
/* Fetch next token */
448
t = db_read_token();
449
}
450
/* Parse subcomannd */
451
if (t == tIDENT) {
452
if (strcmp(db_tok_string, "struct") == 0) {
453
t = db_read_token();
454
455
if (t != tIDENT) {
456
db_error("Invalid struct type name provided\n");
457
}
458
name = db_tok_string;
459
460
if (db_expression(&addr) == 0) {
461
db_error("Address not provided\n");
462
}
463
db_pprint_struct_cmd(addr, name);
464
} else {
465
name = db_tok_string;
466
db_pprint_symbol_cmd(name);
467
}
468
} else {
469
db_error("Invalid subcommand\n");
470
}
471
db_skip_to_eol();
472
}
473
474