Merge pull request #4960 from diffblue/NathanJPhillips/feature/irep-pretty-printer
Add a pretty printer for irept
This commit is contained in:
commit
36dc29a4e2
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue