""" This is the llvm::Optional data formatter from llvm/utils/lldbDataFormatters.py with the implementation replaced by bytecode. """ from __future__ import annotations from formatter_bytecode import * import lldb def __lldb_init_module(debugger, internal_dict): debugger.HandleCommand( "type synthetic add -w llvm " f"-l {__name__}.MyOptionalSynthProvider " '-x "^MyOptional<.+>$"' ) debugger.HandleCommand( "type summary add -w llvm " f"-e -F {__name__}.MyOptionalSummaryProvider " '-x "^MyOptional<.+>$"' ) def stringify(bytecode: bytearray) -> str: s = "" in_hex = False for b in bytecode: if (b < 32 or b > 127 or chr(b) in ['"', "`", "'"]) or ( in_hex and chr(b).lower() in [ "a", "b", "c", "d", "e", "f", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ] ): s += r"\x" + hex(b)[2:] in_hex = True else: s += chr(b) in_hex = False return s def evaluate(assembler: str, data: list): bytecode = compile(assembler) trace = True if trace: print( "Compiled to {0} bytes of bytecode:\n{1}".format( len(bytecode), stringify(bytecode) ) ) result = interpret(bytecode, [], data, False) # trace) if trace: print("--> {0}".format(result)) return result # def GetOptionalValue(valobj): # storage = valobj.GetChildMemberWithName("Storage") # if not storage: # storage = valobj # # failure = 2 # hasVal = storage.GetChildMemberWithName("hasVal").GetValueAsUnsigned(failure) # if hasVal == failure: # return "" # # if hasVal == 0: # return None # # underlying_type = storage.GetType().GetTemplateArgumentType(0) # storage = storage.GetChildMemberWithName("value") # return storage.Cast(underlying_type) def MyOptionalSummaryProvider(valobj, internal_dict): # val = GetOptionalValue(valobj) # if val is None: # return "None" # if val.summary: # return val.summary # return val.GetValue() summary = "" summary += ' dup "Storage" @get_child_with_name call' # valobj storage summary += " dup is_null ~ { swap } if drop" # storage summary += ' dup "hasVal" @get_child_with_name call' # storage obj(hasVal) summary += ' dup is_null { drop "" } {' summary += " @get_value_as_unsigned call" # storage int(hasVal) summary += ' 0u = { "None" } {' summary += " dup @get_type call" summary += " 0u @get_template_argument_type call" # storage type summary += " swap" # type storage summary += ' "value" @get_child_with_name call' # type value summary += " swap @cast call" # type(value) summary += ' dup is_null { "None" } {' summary += ( " dup @summary call dup @strlen call { @get_value call } { drop } ifelse" ) summary += " } ifelse" summary += " } ifelse" summary += " } ifelse" return evaluate(summary, [valobj]) class MyOptionalSynthProvider: """Provides deref support to llvm::Optional""" def __init__(self, valobj, internal_dict): self.valobj = valobj def num_children(self): # return self.valobj.num_children num_children = " @get_num_children call" return evaluate(num_children, [self.valobj]) def get_child_index(self, name): # if name == "$$dereference$$": # return self.valobj.num_children # return self.valobj.GetIndexOfChildWithName(name) get_child_index = ' dup "$$dereference$$" =' get_child_index += " { drop @get_num_children call } {" # obj name get_child_index += " @get_child_index call" # index get_child_index += " } ifelse" return evaluate(get_child_index, [self.valobj, name]) def get_child_at_index(self, index): # if index < self.valobj.num_children: # return self.valobj.GetChildAtIndex(index) # return GetOptionalValue(self.valobj) or lldb.SBValue() get_child_at_index = " over over swap" # obj index index obj get_child_at_index += " @get_num_children call" # obj index index n get_child_at_index += " < { @get_child_at_index call } {" # obj index get_opt_val = ' dup "Storage" @get_child_with_name call' # valobj storage get_opt_val += " dup { swap } if drop" # storage get_opt_val += ' dup "hasVal" @get_child_with_name call' # storage get_opt_val += " @get_value_as_unsigned call" # storage int(hasVal) get_opt_val += ' dup 2 = { drop "" } {' get_opt_val += ' 0 = { "None" } {' get_opt_val += ( " dup @get_type call 0 @get_template_argument_type call" # storage type ) get_opt_val += " swap" # type storage get_opt_val += ' "value" @get_child_with_name call' # type value get_opt_val += " swap @cast call" # type(value) get_opt_val += " } ifelse" get_opt_val += " } ifelse" get_child_at_index += get_opt_val get_child_at_index += " } ifelse" return evaluate(get_child_at_index, [self.valobj, index])