Skip to content

Commit 58301ff

Browse files
Merge pull request #4942 from diffblue/feature/irep_idt_pretty
irep_idt pretty printer improvements
2 parents 6f8cafd + 2eca2b1 commit 58301ff

File tree

3 files changed

+81
-68
lines changed

3 files changed

+81
-68
lines changed

scripts/pretty-printers/gdb/auto_load.py

-24
This file was deleted.

scripts/pretty-printers/gdb/install.py

100644100755
+42-35
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,70 @@
1-
#!/usr/bin/env python
1+
#!/usr/bin/env python3
22

33
import os
4-
5-
# This is the code that should be copied if you're applying the changes by hand.
6-
# Replace {0} with the path to this folder.
7-
file_contents = """
8-
python
9-
import sys
10-
import os
11-
12-
pretty_printer_folder = '{0}'
13-
if os.path.exists(pretty_printer_folder):
14-
sys.path.insert(1, pretty_printer_folder)
15-
import auto_load
16-
auto_load.load_pretty_printers()
17-
end
18-
"""
4+
from shutil import copyfile
195

206

217
def create_gdbinit_file():
228
"""
23-
Add or append to a .gdbinit file the python code to set-up cbmc pretty-printers.
9+
Create and insert into a .gdbinit file the python code to set-up cbmc pretty-printers.
2410
"""
2511

2612
print("Attempting to enable cbmc-specific pretty-printers.")
2713

2814
home_folder = os.path.expanduser("~")
2915
if not home_folder:
30-
print(home_folder + " is an invalid home folder, please manually create a .gdbinit file and apply the code.")
16+
print(home_folder + " is an invalid home folder, can't auto-configure .gdbinit.")
3117
return
3218

19+
# This is the code that should be copied if you're applying the changes by hand.
20+
gdb_directory = os.path.dirname(os.path.abspath(__file__))
21+
code_block_start = "cbmc_printers_folder = "
22+
code_block = \
23+
[
24+
"{0}'{1}'".format(code_block_start, gdb_directory),
25+
"if os.path.exists(cbmc_printers_folder):",
26+
" sys.path.insert(1, cbmc_printers_folder)",
27+
" from pretty_printers import load_cbmc_printers",
28+
" load_cbmc_printers()",
29+
]
30+
3331
gdbinit_file = os.path.join(home_folder, ".gdbinit")
34-
file_write_mode = 'w'
32+
lines = []
3533
if os.path.exists(gdbinit_file):
36-
print(".gdbinit file exists at " + gdbinit_file + "."
37-
" Please type 'y' if you want to append the pretty-printer commands to it. Press any other key to exit.")
38-
while True:
39-
choice = input().lower()
40-
if choice == 'y':
41-
file_write_mode = 'a'
42-
break
43-
else:
44-
print("Not appending to file. Exiting.")
34+
with open(gdbinit_file, 'r') as file:
35+
lines = [ line.rstrip() for line in file ]
36+
line_no = 0
37+
imports = { "os", "sys" }
38+
while line_no < len(lines):
39+
if lines[line_no].startswith('import '):
40+
imports.add(lines[line_no][len("import "):].strip())
41+
lines.pop(line_no)
42+
else:
43+
if lines[line_no].startswith(code_block_start):
44+
print(".gdbinit already contains our pretty printers, not changing it")
4545
return
46+
line_no += 1
47+
while len(lines) != 0 and (lines[0] == "" or lines[0] == "python"):
48+
lines.pop(0)
4649

47-
if file_write_mode == 'w':
48-
print("Creating .gdbinit file.")
50+
lines = [ "python" ] + list(map("import {}".format, sorted(imports))) + [ "", "" ] + code_block + [ "", "" ] + lines + [ "" ]
4951

52+
backup_file = os.path.join(home_folder, "backup.gdbinit")
53+
if os.path.exists(backup_file):
54+
print("backup.gdbinit file already exists. Type 'y' if you would like to overwrite it or any other key to exit.")
55+
choice = input().lower()
56+
if choice != 'y':
57+
return
58+
print("Backing up {0}".format(gdbinit_file))
59+
copyfile(gdbinit_file, backup_file)
5060
print("Adding pretty-print commands to {0}.".format(gdbinit_file))
51-
parent_directory = os.path.dirname(os.path.abspath(__file__))
5261
try:
53-
file = open(gdbinit_file, file_write_mode)
54-
file.write(file_contents.format(parent_directory))
55-
file.close()
62+
with open(gdbinit_file, 'w+') as file:
63+
file.write('\n'.join(lines))
5664
print("Commands added.")
5765
except:
5866
print("Exception occured writing to file. Please apply changes manually.")
5967

6068

6169
if __name__ == "__main__":
6270
create_gdbinit_file()
63-
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import gdb
22

33

4+
# Class for pretty-printing dstringt
45
class DStringPrettyPrinter:
6+
"Print a dstringt"
7+
58
def __init__(self, val):
69
self.val = val
710

811
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.
915
try:
1016
raw_address = str(self.val.address)
1117

@@ -15,20 +21,32 @@ def to_string(self):
1521

1622
# Split the address on the first space, return that value
1723
# Addresses are usually {address} {optional type_name}
18-
typed_pointer = '({}*){}'.format(self.val.type, raw_address.split(None, 1)[0])
24+
typed_pointer = "((const {} *){})".format(self.val.type, raw_address.split(None, 1)[0])
25+
26+
string_no = self.val["no"]
1927

2028
# Check that the pointer is not null.
21-
if gdb.parse_and_eval(typed_pointer + ' == 0'):
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:
2233
return ""
2334

24-
# If it isn't attempt to find the string.
25-
value = '(*{})'.format(typed_pointer)
26-
return gdb.parse_and_eval(value + '.c_str()')
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("\"", "\\\""))
2745
except:
2846
return ""
2947

3048
def display_hint(self):
31-
return 'string'
49+
return None
3250

3351

3452
class InstructionPrettyPrinter:
@@ -38,11 +56,23 @@ def __init__(self, val):
3856
def to_string(self):
3957
try:
4058
raw_address = str(self.val.address)
41-
variable_accessor = '(*({}*){})'.format(self.val.type, raw_address.split(None, 1)[0])
42-
expr = '{0}.to_string()'.format(variable_accessor)
59+
variable_accessor = "(*({}*){})".format(self.val.type, raw_address.split(None, 1)[0])
60+
expr = "{0}.to_string()".format(variable_accessor)
4361
return gdb.parse_and_eval(expr)
4462
except:
4563
return ""
4664

4765
def display_hint(self):
48-
return 'string'
66+
return "string"
67+
68+
69+
# If you change the name of this make sure to change install.py too.
70+
def load_cbmc_printers():
71+
printers = gdb.printing.RegexpCollectionPrettyPrinter("CBMC")
72+
73+
# First argument is the name of the pretty-printer, second is a regex match for which type
74+
# it should be applied too, third is the class that should be called to pretty-print that type.
75+
printers.add_printer("dstringt", "^(?:dstringt|irep_idt)", DStringPrettyPrinter)
76+
printers.add_printer("instructiont", "^goto_programt::instructiont", InstructionPrettyPrinter)
77+
# We aren't associating with a particular object file, so pass in None instead of gdb.current_objfile()
78+
gdb.printing.register_pretty_printer(None, printers, replace=True)

0 commit comments

Comments
 (0)