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 ):
@@ -70,10 +87,16 @@ def find_type(type, name):
70
87
71
88
72
89
class IrepPrettyPrinter :
73
- "Print an irept"
90
+ """
91
+ Print an irept.
92
+
93
+ This is an array GDB type as everything in the tree is key->value, so it
94
+ works better than doing a map type with individual key/value entries.
95
+ """
74
96
75
97
def __init__ (self , val ):
76
98
self .val = val ["data" ].referenced_value ()
99
+ self .clion_representation = get_option ("clion_pretty_printers" )
77
100
78
101
def to_string (self ):
79
102
try :
@@ -82,31 +105,83 @@ def to_string(self):
82
105
return "Exception pretty printing irept"
83
106
84
107
def children (self ):
108
+ """
109
+ This method tells the pretty-printer what children this object can
110
+ return. Because we've stated this is a array then we've also stated that
111
+ irept is a container that holds other values.
112
+
113
+ This makes things awkward because some ireps are not actually containers
114
+ of children but values themselves. It's hard to represent that, so instead
115
+ we return a single child with the value of the node.
116
+ """
117
+
118
+ def get_node_value (data_ref ):
119
+ """ If the item has children, wrap it in [...], if it's just a
120
+ value wrap it in quotes to help differentiate. """
121
+ _ , nested_value = deconstruct_dstring (data_ref ["data" ])
122
+ if nested_value :
123
+ has_subs = data_ref ["sub" ]["_M_impl" ]["_M_start" ] != data_ref ["sub" ]["_M_impl" ]["_M_finish" ]
124
+ has_named_subs = data_ref ["named_sub" ]["_M_t" ]["_M_impl" ]["_M_node_count" ] > 0
125
+
126
+ stripped_value = nested_value .replace ("\" " , "\\ \" " )
127
+ if has_subs or has_named_subs :
128
+ return "[{0}]" .format (stripped_value )
129
+ else :
130
+ return "\" {0}\" " .format (stripped_value )
131
+
132
+ return ""
133
+
85
134
sub = self .val ["sub" ]
86
- count = 0
135
+ sub_count = 0
87
136
item = sub ["_M_impl" ]["_M_start" ]
88
137
finish = sub ["_M_impl" ]["_M_finish" ]
89
138
while item != finish :
90
- yield "sub %d key" % count , "sub[%d]" % count
91
- yield "sub %d value" % count , item .dereference ()
92
- count += 1
139
+ # The original key is just the index, as that's all we have.
140
+ node_key = "{}" .format (sub_count )
141
+ iter_item = item .dereference ()
142
+
143
+ if self .clion_representation :
144
+ nested_id = get_node_value (iter_item ["data" ].referenced_value ())
145
+ if nested_id :
146
+ node_key = "{0}: {1}" .format (node_key , nested_id )
147
+
148
+ yield node_key , iter_item
149
+ else :
150
+ yield "sub %d key" % sub_count , node_key
151
+ yield "sub %d value" % sub_count , item .dereference ()
152
+
153
+ sub_count += 1
93
154
item += 1
94
155
95
156
named_sub = self .val ["named_sub" ]
96
157
size = named_sub ["_M_t" ]["_M_impl" ]["_M_node_count" ]
97
158
node = named_sub ["_M_t" ]["_M_impl" ]["_M_header" ]["_M_left" ]
98
- count = 0
99
- while count != size :
159
+ named_sub_count = 0
160
+ while named_sub_count != size :
100
161
rep_type = find_type (named_sub .type , "_Rep_type" )
101
162
link_type = find_type (rep_type , "_Link_type" )
102
163
node_type = link_type .strip_typedefs ()
103
164
current = node .cast (node_type ).dereference ()
104
165
addr_type = current .type .template_argument (0 ).pointer ()
105
166
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 :
167
+
168
+ # Get the name of the named_sub.
169
+ _ , sub_name = deconstruct_dstring (result ["first" ])
170
+ node_key = sub_name .replace ("\" " , "\\ \" " )
171
+
172
+ iter_item = result ["second" ]
173
+ if self .clion_representation :
174
+ nested_id = get_node_value (iter_item ["data" ].referenced_value ())
175
+ if nested_id :
176
+ node_key = "{0}: {1}" .format (node_key , nested_id )
177
+
178
+ yield node_key , iter_item
179
+ else :
180
+ yield "named_sub %d key" % named_sub_count , node_key
181
+ yield "named_sub %d value" % named_sub_count , iter_item
182
+
183
+ named_sub_count += 1
184
+ if named_sub_count < size :
110
185
# Get the next node
111
186
right = node .dereference ()["_M_right" ]
112
187
if right :
@@ -126,7 +201,7 @@ def children(self):
126
201
node = parent
127
202
128
203
def display_hint (self ):
129
- return "map"
204
+ return "array" if self . clion_representation else " map"
130
205
131
206
132
207
class InstructionPrettyPrinter :
@@ -154,5 +229,7 @@ def load_cbmc_printers():
154
229
# it should be applied too, third is the class that should be called to pretty-print that type.
155
230
printers .add_printer ("dstringt" , "^(?:dstringt|irep_idt)" , DStringPrettyPrinter )
156
231
printers .add_printer ("instructiont" , "^goto_programt::instructiont" , InstructionPrettyPrinter )
232
+ printers .add_printer ("irept" , "^irept" , IrepPrettyPrinter )
233
+
157
234
# We aren't associating with a particular object file, so pass in None instead of gdb.current_objfile()
158
235
gdb .printing .register_pretty_printer (None , printers , replace = True )
0 commit comments