1""" 2This is the llvm::Optional data formatter from llvm/utils/lldbDataFormatters.py 3with the implementation replaced by bytecode. 4""" 5 6from __future__ import annotations 7from formatter_bytecode import * 8import lldb 9 10 11def __lldb_init_module(debugger, internal_dict): 12 debugger.HandleCommand( 13 "type synthetic add -w llvm " 14 f"-l {__name__}.MyOptionalSynthProvider " 15 '-x "^MyOptional<.+>$"' 16 ) 17 debugger.HandleCommand( 18 "type summary add -w llvm " 19 f"-e -F {__name__}.MyOptionalSummaryProvider " 20 '-x "^MyOptional<.+>$"' 21 ) 22 23 24def stringify(bytecode: bytearray) -> str: 25 s = "" 26 in_hex = False 27 for b in bytecode: 28 if (b < 32 or b > 127 or chr(b) in ['"', "`", "'"]) or ( 29 in_hex 30 and chr(b).lower() 31 in [ 32 "a", 33 "b", 34 "c", 35 "d", 36 "e", 37 "f", 38 "0", 39 "1", 40 "2", 41 "3", 42 "4", 43 "5", 44 "6", 45 "7", 46 "8", 47 "9", 48 ] 49 ): 50 s += r"\x" + hex(b)[2:] 51 in_hex = True 52 else: 53 s += chr(b) 54 in_hex = False 55 return s 56 57 58def evaluate(assembler: str, data: list): 59 bytecode = compile(assembler) 60 trace = True 61 if trace: 62 print( 63 "Compiled to {0} bytes of bytecode:\n{1}".format( 64 len(bytecode), stringify(bytecode) 65 ) 66 ) 67 result = interpret(bytecode, [], data, False) # trace) 68 if trace: 69 print("--> {0}".format(result)) 70 return result 71 72 73# def GetOptionalValue(valobj): 74# storage = valobj.GetChildMemberWithName("Storage") 75# if not storage: 76# storage = valobj 77# 78# failure = 2 79# hasVal = storage.GetChildMemberWithName("hasVal").GetValueAsUnsigned(failure) 80# if hasVal == failure: 81# return "<could not read MyOptional>" 82# 83# if hasVal == 0: 84# return None 85# 86# underlying_type = storage.GetType().GetTemplateArgumentType(0) 87# storage = storage.GetChildMemberWithName("value") 88# return storage.Cast(underlying_type) 89 90 91def MyOptionalSummaryProvider(valobj, internal_dict): 92 # val = GetOptionalValue(valobj) 93 # if val is None: 94 # return "None" 95 # if val.summary: 96 # return val.summary 97 # return val.GetValue() 98 summary = "" 99 summary += ' dup "Storage" @get_child_with_name call' # valobj storage 100 summary += " dup is_null ~ { swap } if drop" # storage 101 summary += ' dup "hasVal" @get_child_with_name call' # storage obj(hasVal) 102 summary += ' dup is_null { drop "<could not read MyOptional>" } {' 103 summary += " @get_value_as_unsigned call" # storage int(hasVal) 104 summary += ' 0u = { "None" } {' 105 summary += " dup @get_type call" 106 summary += " 0u @get_template_argument_type call" # storage type 107 summary += " swap" # type storage 108 summary += ' "value" @get_child_with_name call' # type value 109 summary += " swap @cast call" # type(value) 110 summary += ' dup is_null { "None" } {' 111 summary += ( 112 " dup @summary call dup @strlen call { @get_value call } { drop } ifelse" 113 ) 114 summary += " } ifelse" 115 summary += " } ifelse" 116 summary += " } ifelse" 117 return evaluate(summary, [valobj]) 118 119 120class MyOptionalSynthProvider: 121 """Provides deref support to llvm::Optional<T>""" 122 123 def __init__(self, valobj, internal_dict): 124 self.valobj = valobj 125 126 def num_children(self): 127 # return self.valobj.num_children 128 num_children = " @get_num_children call" 129 return evaluate(num_children, [self.valobj]) 130 131 def get_child_index(self, name): 132 # if name == "$$dereference$$": 133 # return self.valobj.num_children 134 # return self.valobj.GetIndexOfChildWithName(name) 135 get_child_index = ' dup "$$dereference$$" =' 136 get_child_index += " { drop @get_num_children call } {" # obj name 137 get_child_index += " @get_child_index call" # index 138 get_child_index += " } ifelse" 139 return evaluate(get_child_index, [self.valobj, name]) 140 141 def get_child_at_index(self, index): 142 # if index < self.valobj.num_children: 143 # return self.valobj.GetChildAtIndex(index) 144 # return GetOptionalValue(self.valobj) or lldb.SBValue() 145 get_child_at_index = " over over swap" # obj index index obj 146 get_child_at_index += " @get_num_children call" # obj index index n 147 get_child_at_index += " < { @get_child_at_index call } {" # obj index 148 149 get_opt_val = ' dup "Storage" @get_child_with_name call' # valobj storage 150 get_opt_val += " dup { swap } if drop" # storage 151 get_opt_val += ' dup "hasVal" @get_child_with_name call' # storage 152 get_opt_val += " @get_value_as_unsigned call" # storage int(hasVal) 153 get_opt_val += ' dup 2 = { drop "<could not read MyOptional>" } {' 154 get_opt_val += ' 0 = { "None" } {' 155 get_opt_val += ( 156 " dup @get_type call 0 @get_template_argument_type call" # storage type 157 ) 158 get_opt_val += " swap" # type storage 159 get_opt_val += ' "value" @get_child_with_name call' # type value 160 get_opt_val += " swap @cast call" # type(value) 161 get_opt_val += " } ifelse" 162 get_opt_val += " } ifelse" 163 164 get_child_at_index += get_opt_val 165 get_child_at_index += " } ifelse" 166 167 return evaluate(get_child_at_index, [self.valobj, index]) 168