Skip to content

Commit

Permalink
Merge pull request #28 from plasma-umass/print-test
Browse files Browse the repository at this point in the history
Added test locals printing command to GDB
  • Loading branch information
khlevin authored Jan 12, 2024
2 parents 3d4f3eb + a506e0b commit 8400ba2
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
96 changes: 96 additions & 0 deletions src/chatdbg/chatdbg_gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import pathlib
import sys
import json

import gdb

Expand Down Expand Up @@ -170,3 +171,98 @@ def buildPrompt() -> str:
pass

return (source_code, stack_trace, last_error_type)

class PrintTest(gdb.Command):
"""print all variables in a run while recursing through pointers, keeping track of seen addresses
"""
def __init__(self):
super().__init__("print-test", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, True)

def invoke(self, arg, from_tty):
help_string = 'Usage: wzd [recurse_max]\n\nrecurse_max: The maximum number of times to recurse through nested structs or pointers to pointers. Default: 3'
if arg == '--help':
print(help_string)
return
recurse_max = 3
if arg != "":
try: recurse_max = int(arg)
except ValueError as e:
print(f"recurse_max value could not be parsed: {e}")
return
if (recurse_max < 1):
print("recurse_max value must be at least 1.")
return
frame = gdb.selected_frame()
block = gdb.block_for_pc(frame.pc())


# Second pass through vars, converting each to JSON
all_vars = []
addresses = {}
for symbol in block:
if symbol.is_argument or symbol.is_variable:
variable = {} # Create python dictionary for each variable
sym_val = frame.read_var(symbol)
variable = self._val_to_json(symbol.name, sym_val, recurse_max, addresses)
# Store address
addresses[frame.read_var(symbol).address.format_string()] = symbol.name
js = json.dumps(variable, indent=4)
all_vars.append(js)

print(addresses)
# Print all JSON objects
for j in all_vars:
print(j)

# Converts a gdb.Value to a JSON object
def _val_to_json(self, name, val, max_recurse, address_book):
diction = {}
# Set var name
diction['name'] = name
# Set var type
if val.type.code is gdb.TYPE_CODE_PTR:
diction['type'] = 'pointer' # Default type name is "none"
elif val.type.code is gdb.TYPE_CODE_ARRAY:
diction['type'] = 'array' # Default type name is "none"
else:
diction['type'] = val.type.name
# Dereference pointers
if val.type.code is gdb.TYPE_CODE_PTR:
if val:
value = "->"
try:
deref_val = val.referenced_value()
# If dereferenced value is "seen", then get name from address book
if deref_val.address.format_string() in address_book:
diction['value'] = address_book[deref_val.address.format_string()]
else:
# Recurse up to max_recurse times
for i in range(max_recurse - 1):
if deref_val.type.code is gdb.TYPE_CODE_PTR:
value += '->'
deref_val = deref_val.referenced_value()
elif deref_val.type.code is gdb.TYPE_CODE_STRUCT:
value = self._val_to_json(None, deref_val, max_recurse - i - 1, address_book)
break
else:
break
if isinstance(value, dict):
diction['value'] = value
else:
diction['value'] = value + deref_val.format_string()
except Exception as e:
diction['value'] = value + "Exception"
else:
# Nullptr case, might be a better way to represent
diction['value'] = "nullptr"
# If struct, recurse through fields
elif val.type.code is gdb.TYPE_CODE_STRUCT:
fields = []
for f in val.type.fields():
fields.append(self._val_to_json(f.name, val[f.name], max_recurse - 1, address_book))
diction['value'] = fields
else:
diction['value'] = val.format_string()
return diction

PrintTest()
Binary file added test/a.out
Binary file not shown.

0 comments on commit 8400ba2

Please sign in to comment.