diff options
Diffstat (limited to 'tools/nim-gdb.py')
-rw-r--r-- | tools/nim-gdb.py | 151 |
1 files changed, 94 insertions, 57 deletions
diff --git a/tools/nim-gdb.py b/tools/nim-gdb.py index e994531b6..8143b94d5 100644 --- a/tools/nim-gdb.py +++ b/tools/nim-gdb.py @@ -34,6 +34,14 @@ def getNimRti(type_name): except: return None +def getNameFromNimRti(rti_val): + """ Return name (or None) given a Nim RTI ``gdb.Value`` """ + try: + # sometimes there isn't a name field -- example enums + return rti['name'].string(encoding="utf-8", errors="ignore") + except: + return None + class NimTypeRecognizer: # this type map maps from types that are generated in the C files to # how they are called in nim. To not mix up the name ``int`` from @@ -42,30 +50,25 @@ class NimTypeRecognizer: # ``int``. type_map_static = { - 'NI': 'system.int', 'NI8': 'int8', 'NI16': 'int16', 'NI32': 'int32', 'NI64': 'int64', - 'NU': 'uint', 'NU8': 'uint8','NU16': 'uint16', 'NU32': 'uint32', 'NU64': 'uint64', + 'NI': 'system.int', 'NI8': 'int8', 'NI16': 'int16', 'NI32': 'int32', + 'NI64': 'int64', + + 'NU': 'uint', 'NU8': 'uint8','NU16': 'uint16', 'NU32': 'uint32', + 'NU64': 'uint64', + 'NF': 'float', 'NF32': 'float32', 'NF64': 'float64', - 'NIM_BOOL': 'bool', 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', - 'NimStringDesc': 'string' + + 'NIM_BOOL': 'bool', + + 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', 'NimStringDesc': 'string' } - # Normally gdb distinguishes between the command `ptype` and - # `whatis`. `ptype` prints a very detailed view of the type, and - # `whatis` a very brief representation of the type. I haven't - # figured out a way to know from the type printer that is - # implemented here how to know if a type printer should print the - # short representation or the long representation. As a hacky - # workaround I just say I am not resposible for printing pointer - # types (seq and string are exception as they are semantically - # values). this way the default type printer will handle pointer - # types and dive into the members of that type. So I can still - # control with `ptype myval` and `ptype *myval` if I want to have - # detail or not. I this this method stinks but I could not figure - # out a better solution. - - object_type_pattern = re.compile("^(\w*):ObjectType$") + # object_type_pattern = re.compile("^(\w*):ObjectType$") def recognize(self, type_obj): + # skip things we can't handle like functions + if type_obj.code in [gdb.TYPE_CODE_FUNC, gdb.TYPE_CODE_VOID]: + return None tname = None if type_obj.tag is not None: @@ -75,44 +78,43 @@ class NimTypeRecognizer: # handle pointer types if not tname: - if type_obj.code == gdb.TYPE_CODE_PTR: + target_type = type_obj + if type_obj.code in [gdb.TYPE_CODE_PTR]: target_type = type_obj.target() - target_type_name = target_type.name - if target_type_name: - # visualize 'string' as non pointer type (unpack pointer type). - if target_type_name == "NimStringDesc": - tname = target_type_name # could also just return 'string' - # visualize 'seq[T]' as non pointer type. - if target_type_name.find('tySequence_') == 0: - tname = target_type_name - if not tname: - # We are not resposible for this type printing. - # Basically this means we don't print pointer types. - return None + if target_type.name: + # visualize 'string' as non pointer type (unpack pointer type). + if target_type.name == "NimStringDesc": + tname = target_type.name # could also just return 'string' + else: + rti = getNimRti(target_type.name) + if rti: + return getNameFromNimRti(rti) - result = self.type_map_static.get(tname, None) - if result: - return result + if tname: + result = self.type_map_static.get(tname, None) + if result: + return result - rti = getNimRti(tname) - if rti: - return rti['name'].string("utf-8", "ignore") - else: - return None + rti = getNimRti(tname) + if rti: + return getNameFromNimRti(rti) + + return None class NimTypePrinter: """Nim type printer. One printer for all Nim types.""" - # enabling and disabling of type printers can be done with the # following gdb commands: # # enable type-printer NimTypePrinter # disable type-printer NimTypePrinter + # relevant docs: https://sourceware.org/gdb/onlinedocs/gdb/Type-Printing-API.html name = "NimTypePrinter" - def __init__ (self): + + def __init__(self): self.enabled = True def instantiate(self): @@ -309,9 +311,25 @@ class NimStringPrinter: def to_string(self): if self.val: l = int(self.val['Sup']['len']) - return self.val['data'][0].address.string("utf-8", "ignore", l) + return self.val['data'].lazy_string(encoding="utf-8", length=l) else: - return "" + return "" + +# class NimStringPrinter: +# pattern = re.compile(r'^NimStringDesc$') + +# def __init__(self, val): +# self.val = val + +# def display_hint(self): +# return 'string' + +# def to_string(self): +# if self.val: +# l = int(self.val['Sup']['len']) +# return self.val['data'].lazy_string(encoding="utf-8", length=l) +# else: +# return "" class NimRopePrinter: pattern = re.compile(r'^tyObject_RopeObj__([A-Za-z0-9]*) \*$') @@ -372,14 +390,15 @@ class NimEnumPrinter: pattern = re.compile(r'^tyEnum_(\w*)__([A-Za-z0-9]*)$') def __init__(self, val): - self.val = val - match = self.pattern.match(self.val.type.name) + self.val = val + typeName = self.val.type.name + match = self.pattern.match(typeName) self.typeNimName = match.group(1) typeInfoName = "NTI__" + match.group(2) + "_" self.nti = gdb.lookup_global_symbol(typeInfoName) if self.nti is None: - printErrorOnce(typeInfoName, "NimEnumPrinter: lookup global symbol '" + typeInfoName + " failed for " + self.val.type.name + ".\n") + printErrorOnce(typeInfoName, f"NimEnumPrinter: lookup global symbol '{typeInfoName}' failed for {typeName}.\n") def to_string(self): if self.nti: @@ -476,11 +495,31 @@ class NimSeqPrinter: def children(self): if self.val: - length = int(self.val['Sup']['len']) - #align = len(str(length - 1)) - for i in range(length): - yield ("data[{0}]".format(i), self.val["data"][i]) + val = self.val + valType = val.type + length = int(val['Sup']['len']) + if length <= 0: + return + + dataType = valType['data'].type + data = val['data'] + + if self.val.type.name is None: + dataType = valType['data'].type.target().pointer() + data = val['data'].cast(dataType) + + inaccessible = False + for i in range(length): + if inaccessible: + return + try: + str(data[i]) + yield "data[{0}]".format(i), data[i] + except RuntimeError: + inaccessible = True + yield "data[{0}]".format(i), "inaccessible" + ################################################################################ class NimArrayPrinter: @@ -524,9 +563,9 @@ class NimStringTablePrinter: def children(self): if self.val: - data = NimSeqPrinter(self.val['data']) + data = NimSeqPrinter(self.val['data'].dereference()) for idxStr, entry in data.children(): - if int(entry['Field2']) > 0: + if int(entry['Field0']) != 0: yield (idxStr + ".Field0", entry['Field0']) yield (idxStr + ".Field1", entry['Field1']) @@ -537,7 +576,6 @@ class NimTablePrinter: def __init__(self, val): self.val = val - # match = self.pattern.match(self.val.type.name) def display_hint(self): return 'map' @@ -556,11 +594,10 @@ class NimTablePrinter: if self.val: data = NimSeqPrinter(self.val['data']) for idxStr, entry in data.children(): - if int(entry['Field0']) > 0: + if int(entry['Field0']) != 0: yield (idxStr + '.Field1', entry['Field1']) yield (idxStr + '.Field2', entry['Field2']) - ################################################################ # this is untested, therefore disabled @@ -651,7 +688,7 @@ def register_nim_pretty_printers_for_object(objfile): if nimMainSym and nimMainSym.symtab.objfile == objfile: print("set Nim pretty printers for ", objfile.filename) - objfile.type_printers = [NimTypePrinter()] + gdb.types.register_type_printer(objfile, NimTypePrinter()) objfile.pretty_printers = [makematcher(var) for var in list(globals().values()) if hasattr(var, 'pattern')] # Register pretty printers for all objfiles that are already loaded. |