Merge pull request #4960 from diffblue/NathanJPhillips/feature/irep-pretty-printer

Add a pretty printer for irept
This commit is contained in:
Nathan Phillips 2019-08-13 10:25:22 +01:00 committed by GitHub
commit 36dc29a4e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 115 additions and 35 deletions

View File

@ -1,6 +1,43 @@
import gdb import gdb
def deconstruct_dstring(val):
# ideally, we want to access the memory where the string
# is stored directly instead of calling a function. However,
# this is simpler.
try:
raw_address = str(val.address)
# If it's ::empty, we know it's empty without going further.
if "::empty" in raw_address:
return -1, ""
# Split the address on the first space, return that value
# Addresses are usually {address} {optional type_name}
typed_pointer = "((const {} *){})".format(val.type, raw_address.split(None, 1)[0])
string_no = val["no"]
# Check that the pointer is not null.
null_ptr = gdb.parse_and_eval("{} == 0".format(typed_pointer))
if null_ptr.is_optimized_out:
return -1, "{}: <Ptr optimized out>".format(string_no)
if null_ptr:
return -1, ""
table_len = gdb.parse_and_eval("get_string_container().string_vector.size()")
if table_len.is_optimized_out:
return -1, "{}: <Table len optimized out>".format(string_no)
if string_no >= table_len:
return -1, "{} index ({}) out of range".format(val.type, string_no)
value = gdb.parse_and_eval("{}->c_str()".format(typed_pointer))
if value.is_optimized_out:
return -1, "{}: <Optimized out>".format(string_no)
return string_no, value.string().replace("\0", "")
except:
return -1, ""
# Class for pretty-printing dstringt # Class for pretty-printing dstringt
class DStringPrettyPrinter: class DStringPrettyPrinter:
"Print a dstringt" "Print a dstringt"
@ -9,46 +46,89 @@ class DStringPrettyPrinter:
self.val = val self.val = val
def to_string(self): def to_string(self):
# ideally, we want to access the memory where the string string_no, value = deconstruct_dstring(self.val)
# is stored directly instead of calling a function. However, if string_no == -1:
# this is simpler. return value
try: return "{}: \"{}\"".format(string_no, value.replace("\"", "\\\""))
raw_address = str(self.val.address)
# If it's ::empty, we know it's empty without going further.
if "::empty" in raw_address:
return ""
# Split the address on the first space, return that value
# Addresses are usually {address} {optional type_name}
typed_pointer = "((const {} *){})".format(self.val.type, raw_address.split(None, 1)[0])
string_no = self.val["no"]
# Check that the pointer is not null.
null_ptr = gdb.parse_and_eval("{} == 0".format(typed_pointer))
if null_ptr.is_optimized_out:
return "{}: <Ptr optimized out>".format(string_no)
if null_ptr:
return ""
table_len = gdb.parse_and_eval("get_string_container().string_vector.size()")
if table_len.is_optimized_out:
return "{}: <Table len optimized out>".format(string_no)
if string_no >= table_len:
return "{} index ({}) out of range".format(self.val.type, string_no)
value = gdb.parse_and_eval("{}->c_str()".format(typed_pointer))
if value.is_optimized_out:
return "{}: <Optimized out>".format(string_no)
return "{}: \"{}\"".format(string_no, value.string().replace("\0", "").replace("\"", "\\\""))
except:
return ""
def display_hint(self): def display_hint(self):
return None return None
def find_type(type, name):
type = type.strip_typedefs()
while True:
# Strip cv-qualifiers.
search = "%s::%s" % (type.unqualified(), name)
try:
return gdb.lookup_type(search)
except RuntimeError:
pass
# The type was not found, so try the superclass.
# We only need to check the first superclass.
type = type.fields()[0].type
class IrepPrettyPrinter:
"Print an irept"
def __init__(self, val):
self.val = val["data"].referenced_value()
def to_string(self):
try:
return "\"{}\"".format(deconstruct_dstring(self.val["data"])[1].replace("\"", "\\\""))
except:
return "Exception pretty printing irept"
def children(self):
sub = self.val["sub"]
count = 0
item = sub["_M_impl"]["_M_start"]
finish = sub["_M_impl"]["_M_finish"]
while item != finish:
yield "sub %d key" % count, "sub[%d]" % count
yield "sub %d value" % count, item.dereference()
count += 1
item += 1
named_sub = self.val["named_sub"]
size = named_sub["_M_t"]["_M_impl"]["_M_node_count"]
node = named_sub["_M_t"]["_M_impl"]["_M_header"]["_M_left"]
count = 0
while count != size:
rep_type = find_type(named_sub.type, "_Rep_type")
link_type = find_type(rep_type, "_Link_type")
node_type = link_type.strip_typedefs()
current = node.cast(node_type).dereference()
addr_type = current.type.template_argument(0).pointer()
result = current["_M_storage"]["_M_storage"].address.cast(addr_type).dereference()
yield "named_sub %d key" % count, "named_sub[\"%s\"]" % deconstruct_dstring(result["first"])[1].replace("\"", "\\\"")
yield "named_sub %d value" % count, result["second"]
count += 1
if count < size:
# Get the next node
right = node.dereference()["_M_right"]
if right:
node = right
while True:
left = node.dereference()["_M_left"]
if not left:
break
node = left
else:
parent = node.dereference()["_M_parent"]
while node == parent.dereference()["_M_right"]:
node = parent
parent = parent.dereference()["_M_parent"]
# Not sure what this checks
if node.dereference()["_M_right"] != parent:
node = parent
def display_hint(self):
return "map"
class InstructionPrettyPrinter: class InstructionPrettyPrinter:
def __init__(self, val): def __init__(self, val):
self.val = val self.val = val