Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added test locals printing command to GDB #28

Merged
merged 4 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like arg contains the entire string after the command, we should be able to parse options this way. (I like argparse personally).

We could use this to add timeout, llm, and other options, provided LLDB has similar functionality.

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.