1
1
import gdb
2
+ import json
3
+ import os
4
+ from json import JSONDecodeError
5
+
6
+ script_directory = os .path .dirname (os .path .abspath (__file__ ))
7
+
8
+ options_path = os .path .join (script_directory , "options.json" )
9
+ pretty_printer_options = {}
10
+ try :
11
+ with open (os .path .join (script_directory , "options.json" ), "r" ) as json_file :
12
+ pretty_printer_options = json .load (json_file )
13
+ except JSONDecodeError as e :
14
+ print ("Options file at {0} failed to load. Exception: {1}" .format (options_path , e .msg ))
15
+
16
+
17
+ def get_option (value ):
18
+ return pretty_printer_options .get (value , None )
2
19
3
20
4
21
def deconstruct_dstring (val ):
@@ -38,6 +55,37 @@ def deconstruct_dstring(val):
38
55
except :
39
56
return - 1 , ""
40
57
58
+
59
+ def has_children_nodes (data_ref ):
60
+ has_subs = data_ref ["sub" ]["_M_impl" ]["_M_start" ] != data_ref ["sub" ]["_M_impl" ]["_M_finish" ]
61
+ has_named_subs = data_ref ["named_sub" ]["_M_t" ]["_M_impl" ]["_M_node_count" ] > 0
62
+ return has_subs or has_named_subs
63
+
64
+
65
+ def get_node_value (data_ref ):
66
+ """ If the item has children, wrap it in [...], if it's just a
67
+ value wrap it in quotes to help differentiate. """
68
+ has_children = has_children_nodes (data_ref )
69
+ id_value = get_id (data_ref )
70
+ if id_value :
71
+ if has_children :
72
+ return "[{0}]" .format (id_value )
73
+ else :
74
+ return "\" {0}\" " .format (id_value )
75
+ elif has_children :
76
+ return "[...]"
77
+
78
+ return "\" \" "
79
+
80
+
81
+ def get_id (data_ref ):
82
+ _ , nested_value = deconstruct_dstring (data_ref ["data" ])
83
+ if nested_value :
84
+ return nested_value .replace ("\" " , "\\ \" " )
85
+
86
+ return ""
87
+
88
+
41
89
# Class for pretty-printing dstringt
42
90
class DStringPrettyPrinter :
43
91
"Print a dstringt"
@@ -70,43 +118,85 @@ def find_type(type, name):
70
118
71
119
72
120
class IrepPrettyPrinter :
73
- "Print an irept"
121
+ """
122
+ Print an irept.
123
+
124
+ This is an array GDB type as everything in the tree is key->value, so it
125
+ works better than doing a map type with individual key/value entries.
126
+ """
74
127
75
128
def __init__ (self , val ):
76
129
self .val = val ["data" ].referenced_value ()
130
+ self .clion_representation = get_option ("clion_pretty_printers" )
77
131
78
132
def to_string (self ):
79
133
try :
80
- return "\" {}\" " .format (deconstruct_dstring (self .val [ "data" ])[ 1 ]. replace ( " \" " , " \\ \" " ))
134
+ return "\" {}\" " .format (get_id (self .val ))
81
135
except :
82
136
return "Exception pretty printing irept"
83
137
84
138
def children (self ):
139
+ """
140
+ This method tells the pretty-printer what children this object can
141
+ return. Because we've stated this is a array then we've also stated that
142
+ irept is a container that holds other values.
143
+
144
+ This makes things awkward because some ireps are not actually containers
145
+ of children but values themselves. It's hard to represent that, so instead
146
+ we return a single child with the value of the node.
147
+ """
148
+
85
149
sub = self .val ["sub" ]
86
- count = 0
150
+ sub_count = 0
87
151
item = sub ["_M_impl" ]["_M_start" ]
88
152
finish = sub ["_M_impl" ]["_M_finish" ]
89
153
while item != finish :
90
- yield "sub %d key" % count , "sub[%d]" % count
91
- yield "sub %d value" % count , item .dereference ()
92
- count += 1
154
+ # The original key is just the index, as that's all we have.
155
+ node_key = "{}" .format (sub_count )
156
+ iter_item = item .dereference ()
157
+
158
+ if self .clion_representation :
159
+ nested_id = get_node_value (iter_item ["data" ].referenced_value ())
160
+ if nested_id :
161
+ node_key = "{0}: {1}" .format (node_key , nested_id )
162
+
163
+ yield node_key , iter_item
164
+ else :
165
+ yield "sub %d key" % sub_count , node_key
166
+ yield "sub %d value" % sub_count , item .dereference ()
167
+
168
+ sub_count += 1
93
169
item += 1
94
170
95
171
named_sub = self .val ["named_sub" ]
96
172
size = named_sub ["_M_t" ]["_M_impl" ]["_M_node_count" ]
97
173
node = named_sub ["_M_t" ]["_M_impl" ]["_M_header" ]["_M_left" ]
98
- count = 0
99
- while count != size :
174
+ named_sub_count = 0
175
+ while named_sub_count != size :
100
176
rep_type = find_type (named_sub .type , "_Rep_type" )
101
177
link_type = find_type (rep_type , "_Link_type" )
102
178
node_type = link_type .strip_typedefs ()
103
179
current = node .cast (node_type ).dereference ()
104
180
addr_type = current .type .template_argument (0 ).pointer ()
105
181
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 :
182
+
183
+ # Get the name of the named_sub.
184
+ _ , sub_name = deconstruct_dstring (result ["first" ])
185
+ node_key = sub_name .replace ("\" " , "\\ \" " )
186
+
187
+ iter_item = result ["second" ]
188
+ if self .clion_representation :
189
+ nested_id = get_node_value (iter_item ["data" ].referenced_value ())
190
+ if nested_id :
191
+ node_key = "{0}: {1}" .format (node_key , nested_id )
192
+
193
+ yield node_key , iter_item
194
+ else :
195
+ yield "named_sub %d key" % named_sub_count , node_key
196
+ yield "named_sub %d value" % named_sub_count , iter_item
197
+
198
+ named_sub_count += 1
199
+ if named_sub_count < size :
110
200
# Get the next node
111
201
right = node .dereference ()["_M_right" ]
112
202
if right :
@@ -126,7 +216,7 @@ def children(self):
126
216
node = parent
127
217
128
218
def display_hint (self ):
129
- return "map"
219
+ return "array" if self . clion_representation else " map"
130
220
131
221
132
222
class InstructionPrettyPrinter :
@@ -153,6 +243,8 @@ def load_cbmc_printers():
153
243
# First argument is the name of the pretty-printer, second is a regex match for which type
154
244
# it should be applied too, third is the class that should be called to pretty-print that type.
155
245
printers .add_printer ("dstringt" , "^(?:dstringt|irep_idt)" , DStringPrettyPrinter )
246
+ printers .add_printer ("irept" , "^irept" , IrepPrettyPrinter )
156
247
printers .add_printer ("instructiont" , "^goto_programt::instructiont" , InstructionPrettyPrinter )
248
+
157
249
# We aren't associating with a particular object file, so pass in None instead of gdb.current_objfile()
158
250
gdb .printing .register_pretty_printer (None , printers , replace = True )
0 commit comments