Skip to content

Commit 924b2c6

Browse files
committed
Add GDB formatters for darray and dvec (#10)
- Lets you run `source scripts/gdb/init` in the debugger to pretty-print dvec and darray types
1 parent 93b4363 commit 924b2c6

8 files changed

Lines changed: 193 additions & 6 deletions

File tree

.zed/debug.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"program": "$ZED_WORKTREE_ROOT/build/examples/pdf-example",
1010
"request": "launch",
11-
"adapter": "CodeLLDB"
11+
"adapter": "GDB"
1212
},
1313
{
1414
"label": "Debug font-example",
@@ -19,7 +19,7 @@
1919
},
2020
"program": "$ZED_WORKTREE_ROOT/build/examples/font-example",
2121
"request": "launch",
22-
"adapter": "CodeLLDB"
22+
"adapter": "GDB"
2323
},
2424
{
2525
"label": "Debug tessellation-example",
@@ -30,7 +30,7 @@
3030
},
3131
"program": "$ZED_WORKTREE_ROOT/build/examples/tessellation-example",
3232
"request": "launch",
33-
"adapter": "CodeLLDB"
33+
"adapter": "GDB"
3434
},
3535
{
3636
"label": "Debug cmap-example",
@@ -41,7 +41,7 @@
4141
},
4242
"program": "$ZED_WORKTREE_ROOT/build/examples/cmap-example",
4343
"request": "launch",
44-
"adapter": "CodeLLDB"
44+
"adapter": "GDB"
4545
},
4646
{
4747
"label": "Debug test",
@@ -50,11 +50,11 @@
5050
"args": [],
5151
"cwd": "$ZED_WORKTREE_ROOT",
5252
"env": {
53-
"DEBUG_TEST_FUNCTION": "test_postscript_tokenize_single_plus_name_non_eof"
53+
"DEBUG_TEST_FUNCTION": "test_vec_growth"
5454
}
5555
},
5656
"program": "$ZED_WORKTREE_ROOT/build/libs/test/pdf-test-main",
5757
"request": "launch",
58-
"adapter": "CodeLLDB"
58+
"adapter": "GDB"
5959
}
6060
]

libs/arena/include/arena/darray_impl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
#include <stdbool.h>
2+
#include <stdint.h>
23
#include <string.h>
34

45
#include "arena/arena.h"
56
#include "logger/log.h"
67

8+
#define DARRAY_DEBUG_MAGIC 0x4152525F444247ULL
9+
710
// Check arguments
811
#ifndef DARRAY_NAME
912
#error "DARRAY_NAME is not defined"
@@ -33,6 +36,9 @@ typedef struct DARRAY_NAME DARRAY_NAME;
3336
struct DARRAY_NAME {
3437
size_t len;
3538
DARRAY_TYPE* elements;
39+
40+
/// Marker field so that the lldb formatter can detect arrays.
41+
uint64_t dbg_magic;
3642
};
3743

