Files
scc/runtime/runtime_gdb.py
zzy 07f5d9331b feat(lexer, preprocessor): replace cstring conversion with copy and refactor macro expansion
- Replace `scc_cstring_from_cstr(scc_cstring_as_cstr(...))` with `scc_cstring_copy()` in lexer to fix memory leaks
- Extract macro expansion logic into separate `expand_macro.c` file
- Remove `expand_stack` parameter from `scc_pp_expand_macro()` function
- Add new parsing functions for macro replacement lists and arguments
- Add string utility functions for whitespace trimming and string joining
- Update memory stream documentation for clarity
2025-12-15 20:24:39 +08:00

223 lines
7.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python-API.html#Python-API"
import gdb # type: ignore
class VectorPrinter(gdb.ValuePrinter):
"""兼容新旧注册方式的最终方案"""
def __init__(self, val: gdb.Value):
self.val: gdb.Value = val
@staticmethod
def check_type(val: gdb.Value) -> bool:
"""类型检查(兼容匿名结构体)"""
try:
if val.type.code not in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_TYPEDEF):
return False
if val.type.name == "scc_cstring_t":
return False
fields = val.type.fields()
if not fields:
return False
exp = ["size", "cap", "data"]
for t in fields:
if t.name in exp:
exp.remove(t.name)
else:
return False
return True
except gdb.error:
return False
except ValueError:
return False
except TypeError:
return False
except Exception as e:
print(f"[DEBUG] Unknown exception type: {type(e).__name__}")
print(f"[DEBUG] Exception details: {e}")
print(
f"[DEBUG] val type: {val.type if hasattr(val, 'type') else 'no type attr'}"
)
return False
def to_string(self):
"""
GDB will call this method to display the string representation
of the value passed to the object's constructor.
This is a basic method, and is optional.
When printing from the CLI, if the to_string method exists,
then GDB will prepend its result to the values returned by children.
Exactly how this formatting is done is dependent on the display hint,
and may change as more hints are added. Also, depending on the print settings
(see Print Settings), the CLI may print just the result of to_string
in a stack trace, omitting the result of children.
If this method returns a string, it is printed verbatim.
Otherwise, if this method returns an instance of gdb.Value,
then GDB prints this value. This may result in a call to another pretty-printer.
If instead the method returns a Python value which is convertible to a gdb.Value,
then GDB performs the conversion and prints the resulting value. Again,
this may result in a call to another pretty-printer. Python scalars
(integers, floats, and booleans) and strings are convertible to gdb.Value;
other types are not.
Finally, if this method returns None then no further operations are performed
in this method and nothing is printed.
If the result is not one of these types, an exception is raised.
https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API
"""
return (
f"vector({self.val.address} size={self.val['size']}, cap={self.val['cap']})"
)
def display_hint(self):
"""
The CLI may call this method and use its result to change the formatting of a value.
The result will also be supplied to an MI consumer as a 'displayhint'
attribute of the variable being printed.
This is a basic method, and is optional. If it does exist,
this method must return a string or the special value None.
Some display hints are predefined by GDB:
'array'
Indicate that the object being printed is “array-like”.
The CLI uses this to respect parameters such as set print elements and set print array.
'map'
Indicate that the object being printed is “map-like”,
and that the children of this value can be assumed to alternate between keys and values.
'string'
Indicate that the object being printed is “string-like”.
If the printer's to_string method returns a Python string of some kind,
then GDB will call its internal language-specific string-printing function
to format the string. For the CLI this means adding quotation marks, possibly
escaping some characters, respecting set print elements, and the like.
The special value None causes GDB to apply the default display rules.
https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API
"""
return "array"
def num_children(self):
"""
This is not a basic method, so GDB will only ever call it for objects
derived from gdb.ValuePrinter.
If available, this method should return the number of children.
None may be returned if the number can't readily be computed.
https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API
"""
return int(self.val["size"])
def children(self):
"""
This is not a basic method, so GDB will only ever call it for objects
derived from gdb.ValuePrinter.
If available, this method should return the child item (that is,
a tuple holding the name and value of this child) indicated by n.
Indices start at zero.
GDB provides a function which can be used to look up the default
pretty-printer for a gdb.Value:
https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API
"""
size = int(self.val["size"])
cap = int(self.val["cap"])
data_ptr = self.val["data"]
if cap == 0 or data_ptr == 0:
return []
# 使用 GDB 内置数组转换
array = data_ptr.dereference()
array = array.cast(data_ptr.type.target().array(cap - 1))
for i in range(size):
# state = "<used>" if i < size else "<unused>"
try:
value = array[i]
yield (f"[{i}] {value.type} {value.address}", value)
except gdb.MemoryError:
yield (f"[{i}]", "<invalid>")
class HashTablePrinter(gdb.ValuePrinter):
def __init__(self, val: gdb.Value):
self.val: gdb.Value = val
@staticmethod
def check_type(val: gdb.Value) -> bool:
if val.type.name in ["scc_hashtable_t", "scc_hashtable"]:
return True
return False
def append_printer():
"注册方式一传统append方法您之前有效的方式self"
gdb.pretty_printers.append(
lambda val: VectorPrinter(val) if VectorPrinter.check_type(val) else None
)
def register_new_printer():
"注册方式二:新版注册方法(备用方案)"
def str_lookup_function(val):
if VectorPrinter.check_type(val) is False:
return None
ret = VectorPrinter(val)
# print(
# f"ret {ret}, type {val.type.name}, {[(i.name, i.type) for i in val.type.fields()]}"
# )
return ret
gdb.printing.register_pretty_printer(gdb.current_objfile(), str_lookup_function)
# if gdb.current_progspace() is not None:
# pts = gdb.current_progspace().pretty_printers
# print(pts, len(pts))
# pts.append(str_lookup_function)
class VectorInfoCommand(gdb.Command):
"""保持原有命令不变"""
def __init__(self):
super().__init__("vector_info", gdb.COMMAND_USER)
def invoke(self, argument, from_tty):
val = gdb.parse_and_eval(argument)
if not VectorPrinter.check_type(val):
print("Invalid vector")
return
printer = VectorPrinter(val)
print("=== Vector Details ===")
print("Size:", val["size"])
print("Capacity:", val["cap"])
print("Elements:")
for name, value in printer.children():
print(f" {name}: {value}")
if __name__ == "__main__":
# 双重注册保证兼容性
# append_printer() # 保留您原来有效的方式
register_new_printer() # 添加新版注册
VectorInfoCommand()