Skip to content

Commit 66ede66

Browse files
committed
Add a pretty printer extension to directly return the number of children
This avoids us needing to enumerate the children one by one (if the pretty printer supports the extension). To keep the pretty printer interface consistent, I've define the extensions in terms of the number of children returned/yielded by the `children()` function rather than the number of entries in a map, even though this means that most map pretty printers will need to multiple the number of elemnts by two, only for GALA to divide it again. I'm also passing down the `max_count` value we get from lldb, in it's useful in some pretty printers for limiting the amount of work. With llvm/llvm-project#93946, lldb will pass down reasonable values for max_count, so we might be able to remove the limiting hack on the fallback path, but I'm leaving that for a separate patch/discussion.
1 parent 6d16899 commit 66ede66

File tree

4 files changed

+68
-12
lines changed

4 files changed

+68
-12
lines changed

gdb/printing.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,16 @@ def __init__(
194194
self._children_iterator = None
195195
self._iter_count = 0
196196
self._captured_errors = []
197+
self._child_coeff = 1
197198
self.find_pretty_printer()
198199

199200
@_set_current_target
200201
def find_pretty_printer(self):
201202
try:
202203
self._pp = make_printer_func(gdb.Value(self._sbvalue))
204+
if self._get_display_hint() == 'map':
205+
# For maps two gdb children count as one lldb child
206+
self._child_coeff = 2
203207
except:
204208
self._captured_errors.append(
205209
'Error calling into GDB printer "%s".\n%s'
@@ -279,6 +283,10 @@ def _get_display_hint(self) -> str:
279283

280284
@_set_current_target
281285
def num_children(self, max_count: int) -> int:
286+
# See if the prettyprinter supports our num_children extension.
287+
if hasattr(self._pp, 'num_children'):
288+
return self._pp.num_children(max_count * self._child_coeff) // self._child_coeff
289+
282290
# gdb prettyprinters don't directly compute the number of children.
283291
# They expose a `children` iterator function instead, and it will
284292
# be called at most as many times as specified by `set print
@@ -301,12 +309,8 @@ def num_children(self, max_count: int) -> int:
301309
if print_elements is not None:
302310
max_count = min(max_count, print_elements + 1)
303311

304-
if self._get_display_hint() == 'map':
305-
self._get_children(2 * max_count)
306-
return min(len(self._children) // 2, max_count)
307-
else:
308-
self._get_children(max_count)
309-
return min(len(self._children), max_count)
312+
self._get_children(max_count * self._child_coeff)
313+
return len(self._children) // self._child_coeff
310314

311315
@_set_current_target
312316
def get_child_index(self, name: str) -> int:
@@ -319,13 +323,13 @@ def get_child_index(self, name: str) -> int:
319323

320324
@_set_current_target
321325
def get_child_at_index(self, index: int) -> Optional[lldb.SBValue]:
326+
self._get_children((index + 1) * self._child_coeff)
322327
# lldb-vscode currently relies on the fact that passing an invalid
323328
# index to SBValue.GetChildAtIndex "works" (it returns a non-valid
324329
# SBValue). Asserting here causes scary error messages in the log,
325330
# so just return None for compatibility.
326-
if self._get_display_hint() == 'map':
327-
self._get_children(2 * (index + 1))
328-
if index < (len(self._children) / 2):
331+
if index < (len(self._children) // self._child_coeff):
332+
if self._get_display_hint() == 'map':
329333
key = self._children[index * 2][1]
330334
val = self._children[index * 2 + 1][1]
331335
if isinstance(key, gdb.Value):
@@ -337,9 +341,7 @@ def get_child_at_index(self, index: int) -> Optional[lldb.SBValue]:
337341
else:
338342
key_str = str(key)
339343
return _named_sbvalue(self._sbvalue, '[%s]' % key_str, val)
340-
else:
341-
self._get_children(index + 1)
342-
if index < len(self._children):
344+
else:
343345
c = self._children[index]
344346
return _named_sbvalue(self._sbvalue, c[0], c[1])
345347
return None

test/lit/num_children.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Test our num_children pretty printer extension.
2+
3+
RUN: %clangxx -g -o %t num_children/test_program.cc
4+
RUN: %lldb %t -b \
5+
RUN: -o 'settings set target.max-children-count 142' \
6+
RUN: -o 'script import num_children' \
7+
RUN: -o 'script print("num_children = ", lldb.target.FindFirstGlobalVariable("s").GetNumChildren(47))' \
8+
RUN: -o 'script print("MAX_MAX_COUNT = ", num_children.MyStructPrinter.MAX_MAX_COUNT)' \
9+
RUN: -o 'target variable s' \
10+
RUN: -o 'script print("MAX_MAX_COUNT = ", num_children.MyStructPrinter.MAX_MAX_COUNT)' \
11+
RUN: | FileCheck %s
12+
13+
CHECK: num_children = 2
14+
CHECK: MAX_MAX_COUNT = 94
15+
CHECK: (MyStruct) s = A pretty MyStruct {
16+
CHECK-NEXT: [key0] = "val0"
17+
CHECK-NEXT: [key1] = "val1"
18+
CHECK-NEXT: }
19+
# 2 * (142 + 1)
20+
CHECK: MAX_MAX_COUNT = 286

test/lit/num_children/__init__.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import gdb
2+
import gdb.printing
3+
4+
class MyStructPrinter:
5+
MAX_MAX_COUNT = 0
6+
7+
def __init__(self, val):
8+
self._val = val
9+
10+
def display_hint(self):
11+
return "map"
12+
13+
def to_string(self):
14+
return "A pretty MyStruct"
15+
16+
def num_children(self, max_count):
17+
MyStructPrinter.MAX_MAX_COUNT = max(MyStructPrinter.MAX_MAX_COUNT, max_count)
18+
return 4
19+
20+
def children(self):
21+
yield "key[0]", "key0"
22+
yield "val[0]", "val0"
23+
yield "key[1]", "key1"
24+
yield "val[1]", "val1"
25+
26+
printer = gdb.printing.RegexpCollectionPrettyPrinter("test_regexp_printer")
27+
printer.add_printer("MyStruct", "MyStruct", MyStructPrinter)
28+
29+
gdb.printing.register_pretty_printer(gdb.current_objfile(), printer)

test/lit/num_children/test_program.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
struct MyStruct {};
2+
3+
MyStruct s;
4+
5+
int main() { return 0; }

0 commit comments

Comments
 (0)