1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381 |
- import lldb
- from collections import OrderedDict
- from typing import Union
- def sbvaluegetitem(self: lldb.SBValue, name: Union[int, str]) -> lldb.SBValue:
- if isinstance(name, str):
- return self.GetChildMemberWithName(name)
- else:
- return self.GetChildAtIndex(name)
- # Make this easier to work with
- lldb.SBValue.__getitem__ = sbvaluegetitem
- NIM_IS_V2 = True
- def get_nti(value: lldb.SBValue, nim_name=None):
- name_split = value.type.name.split("_")
- type_nim_name = nim_name or name_split[1]
- id_string = name_split[-1].split(" ")[0]
- type_info_name = "NTI" + type_nim_name.lower() + "__" + id_string + "_"
- nti = value.target.FindFirstGlobalVariable(type_info_name)
- if not nti.IsValid():
- type_info_name = "NTI" + "__" + id_string + "_"
- nti = value.target.FindFirstGlobalVariable(type_info_name)
- if not nti.IsValid():
- print(f"NimEnumPrinter: lookup global symbol: '{type_info_name}' failed for {value.type.name}.\n")
- return type_nim_name, nti
- def enum_to_string(value: lldb.SBValue, int_val=None, nim_name=None):
- tname = nim_name or value.type.name.split("_")[1]
- enum_val = value.signed
- if int_val is not None:
- enum_val = int_val
- default_val = f"{tname}.{str(enum_val)}"
- fn_syms = value.target.FindFunctions("reprEnum")
- if not fn_syms.GetSize() > 0:
- return default_val
- fn_sym: lldb.SBSymbolContext = fn_syms.GetContextAtIndex(0)
- fn: lldb.SBFunction = fn_sym.function
- fn_type: lldb.SBType = fn.type
- arg_types: lldb.SBTypeList = fn_type.GetFunctionArgumentTypes()
- if arg_types.GetSize() < 2:
- return default_val
- arg1_type: lldb.SBType = arg_types.GetTypeAtIndex(0)
- arg2_type: lldb.SBType = arg_types.GetTypeAtIndex(1)
- ty_info_name, nti = get_nti(value, nim_name=tname)
- if not nti.IsValid():
- return default_val
- call = f"{fn.name}(({arg1_type.name}){enum_val}, ({arg2_type.name})" + str(nti.GetLoadAddress()) + ");"
- res = executeCommand(call)
- if res.error.fail:
- return default_val
- return f"{tname}.{res.summary[1:-1]}"
- def to_string(value: lldb.SBValue):
- # For getting NimStringDesc * value
- value = value.GetNonSyntheticValue()
- # Check if data pointer is Null
- if value.type.is_pointer and value.unsigned == 0:
- return None
- size = int(value["Sup"]["len"].unsigned)
- if size == 0:
- return ""
- if size > 2**14:
- return "... (too long) ..."
- data = value["data"]
- # Check if first element is NULL
- base_data_type = value.target.FindFirstType("char")
- cast = data.Cast(base_data_type)
- if cast.unsigned == 0:
- return None
- cast = data.Cast(value.target.FindFirstType("char").GetArrayType(size))
- return bytearray(cast.data.uint8s).decode("utf-8")
- def to_stringV2(value: lldb.SBValue):
- # For getting NimStringV2 value
- value = value.GetNonSyntheticValue()
- data = value["p"]["data"]
- # Check if data pointer is Null
- if value["p"].unsigned == 0:
- return None
- size = int(value["len"].signed)
- if size == 0:
- return ""
- if size > 2**14:
- return "... (too long) ..."
- # Check if first element is NULL
- base_data_type = data.type.GetArrayElementType().GetTypedefedType()
- cast = data.Cast(base_data_type)
- if cast.unsigned == 0:
- return None
- cast = data.Cast(base_data_type.GetArrayType(size))
- return bytearray(cast.data.uint8s).decode("utf-8")
- def NimString(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- if NIM_IS_V2:
- res = to_stringV2(value)
- else:
- res = to_string(value)
- if res is not None:
- return f'"{res}"'
- else:
- return "nil"
- def rope_helper(value: lldb.SBValue) -> str:
- value = value.GetNonSyntheticValue()
- if value.type.is_pointer and value.unsigned == 0:
- return ""
- if value["length"].unsigned == 0:
- return ""
- if NIM_IS_V2:
- str_val = to_stringV2(value["data"])
- else:
- str_val = to_string(value["data"])
- if str_val is None:
- str_val = ""
- return rope_helper(value["left"]) + str_val + rope_helper(value["right"])
- def Rope(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- rope_str = rope_helper(value)
- if len(rope_str) == 0:
- rope_str = "nil"
- else:
- rope_str = f'"{rope_str}"'
- return f"Rope({rope_str})"
- def NCSTRING(value: lldb.SBValue, internal_dict=None):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- ty = value.Dereference().type
- val = value.target.CreateValueFromAddress(
- value.name or "temp", lldb.SBAddress(value.unsigned, value.target), ty
- ).AddressOf()
- return val.summary
- def ObjectV2(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- orig_value = value.GetNonSyntheticValue()
- if orig_value.type.is_pointer and orig_value.unsigned == 0:
- return "nil"
- custom_summary = get_custom_summary(value)
- if custom_summary is not None:
- return custom_summary
- while orig_value.type.is_pointer:
- orig_value = orig_value.Dereference()
- if "_" in orig_value.type.name:
- obj_name = orig_value.type.name.split("_")[1].replace("colonObjectType", "")
- else:
- obj_name = orig_value.type.name
- num_children = value.num_children
- fields = []
- for i in range(num_children):
- fields.append(f"{value[i].name}: {value[i].summary}")
- res = f"{obj_name}(" + ", ".join(fields) + ")"
- return res
- def Number(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- if value.type.is_pointer and value.signed == 0:
- return "nil"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- return str(value.signed)
- def Float(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- return str(value.value)
- def UnsignedNumber(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- return str(value.unsigned)
- def Bool(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- return str(value.value)
- def CharArray(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- return str([f"'{char}'" for char in value.uint8s])
- def Array(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- value = value.GetNonSyntheticValue()
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- value = value.GetNonSyntheticValue()
- return "[" + ", ".join([value[i].summary for i in range(value.num_children)]) + "]"
- def Tuple(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- while value.type.is_pointer:
- value = value.Dereference()
- num_children = value.num_children
- fields = []
- for i in range(num_children):
- key = value[i].name
- val = value[i].summary
- if key.startswith("Field"):
- fields.append(f"{val}")
- else:
- fields.append(f"{key}: {val}")
- return "(" + ", ".join(fields) + f")"
- def is_local(value: lldb.SBValue) -> bool:
- line: lldb.SBLineEntry = value.frame.GetLineEntry()
- decl: lldb.SBDeclaration = value.GetDeclaration()
- if line.file == decl.file and decl.line != 0:
- return True
- return False
- def is_in_scope(value: lldb.SBValue) -> bool:
- line: lldb.SBLineEntry = value.frame.GetLineEntry()
- decl: lldb.SBDeclaration = value.GetDeclaration()
- if is_local(value) and decl.line < line.line:
- return True
- return False
- def Enum(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_value_summary(value)
- if custom_summary is not None:
- return custom_summary
- return enum_to_string(value)
- def EnumSet(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- vals = []
- max_vals = 7
- for child in value.children:
- vals.append(child.summary)
- if len(vals) > max_vals:
- vals.append("...")
- break
- return "{" + ", ".join(vals) + "}"
- def Set(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if custom_summary is not None:
- return custom_summary
- vals = []
- max_vals = 7
- for child in value.children:
- vals.append(child.value)
- if len(vals) > max_vals:
- vals.append("...")
- break
- return "{" + ", ".join(vals) + "}"
- def Table(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if custom_summary is not None:
- return custom_summary
- fields = []
- for i in range(value.num_children):
- key = value[i].name
- val = value[i].summary
- fields.append(f"{key}: {val}")
- return "Table({" + ", ".join(fields) + "})"
- def HashSet(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if custom_summary is not None:
- return custom_summary
- fields = []
- for i in range(value.num_children):
- fields.append(f"{value[i].summary}")
- return "HashSet({" + ", ".join(fields) + "})"
- def StringTable(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- fields = []
- for i in range(value.num_children - 1):
- key = value[i].name
- val = value[i].summary
- fields.append(f"{key}: {val}")
- mode = value[value.num_children - 1].summary
- return "StringTable({" + ", ".join(fields) + f"}}, mode={mode})"
- def Sequence(value: lldb.SBValue, internal_dict):
- if is_local(value):
- if not is_in_scope(value):
- return "undefined"
- custom_summary = get_custom_summary(value)
- if not custom_summary is None:
- return custom_summary
- return "@[" + ", ".join([value[i].summary for i in range(value.num_children)]) + "]"
- class StringChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.data_type: lldb.SBType
- if not NIM_IS_V2:
- self.data_type = self.value.target.FindFirstType("char")
- self.first_element: lldb.SBValue
- self.update()
- self.count = 0
- def num_children(self):
- return self.count
- def get_child_index(self, name):
- return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- offset = index * self.data_size
- return self.first_element.CreateChildAtOffset("[" + str(index) + "]", offset, self.data_type)
- def get_data(self) -> lldb.SBValue:
- return self.value["p"]["data"] if NIM_IS_V2 else self.value["data"]
- def get_len(self) -> int:
- if NIM_IS_V2:
- if self.value["p"].unsigned == 0:
- return 0
- size = int(self.value["len"].signed)
- if size == 0:
- return 0
- data = self.value["p"]["data"]
- # Check if first element is NULL
- base_data_type = data.type.GetArrayElementType().GetTypedefedType()
- cast = data.Cast(base_data_type)
- if cast.unsigned == 0:
- return 0
- else:
- if self.value.type.is_pointer and self.value.unsigned == 0:
- return 0
- size = int(self.value["Sup"]["len"].unsigned)
- if size == 0:
- return 0
- data = self.value["data"]
- # Check if first element is NULL
- base_data_type = self.value.target.FindFirstType("char")
- cast = data.Cast(base_data_type)
- if cast.unsigned == 0:
- return 0
- return size
- def update(self):
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- data = self.get_data()
- size = self.get_len()
- self.count = size
- self.first_element = data
- if NIM_IS_V2:
- self.data_type = data.type.GetArrayElementType().GetTypedefedType()
- self.data_size = self.data_type.GetByteSize()
- def has_children(self):
- return bool(self.num_children())
- class ArrayChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.data_type: lldb.SBType
- self.first_element: lldb.SBValue
- self.update()
- def num_children(self):
- return self.has_children() and self.value.num_children
- def get_child_index(self, name: str):
- return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- offset = index * self.value[index].GetByteSize()
- return self.first_element.CreateChildAtOffset("[" + str(index) + "]", offset, self.data_type)
- def update(self):
- if not self.has_children():
- return
- self.first_element = self.value[0]
- self.data_type = self.value.type.GetArrayElementType()
- def has_children(self):
- if is_local(self.value):
- if not is_in_scope(self.value):
- return False
- return bool(self.value.num_children)
- class SeqChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.data_type: lldb.SBType
- self.first_element: lldb.SBValue
- self.data: lldb.SBValue
- self.count = 0
- self.update()
- def num_children(self):
- return self.count
- def get_child_index(self, name: str):
- return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- offset = index * self.data[index].GetByteSize()
- return self.first_element.CreateChildAtOffset("[" + str(index) + "]", offset, self.data_type)
- def get_data(self) -> lldb.SBValue:
- return self.value["p"]["data"] if NIM_IS_V2 else self.value["data"]
- def get_len(self) -> lldb.SBValue:
- return self.value["len"] if NIM_IS_V2 else self.value["Sup"]["len"]
- def update(self):
- self.count = 0
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- self.count = self.get_len().unsigned
- if not self.has_children():
- return
- data = self.get_data()
- self.data_type = data.type.GetArrayElementType()
- self.data = data.Cast(self.data_type.GetArrayType(self.num_children()))
- self.first_element = self.data
- def has_children(self):
- return bool(self.num_children())
- class ObjectChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.data_type: lldb.SBType
- self.first_element: lldb.SBValue
- self.data: lldb.SBValue
- self.children: OrderedDict[str, int] = OrderedDict()
- self.child_list: list[lldb.SBValue] = []
- self.update()
- def num_children(self):
- return len(self.children)
- def get_child_index(self, name: str):
- return self.children[name]
- def get_child_at_index(self, index):
- return self.child_list[index]
- def populate_children(self):
- self.children.clear()
- self.child_list = []
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- stack = [self.value.GetNonSyntheticValue()]
- index = 0
- while stack:
- cur_val = stack.pop()
- if cur_val.type.is_pointer and cur_val.unsigned == 0:
- continue
- while cur_val.type.is_pointer:
- cur_val = cur_val.Dereference()
- # Add super objects if they exist
- if cur_val.num_children > 0 and cur_val[0].name == "Sup" and cur_val[0].type.name.startswith("tyObject"):
- stack.append(cur_val[0])
- for child in cur_val.children:
- child = child.GetNonSyntheticValue()
- if child.name == "Sup":
- continue
- self.children[child.name] = index
- self.child_list.append(child)
- index += 1
- def update(self):
- self.populate_children()
- def has_children(self):
- return bool(self.num_children())
- class HashSetChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.child_list: list[lldb.SBValue] = []
- self.update()
- def num_children(self):
- return len(self.child_list)
- def get_child_index(self, name: str):
- return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- return self.child_list[index]
- def get_data(self) -> lldb.SBValue:
- return self.value["data"]["p"]["data"] if NIM_IS_V2 else self.value["data"]["data"]
- def get_len(self) -> lldb.SBValue:
- return self.value["data"]["len"] if NIM_IS_V2 else self.value["data"]["Sup"]["len"]
- def update(self):
- self.child_list = []
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- tuple_len = int(self.get_len().unsigned)
- tuple = self.get_data()
- base_data_type = tuple.type.GetArrayElementType()
- cast = tuple.Cast(base_data_type.GetArrayType(tuple_len))
- index = 0
- for i in range(tuple_len):
- el = cast[i]
- field0 = int(el[0].unsigned)
- if field0 == 0:
- continue
- key = el[1]
- child = key.CreateValueFromAddress(f"[{str(index)}]", key.GetLoadAddress(), key.GetType())
- index += 1
- self.child_list.append(child)
- def has_children(self):
- return bool(self.num_children())
- class SetCharChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.ty = self.value.target.FindFirstType("char")
- self.child_list: list[lldb.SBValue] = []
- self.update()
- def num_children(self):
- return len(self.child_list)
- def get_child_index(self, name: str):
- return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- return self.child_list[index]
- def update(self):
- self.child_list = []
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- cur_pos = 0
- for child in self.value.children:
- child_val = child.signed
- if child_val != 0:
- temp = child_val
- num_bits = 8
- while temp != 0:
- is_set = temp & 1
- if is_set == 1:
- data = lldb.SBData.CreateDataFromInt(cur_pos)
- child = self.value.synthetic_child_from_data(f"[{len(self.child_list)}]", data, self.ty)
- self.child_list.append(child)
- temp = temp >> 1
- cur_pos += 1
- num_bits -= 1
- cur_pos += num_bits
- else:
- cur_pos += 8
- def has_children(self):
- return bool(self.num_children())
- def create_set_children(value: lldb.SBValue, child_type: lldb.SBType, starting_pos: int) -> list[lldb.SBValue]:
- child_list: list[lldb.SBValue] = []
- cur_pos = starting_pos
- if value.num_children > 0:
- children = value.children
- else:
- children = [value]
- for child in children:
- child_val = child.signed
- if child_val != 0:
- temp = child_val
- num_bits = 8
- while temp != 0:
- is_set = temp & 1
- if is_set == 1:
- data = lldb.SBData.CreateDataFromInt(cur_pos)
- child = value.synthetic_child_from_data(f"[{len(child_list)}]", data, child_type)
- child_list.append(child)
- temp = temp >> 1
- cur_pos += 1
- num_bits -= 1
- cur_pos += num_bits
- else:
- cur_pos += 8
- return child_list
- class SetIntChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.ty = self.value.target.FindFirstType(f"NI64")
- self.child_list: list[lldb.SBValue] = []
- self.update()
- def num_children(self):
- return len(self.child_list)
- def get_child_index(self, name: str):
- return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- return self.child_list[index]
- def update(self):
- self.child_list = []
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- bits = self.value.GetByteSize() * 8
- starting_pos = -(bits // 2)
- self.child_list = create_set_children(self.value, self.ty, starting_pos)
- def has_children(self):
- return bool(self.num_children())
- class SetUIntChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.ty = self.value.target.FindFirstType(f"NU64")
- self.child_list: list[lldb.SBValue] = []
- self.update()
- def num_children(self):
- return len(self.child_list)
- def get_child_index(self, name: str):
- return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- return self.child_list[index]
- def update(self):
- self.child_list = []
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- self.child_list = create_set_children(self.value, self.ty, starting_pos=0)
- def has_children(self):
- return bool(self.num_children())
- class SetEnumChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.ty = self.value.target.FindFirstType(self.value.type.name.replace("tySet_", ""))
- self.child_list: list[lldb.SBValue] = []
- self.update()
- def num_children(self):
- return len(self.child_list)
- def get_child_index(self, name: str):
- return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- return self.child_list[index]
- def update(self):
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- self.child_list = create_set_children(self.value, self.ty, starting_pos=0)
- def has_children(self):
- return bool(self.num_children())
- class TableChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.children: OrderedDict[str, int] = OrderedDict()
- self.child_list: list[lldb.SBValue] = []
- self.update()
- def num_children(self):
- return len(self.child_list)
- def get_child_index(self, name: str):
- return self.children[name]
- def get_child_at_index(self, index):
- return self.child_list[index]
- def get_data(self) -> lldb.SBValue:
- return self.value["data"]["p"]["data"] if NIM_IS_V2 else self.value["data"]["data"]
- def get_len(self) -> lldb.SBValue:
- return self.value["data"]["len"] if NIM_IS_V2 else self.value["data"]["Sup"]["len"]
- def update(self):
- self.child_list = []
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- tuple_len = int(self.get_len().unsigned)
- tuple = self.get_data()
- base_data_type = tuple.type.GetArrayElementType()
- cast = tuple.Cast(base_data_type.GetArrayType(tuple_len))
- index = 0
- for i in range(tuple_len):
- el = cast[i]
- field0 = int(el[0].unsigned)
- if field0 == 0:
- continue
- key = el[1]
- val = el[2]
- key_summary = key.summary
- child = self.value.CreateValueFromAddress(key_summary, val.GetLoadAddress(), val.GetType())
- self.child_list.append(child)
- self.children[key_summary] = index
- index += 1
- def has_children(self):
- return bool(self.num_children())
- class StringTableChildrenProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value = value
- self.children: OrderedDict[str, int] = OrderedDict()
- self.child_list: list[lldb.SBValue] = []
- self.update()
- def num_children(self):
- return len(self.child_list)
- def get_child_index(self, name: str):
- return self.children[name]
- def get_child_at_index(self, index):
- return self.child_list[index]
- def get_data(self) -> lldb.SBValue:
- return self.value["data"]["p"]["data"] if NIM_IS_V2 else self.value["data"]["data"]
- def get_len(self) -> lldb.SBValue:
- return self.value["data"]["len"] if NIM_IS_V2 else self.value["data"]["Sup"]["len"]
- def update(self):
- self.children.clear()
- self.child_list = []
- if is_local(self.value):
- if not is_in_scope(self.value):
- return
- tuple_len = int(self.get_len().unsigned)
- tuple = self.get_data()
- base_data_type = tuple.type.GetArrayElementType()
- cast = tuple.Cast(base_data_type.GetArrayType(tuple_len))
- index = 0
- for i in range(tuple_len):
- el = cast[i]
- field0 = int(el[2].unsigned)
- if field0 == 0:
- continue
- key = el[0]
- val = el[1]
- child = val.CreateValueFromAddress(key.summary, val.GetLoadAddress(), val.GetType())
- self.child_list.append(child)
- self.children[key.summary] = index
- index += 1
- self.child_list.append(self.value["mode"])
- self.children["mode"] = index
- def has_children(self):
- return bool(self.num_children())
- class LLDBDynamicObjectProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- value = value.GetNonSyntheticValue()
- self.value: lldb.SBValue = value[0]
- self.children: OrderedDict[str, int] = OrderedDict()
- self.child_list: list[lldb.SBValue] = []
- while self.value.type.is_pointer:
- self.value = self.value.Dereference()
- self.update()
- def num_children(self):
- return len(self.child_list)
- def get_child_index(self, name: str):
- return self.children[name]
- def get_child_at_index(self, index):
- return self.child_list[index]
- def update(self):
- self.children.clear()
- self.child_list = []
- for i, child in enumerate(self.value.children):
- name = child.name.strip('"')
- new_child = child.CreateValueFromAddress(name, child.GetLoadAddress(), child.GetType())
- self.children[name] = i
- self.child_list.append(new_child)
- def has_children(self):
- return bool(self.num_children())
- class LLDBBasicObjectProvider:
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value: lldb.SBValue = value
- def num_children(self):
- if self.value is not None:
- return self.value.num_children
- return 0
- def get_child_index(self, name: str):
- return self.value.GetIndexOfChildWithName(name)
- def get_child_at_index(self, index):
- return self.value.GetChildAtIndex(index)
- def update(self):
- pass
- def has_children(self):
- return self.num_children() > 0
- class CustomObjectChildrenProvider:
- """
- This children provider handles values returned from lldbDebugSynthetic*
- Nim procedures
- """
- def __init__(self, value: lldb.SBValue, internalDict):
- self.value: lldb.SBValue = get_custom_synthetic(value) or value
- if "lldbdynamicobject" in self.value.type.name.lower():
- self.provider = LLDBDynamicObjectProvider(self.value, internalDict)
- else:
- self.provider = LLDBBasicObjectProvider(self.value, internalDict)
- def num_children(self):
- return self.provider.num_children()
- def get_child_index(self, name: str):
- return self.provider.get_child_index(name)
- def get_child_at_index(self, index):
- return self.provider.get_child_at_index(index)
- def update(self):
- self.provider.update()
- def has_children(self):
- return self.provider.has_children()
- def echo(debugger: lldb.SBDebugger, command: str, result, internal_dict):
- debugger.HandleCommand("po " + command)
- SUMMARY_FUNCTIONS: dict[str, lldb.SBFunction] = {}
- SYNTHETIC_FUNCTIONS: dict[str, lldb.SBFunction] = {}
- def get_custom_summary(value: lldb.SBValue) -> Union[str, None]:
- """Get a custom summary if a function exists for it"""
- value = value.GetNonSyntheticValue()
- if value.GetAddress().GetOffset() == 0:
- return None
- base_type = get_base_type(value.type)
- fn = SUMMARY_FUNCTIONS.get(base_type.name)
- if fn is None:
- return None
- fn_type: lldb.SBType = fn.type
- arg_types: lldb.SBTypeList = fn_type.GetFunctionArgumentTypes()
- first_type = arg_types.GetTypeAtIndex(0)
- while value.type.is_pointer:
- value = value.Dereference()
- if first_type.is_pointer:
- command = f"{fn.name}(({first_type.name})" + str(value.GetLoadAddress()) + ");"
- else:
- command = f"{fn.name}(*({first_type.GetPointerType().name})" + str(value.GetLoadAddress()) + ");"
- res = executeCommand(command)
- if res.error.fail:
- return None
- return res.summary.strip('"')
- def get_custom_value_summary(value: lldb.SBValue) -> Union[str, None]:
- """Get a custom summary if a function exists for it"""
- fn: lldb.SBFunction = SUMMARY_FUNCTIONS.get(value.type.name)
- if fn is None:
- return None
- command = f"{fn.name}(({value.type.name})" + str(value.signed) + ");"
- res = executeCommand(command)
- if res.error.fail:
- return None
- return res.summary.strip('"')
- def get_custom_synthetic(value: lldb.SBValue) -> Union[lldb.SBValue, None]:
- """Get a custom synthetic object if a function exists for it"""
- value = value.GetNonSyntheticValue()
- if value.GetAddress().GetOffset() == 0:
- return None
- base_type = get_base_type(value.type)
- fn = SYNTHETIC_FUNCTIONS.get(base_type.name)
- if fn is None:
- return None
- fn_type: lldb.SBType = fn.type
- arg_types: lldb.SBTypeList = fn_type.GetFunctionArgumentTypes()
- first_type = arg_types.GetTypeAtIndex(0)
- while value.type.is_pointer:
- value = value.Dereference()
- if first_type.is_pointer:
- first_arg = f"({first_type.name}){value.GetLoadAddress()}"
- else:
- first_arg = f"*({first_type.GetPointerType().name}){value.GetLoadAddress()}"
- if arg_types.GetSize() > 1 and fn.GetArgumentName(1) == "Result":
- ret_type = arg_types.GetTypeAtIndex(1)
- ret_type = get_base_type(ret_type)
- command = f"""
- {ret_type.name} lldbT;
- nimZeroMem((void*)(&lldbT), sizeof({ret_type.name}));
- {fn.name}(({first_arg}), (&lldbT));
- lldbT;
- """
- else:
- command = f"{fn.name}({first_arg});"
- res = executeCommand(command)
- if res.error.fail:
- print(res.error)
- return None
- return res
- def get_base_type(ty: lldb.SBType) -> lldb.SBType:
- """Get the base type of the type"""
- temp = ty
- while temp.IsPointerType():
- temp = temp.GetPointeeType()
- return temp
- def use_base_type(ty: lldb.SBType) -> bool:
- types_to_check = [
- "NF",
- "NF32",
- "NF64",
- "NI",
- "NI8",
- "NI16",
- "NI32",
- "NI64",
- "bool",
- "NIM_BOOL",
- "NU",
- "NU8",
- "NU16",
- "NU32",
- "NU64",
- ]
- for type_to_check in types_to_check:
- if ty.name.startswith(type_to_check):
- return False
- return True
- def breakpoint_function_wrapper(frame: lldb.SBFrame, bp_loc, internal_dict):
- """This allows function calls to Nim for custom object summaries and synthetic children"""
- debugger = lldb.debugger
- global SUMMARY_FUNCTIONS
- global SYNTHETIC_FUNCTIONS
- global NIM_IS_V2
- for tname, fn in SYNTHETIC_FUNCTIONS.items():
- debugger.HandleCommand(f"type synthetic delete -w nim {tname}")
- SUMMARY_FUNCTIONS = {}
- SYNTHETIC_FUNCTIONS = {}
- target: lldb.SBTarget = debugger.GetSelectedTarget()
- NIM_IS_V2 = target.FindFirstType("TNimTypeV2").IsValid()
- module = frame.GetSymbolContext(lldb.eSymbolContextModule).module
- for sym in module:
- if (
- not sym.name.startswith("lldbDebugSummary")
- and not sym.name.startswith("lldbDebugSynthetic")
- and not sym.name.startswith("dollar___")
- ):
- continue
- fn_syms: lldb.SBSymbolContextList = target.FindFunctions(sym.name)
- if not fn_syms.GetSize() > 0:
- continue
- fn_sym: lldb.SBSymbolContext = fn_syms.GetContextAtIndex(0)
- fn: lldb.SBFunction = fn_sym.function
- fn_type: lldb.SBType = fn.type
- arg_types: lldb.SBTypeList = fn_type.GetFunctionArgumentTypes()
- if arg_types.GetSize() > 1 and fn.GetArgumentName(1) == "Result":
- pass # don't continue
- elif arg_types.GetSize() != 1:
- continue
- arg_type: lldb.SBType = arg_types.GetTypeAtIndex(0)
- if use_base_type(arg_type):
- arg_type = get_base_type(arg_type)
- if sym.name.startswith("lldbDebugSummary") or sym.name.startswith("dollar___"):
- SUMMARY_FUNCTIONS[arg_type.name] = fn
- elif sym.name.startswith("lldbDebugSynthetic"):
- SYNTHETIC_FUNCTIONS[arg_type.name] = fn
- debugger.HandleCommand(
- f"type synthetic add -w nim -l {__name__}.CustomObjectChildrenProvider {arg_type.name}"
- )
- def executeCommand(command, *args):
- debugger = lldb.debugger
- process = debugger.GetSelectedTarget().GetProcess()
- frame: lldb.SBFrame = process.GetSelectedThread().GetSelectedFrame()
- expr_options = lldb.SBExpressionOptions()
- expr_options.SetIgnoreBreakpoints(False)
- expr_options.SetFetchDynamicValue(lldb.eDynamicCanRunTarget)
- expr_options.SetTimeoutInMicroSeconds(30 * 1000 * 1000) # 30 second timeout
- expr_options.SetTryAllThreads(True)
- expr_options.SetUnwindOnError(False)
- expr_options.SetGenerateDebugInfo(True)
- expr_options.SetLanguage(lldb.eLanguageTypeC)
- expr_options.SetCoerceResultToId(True)
- res = frame.EvaluateExpression(command, expr_options)
- return res
- def __lldb_init_module(debugger, internal_dict):
- # fmt: off
- debugger.HandleCommand(f"breakpoint command add -F {__name__}.breakpoint_function_wrapper --script-type python 1")
- debugger.HandleCommand(f"type summary add -w nim -n sequence -F {__name__}.Sequence -x tySequence_+[[:alnum:]]+$")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SeqChildrenProvider -x tySequence_+[[:alnum:]]+$")
- debugger.HandleCommand(f"type summary add -w nim -n chararray -F {__name__}.CharArray -x char\s+[\d+]")
- debugger.HandleCommand(f"type summary add -w nim -n array -F {__name__}.Array -x tyArray_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.ArrayChildrenProvider -x tyArray_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n string -F {__name__}.NimString NimStringDesc")
- debugger.HandleCommand(f"type summary add -w nim -n stringv2 -F {__name__}.NimString -x NimStringV2$")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.StringChildrenProvider -x NimStringV2$")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.StringChildrenProvider -x NimStringDesc$")
- debugger.HandleCommand(f"type summary add -w nim -n cstring -F {__name__}.NCSTRING NCSTRING")
- debugger.HandleCommand(f"type summary add -w nim -n object -F {__name__}.ObjectV2 -x tyObject_+[[:alnum:]]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.ObjectChildrenProvider -x tyObject_+[[:alnum:]]+_+[[:alnum:]]+$")
- debugger.HandleCommand(f"type summary add -w nim -n tframe -F {__name__}.ObjectV2 -x TFrame$")
- debugger.HandleCommand(f"type summary add -w nim -n rootobj -F {__name__}.ObjectV2 -x RootObj$")
- debugger.HandleCommand(f"type summary add -w nim -n enum -F {__name__}.Enum -x tyEnum_+[[:alnum:]]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n hashset -F {__name__}.HashSet -x tyObject_+HashSet_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.HashSetChildrenProvider -x tyObject_+HashSet_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n rope -F {__name__}.Rope -x tyObject_+Rope[[:alnum:]]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n setuint -F {__name__}.Set -x tySet_+tyInt_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetIntChildrenProvider -x tySet_+tyInt[0-9]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n setint -F {__name__}.Set -x tySet_+tyInt[0-9]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n setuint2 -F {__name__}.Set -x tySet_+tyUInt[0-9]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetUIntChildrenProvider -x tySet_+tyUInt[0-9]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetUIntChildrenProvider -x tySet_+tyInt_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n setenum -F {__name__}.EnumSet -x tySet_+tyEnum_+[[:alnum:]]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetEnumChildrenProvider -x tySet_+tyEnum_+[[:alnum:]]+_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n setchar -F {__name__}.Set -x tySet_+tyChar_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.SetCharChildrenProvider -x tySet_+tyChar_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n table -F {__name__}.Table -x tyObject_+Table_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.TableChildrenProvider -x tyObject_+Table_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n stringtable -F {__name__}.StringTable -x tyObject_+StringTableObj_+[[:alnum:]]+")
- debugger.HandleCommand(f"type synthetic add -w nim -l {__name__}.StringTableChildrenProvider -x tyObject_+StringTableObj_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n tuple2 -F {__name__}.Tuple -x tyObject_+Tuple_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n tuple -F {__name__}.Tuple -x tyTuple_+[[:alnum:]]+")
- debugger.HandleCommand(f"type summary add -w nim -n float -F {__name__}.Float NF")
- debugger.HandleCommand(f"type summary add -w nim -n float32 -F {__name__}.Float NF32")
- debugger.HandleCommand(f"type summary add -w nim -n float64 -F {__name__}.Float NF64")
- debugger.HandleCommand(f"type summary add -w nim -n integer -F {__name__}.Number -x NI")
- debugger.HandleCommand(f"type summary add -w nim -n integer8 -F {__name__}.Number -x NI8")
- debugger.HandleCommand(f"type summary add -w nim -n integer16 -F {__name__}.Number -x NI16")
- debugger.HandleCommand(f"type summary add -w nim -n integer32 -F {__name__}.Number -x NI32")
- debugger.HandleCommand(f"type summary add -w nim -n integer64 -F {__name__}.Number -x NI64")
- debugger.HandleCommand(f"type summary add -w nim -n bool -F {__name__}.Bool -x bool")
- debugger.HandleCommand(f"type summary add -w nim -n bool2 -F {__name__}.Bool -x NIM_BOOL")
- debugger.HandleCommand(f"type summary add -w nim -n uinteger -F {__name__}.UnsignedNumber -x NU")
- debugger.HandleCommand(f"type summary add -w nim -n uinteger8 -F {__name__}.UnsignedNumber -x NU8")
- debugger.HandleCommand(f"type summary add -w nim -n uinteger16 -F {__name__}.UnsignedNumber -x NU16")
- debugger.HandleCommand(f"type summary add -w nim -n uinteger32 -F {__name__}.UnsignedNumber -x NU32")
- debugger.HandleCommand(f"type summary add -w nim -n uinteger64 -F {__name__}.UnsignedNumber -x NU64")
- debugger.HandleCommand("type category enable nim")
- debugger.HandleCommand(f"command script add -f {__name__}.echo echo")
- # fmt: on
|