Skip to content

Commit 36dc29a

Browse files
Merge pull request #4960 from diffblue/NathanJPhillips/feature/irep-pretty-printer
Add a pretty printer for irept
2 parents 7ef8430 + e1e5092 commit 36dc29a

File tree

1 file changed

+113
-33
lines changed

1 file changed

+113
-33
lines changed

Diff for: scripts/pretty-printers/gdb/pretty_printers.py

+113-33
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,43 @@
11
import gdb
22

33

4+
def deconstruct_dstring(val):
5+
# ideally, we want to access the memory where the string
6+
# is stored directly instead of calling a function. However,
7+
# this is simpler.
8+
try:
9+
raw_address = str(val.address)
10+
11+
# If it's ::empty, we know it's empty without going further.
12+
if "::empty" in raw_address:
13+
return -1, ""
14+
15+
# Split the address on the first space, return that value
16+
# Addresses are usually {address} {optional type_name}
17+
typed_pointer = "((const {} *){})".format(val.type, raw_address.split(None, 1)[0])
18+
19+
string_no = val["no"]
20+
21+
# Check that the pointer is not null.
22+
null_ptr = gdb.parse_and_eval("{} == 0".format(typed_pointer))
23+
if null_ptr.is_optimized_out:
24+
return -1, "{}: <Ptr optimized out>".format(string_no)
25+
if null_ptr:
26+
return -1, ""
27+
28+
table_len = gdb.parse_and_eval("get_string_container().string_vector.size()")
29+
if table_len.is_optimized_out:
30+
return -1, "{}: <Table len optimized out>".format(string_no)
31+
if string_no >= table_len:
32+
return -1, "{} index ({}) out of range".format(val.type, string_no)
33+
34+
value = gdb.parse_and_eval("{}->c_str()".format(typed_pointer))
35+
if value.is_optimized_out:
36+
return -1, "{}: <Optimized out>".format(string_no)
37+
return string_no, value.string().replace("\0", "")
38+
except:
39+
return -1, ""
40+
441
# Class for pretty-printing dstringt
542
class DStringPrettyPrinter:
643
"Print a dstringt"
@@ -9,44 +46,87 @@ def __init__(self, val):
946
self.val = val
1047

1148
def to_string(self):
12-
# ideally, we want to access the memory where the string
13-
# is stored directly instead of calling a function. However,
14-
# this is simpler.
49+
string_no, value = deconstruct_dstring(self.val)
50+
if string_no == -1:
51+
return value
52+
return "{}: \"{}\"".format(string_no, value.replace("\"", "\\\""))
53+
54+
def display_hint(self):
55+
return None
56+
57+
58+
def find_type(type, name):
59+
type = type.strip_typedefs()
60+
while True:
61+
# Strip cv-qualifiers.
62+
search = "%s::%s" % (type.unqualified(), name)
1563
try:
16-
raw_address = str(self.val.address)
64+
return gdb.lookup_type(search)
65+
except RuntimeError:
66+
pass
67+
# The type was not found, so try the superclass.
68+
# We only need to check the first superclass.
69+
type = type.fields()[0].type
70+
1771

18-
# If it's ::empty, we know it's empty without going further.
19-
if "::empty" in raw_address:
20-
return ""
21-
22-
# Split the address on the first space, return that value
23-
# Addresses are usually {address} {optional type_name}
24-
typed_pointer = "((const {} *){})".format(self.val.type, raw_address.split(None, 1)[0])
25-
26-
string_no = self.val["no"]
27-
28-
# Check that the pointer is not null.
29-
null_ptr = gdb.parse_and_eval("{} == 0".format(typed_pointer))
30-
if null_ptr.is_optimized_out:
31-
return "{}: <Ptr optimized out>".format(string_no)
32-
if null_ptr:
33-
return ""
34-
35-
table_len = gdb.parse_and_eval("get_string_container().string_vector.size()")
36-
if table_len.is_optimized_out:
37-
return "{}: <Table len optimized out>".format(string_no)
38-
if string_no >= table_len:
39-
return "{} index ({}) out of range".format(self.val.type, string_no)
40-
41-
value = gdb.parse_and_eval("{}->c_str()".format(typed_pointer))
42-
if value.is_optimized_out:
43-
return "{}: <Optimized out>".format(string_no)
44-
return "{}: \"{}\"".format(string_no, value.string().replace("\0", "").replace("\"", "\\\""))
72+
class IrepPrettyPrinter:
73+
"Print an irept"
74+
75+
def __init__(self, val):
76+
self.val = val["data"].referenced_value()
77+
78+
def to_string(self):
79+
try:
80+
return "\"{}\"".format(deconstruct_dstring(self.val["data"])[1].replace("\"", "\\\""))
4581
except:
46-
return ""
82+
return "Exception pretty printing irept"
83+
84+
def children(self):
85+
sub = self.val["sub"]
86+
count = 0
87+
item = sub["_M_impl"]["_M_start"]
88+
finish = sub["_M_impl"]["_M_finish"]
89+
while item != finish:
90+
yield "sub %d key" % count, "sub[%d]" % count
91+
yield "sub %d value" % count, item.dereference()
92+
count += 1
93+
item += 1
94+
95+
named_sub = self.val["named_sub"]
96+
size = named_sub["_M_t"]["_M_impl"]["_M_node_count"]
97+
node = named_sub["_M_t"]["_M_impl"]["_M_header"]["_M_left"]
98+
count = 0
99+
while count != size:
100+
rep_type = find_type(named_sub.type, "_Rep_type")
101+
link_type = find_type(rep_type, "_Link_type")
102+
node_type = link_type.strip_typedefs()
103+
current = node.cast(node_type).dereference()
104+
addr_type = current.type.template_argument(0).pointer()
105+
result = current["_M_storage"]["_M_storage"].address.cast(addr_type).dereference()
106+
yield "named_sub %d key" % count, "named_sub[\"%s\"]" % deconstruct_dstring(result["first"])[1].replace("\"", "\\\"")
107+
yield "named_sub %d value" % count, result["second"]
108+
count += 1
109+
if count < size:
110+
# Get the next node
111+
right = node.dereference()["_M_right"]
112+
if right:
113+
node = right
114+
while True:
115+
left = node.dereference()["_M_left"]
116+
if not left:
117+
break
118+
node = left
119+
else:
120+
parent = node.dereference()["_M_parent"]
121+
while node == parent.dereference()["_M_right"]:
122+
node = parent
123+
parent = parent.dereference()["_M_parent"]
124+
# Not sure what this checks
125+
if node.dereference()["_M_right"] != parent:
126+
node = parent
47127

48128
def display_hint(self):
49-
return None
129+
return "map"
50130

51131

52132
class InstructionPrettyPrinter:

0 commit comments

Comments
 (0)