3844
// Creates a new arena-backed array of a set size with uninitialized elements
@@ -49,6 +55,7 @@ DARRAY_NAME* DARRAY_FN(new)(Arena* arena, size_t num_elements) {
4955

5056
DARRAY_NAME* array = arena_alloc(arena, sizeof(DARRAY_NAME));
5157
array->len = num_elements;
58+
array->dbg_magic = DARRAY_DEBUG_MAGIC;
5259

5360
if (num_elements != 0) {
5461
array->elements =
@@ -160,6 +167,7 @@ DARRAY_TYPE* DARRAY_FN(get_raw)(const DARRAY_NAME* array, size_t* len_out) {
160167
}
161168

162169
// Undefines
170+
#undef DARRAY_DEBUG_MAGIC
163171
#undef DARRAY_NAME
164172
#undef DARRAY_LOWERCASE_NAME
165173
#undef DARRAY_TYPE

libs/arena/include/arena/dvec_impl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#include <stdbool.h>
2+
#include <stdint.h>
23

34
#include "arena/arena.h"
45
#include "logger/log.h"
56

7+
#define DVEC_DEBUG_MAGIC 0x5645435F444247ULL
8+
69
#ifndef DVEC_SRC
710
#define DVEC_SRC
811
#ifdef _MSC_VER
@@ -60,6 +63,9 @@ struct DVEC_NAME {
6063
size_t len;
6164
size_t allocated_blocks;
6265
DVEC_TYPE* blocks[DVEC_MAX_BLOCKS];
66+
67+
/// Marker field so that the lldb formatter can detect vecs.
68+
uint64_t dbg_magic;
6369
};
6470

6571
// Creates a new arena-backed vector with zero elements
@@ -77,6 +83,7 @@ DVEC_NAME* DVEC_FN(new)(Arena* arena) {
7783
vec->len = 0;
7884
vec->allocated_blocks = 0;
7985
vec->blocks[0] = NULL;
86+
vec->dbg_magic = DVEC_DEBUG_MAGIC;
8087

8188
return vec;
8289
}
@@ -223,6 +230,7 @@ size_t DVEC_FN(len)(const DVEC_NAME* vec) {
223230
}
224231

225232
// Undefines
233+
#undef DVEC_DEBUG_MAGIC
226234
#undef DVEC_NAME
227235
#undef DVEC_LOWERCASE_NAME
228236
#undef DVEC_TYPE

scripts/gdb/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__

scripts/gdb/darray_gdb.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import gdb
2+
import fmt_helpers
3+
4+
DARRAY_DEBUG_MAGIC = 0x4152525F444247
5+
6+
7+
class DArrayPrinter:
8+
def __init__(self, val):
9+
self.val = fmt_helpers.strip_ptr_and_typedefs(val)
10+
11+
try:
12+
self.length = int(self.val["len"])
13+
except Exception:
14+
self.length = 0
15+
16+
try:
17+
self.elements = self.val["elements"]
18+
except Exception:
19+
self.elements = None
20+
21+
def to_string(self):
22+
return f"darray[{self.length}]"
23+
24+
def children(self):
25+
if not self.elements:
26+
return
27+
28+
try:
29+
element_type = self.elements.type
30+
31+
if self.length < 0:
32+
return
33+
for idx in range(self.length):
34+
try:
35+
yield ("[%d]" % idx, self.elements[idx])
36+
except Exception:
37+
yield ("[%d]" % idx, "<error reading element>")
38+
except Exception:
39+
return
40+
41+
def display_hint(self):
42+
return "array"
43+
44+
45+
def darray_printer_lookup(val):
46+
try:
47+
candidate = fmt_helpers.strip_ptr_and_typedefs(val)
48+
magic_field = candidate["dbg_magic"]
49+
magic = int(magic_field)
50+
except Exception:
51+
return None
52+
53+
if magic == DARRAY_DEBUG_MAGIC:
54+
return DArrayPrinter(val)
55+
56+
return None
57+
58+
59+
def register_darray_printers(objfile=None):
60+
if objfile is None:
61+
gdb.pretty_printers.append(darray_printer_lookup)
62+
else:
63+
gdb.printing.register_pretty_printer_for_object_file(objfile, darray_printer_lookup)
64+
65+
66+
register_darray_printers()

scripts/gdb/dvec_gdb.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import gdb
2+
import fmt_helpers
3+
import math
4+
5+
DVEC_DEBUG_MAGIC = 0x5645435F444247
6+
7+
8+
class DVecPrinter:
9+
def __init__(self, val):
10+
self.val = fmt_helpers.strip_ptr_and_typedefs(val)
11+
12+
try:
13+
self.length = int(self.val["len"])
14+
except Exception:
15+
self.length = 0
16+
17+
try:
18+
self.num_blocks = int(self.val["allocated_blocks"])
19+
except Exception:
20+
self.num_blocks = 0
21+
22+
try:
23+
self.blocks = self.val["blocks"]
24+
except Exception:
25+
self.blocks = None
26+
27+
def to_string(self):
28+
return f"dvec[{self.length}] ({self.num_blocks} blocks)"
29+
30+
def children(self):
31+
if not self.blocks:
32+
return
33+
34+
try:
35+
block_type = self.blocks.type
36+
37+
if self.length < 0:
38+
return
39+
for idx in range(self.length):
40+
block_idx = math.floor(math.log2(idx + 1))
41+
idx_in_block = idx - (2**block_idx - 1)
42+
43+
if block_idx >= self.num_blocks or idx < 0:
44+
yield (f"[{idx}]", "shit")
45+
else:
46+
try:
47+
yield (f"[{idx}]", self.blocks[block_idx][idx_in_block])
48+
except Exception:
49+
yield (f"[{idx}]", "<error reading element>")
50+
except Exception:
51+
return
52+
53+
def display_hint(self):
54+
return "array"
55+
56+
57+
def dvec_printer_lookup(val):
58+
try:
59+
candidate = fmt_helpers.strip_ptr_and_typedefs(val)
60+
magic_field = candidate["dbg_magic"]
61+
magic = int(magic_field)
62+
except Exception:
63+
return None
64+
65+
if magic == DVEC_DEBUG_MAGIC:
66+
return DVecPrinter(val)
67+
68+
return None
69+
70+
71+
def register_dvec_printers(objfile=None):
72+
if objfile is None:
73+
gdb.pretty_printers.append(dvec_printer_lookup)
74+
else:
75+
gdb.printing.register_pretty_printer_for_object_file(objfile, dvec_printer_lookup)
76+
77+
78+
register_dvec_printers()

scripts/gdb/fmt_helpers.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import gdb
2+
3+
def strip_ptr_and_typedefs(val):
4+
"""Helper function to remove pointers, qualifiers and typedefs from a value"""
5+
typ = val.type
6+
7+
# Strips typedefs and qualifiers
8+
try:
9+
typ = typ.strip_typedefs()
10+
except Exception:
11+
pass
12+
13+
# Deference pointers
14+
if typ.code == gdb.TYPE_CODE_PTR:
15+
try:
16+
return val.dereference()
17+
except gdb.error:
18+
# Return original value if deference fails (ie. due to NULL)
19+
return val
20+
return val

scripts/gdb/init

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
python
2+
import sys, os
3+
sys.path.insert(0, os.path.join(os.getcwd(), "scripts", "gdb"))
4+
import darray_gdb
5+
import dvec_gdb
6+
end

0 commit comments

Comments
 (0)