1fffe8c66SAdrian Prantl""" 2fffe8c66SAdrian PrantlSpecification, compiler, disassembler, and interpreter 3fffe8c66SAdrian Prantlfor LLDB dataformatter bytecode. 4fffe8c66SAdrian Prantl 5fffe8c66SAdrian PrantlSee https://lldb.llvm.org/resources/formatterbytecode.html for more details. 6fffe8c66SAdrian Prantl""" 7fffe8c66SAdrian Prantl 8fffe8c66SAdrian Prantlfrom __future__ import annotations 9fffe8c66SAdrian Prantl 10fffe8c66SAdrian Prantl# Types 11fffe8c66SAdrian Prantltype_String = 1 12fffe8c66SAdrian Prantltype_Int = 2 13fffe8c66SAdrian Prantltype_UInt = 3 14fffe8c66SAdrian Prantltype_Object = 4 15fffe8c66SAdrian Prantltype_Type = 5 16fffe8c66SAdrian Prantl 17fffe8c66SAdrian Prantl# Opcodes 18fffe8c66SAdrian Prantlopcode = dict() 19fffe8c66SAdrian Prantl 20fffe8c66SAdrian Prantl 21fffe8c66SAdrian Prantldef define_opcode(n, mnemonic, name): 22fffe8c66SAdrian Prantl globals()["op_" + name] = n 23fffe8c66SAdrian Prantl if mnemonic: 24fffe8c66SAdrian Prantl opcode[mnemonic] = n 25fffe8c66SAdrian Prantl opcode[n] = mnemonic 26fffe8c66SAdrian Prantl 27fffe8c66SAdrian Prantl 28fffe8c66SAdrian Prantldefine_opcode(1, "dup", "dup") 29fffe8c66SAdrian Prantldefine_opcode(2, "drop", "drop") 30fffe8c66SAdrian Prantldefine_opcode(3, "pick", "pick") 31fffe8c66SAdrian Prantldefine_opcode(4, "over", "over") 32fffe8c66SAdrian Prantldefine_opcode(5, "swap", "swap") 33fffe8c66SAdrian Prantldefine_opcode(6, "rot", "rot") 34fffe8c66SAdrian Prantl 35fffe8c66SAdrian Prantldefine_opcode(0x10, "{", "begin") 36fffe8c66SAdrian Prantldefine_opcode(0x11, "if", "if") 37fffe8c66SAdrian Prantldefine_opcode(0x12, "ifelse", "ifelse") 38*ee1adc5aSAdrian Prantldefine_opcode(0x13, "return", "return") 39fffe8c66SAdrian Prantl 40fffe8c66SAdrian Prantldefine_opcode(0x20, None, "lit_uint") 41fffe8c66SAdrian Prantldefine_opcode(0x21, None, "lit_int") 42fffe8c66SAdrian Prantldefine_opcode(0x22, None, "lit_string") 43fffe8c66SAdrian Prantldefine_opcode(0x23, None, "lit_selector") 44fffe8c66SAdrian Prantl 45fffe8c66SAdrian Prantldefine_opcode(0x2A, "as_int", "as_int") 46fffe8c66SAdrian Prantldefine_opcode(0x2B, "as_uint", "as_uint") 47fffe8c66SAdrian Prantldefine_opcode(0x2C, "is_null", "is_null") 48fffe8c66SAdrian Prantl 49fffe8c66SAdrian Prantldefine_opcode(0x30, "+", "plus") 50fffe8c66SAdrian Prantldefine_opcode(0x31, "-", "minus") 51fffe8c66SAdrian Prantldefine_opcode(0x32, "*", "mul") 52fffe8c66SAdrian Prantldefine_opcode(0x33, "/", "div") 53fffe8c66SAdrian Prantldefine_opcode(0x34, "%", "mod") 54fffe8c66SAdrian Prantldefine_opcode(0x35, "<<", "shl") 55fffe8c66SAdrian Prantldefine_opcode(0x36, ">>", "shr") 56fffe8c66SAdrian Prantl 57fffe8c66SAdrian Prantldefine_opcode(0x40, "&", "and") 58fffe8c66SAdrian Prantldefine_opcode(0x41, "|", "or") 59fffe8c66SAdrian Prantldefine_opcode(0x42, "^", "xor") 60fffe8c66SAdrian Prantldefine_opcode(0x43, "~", "not") 61fffe8c66SAdrian Prantl 62fffe8c66SAdrian Prantldefine_opcode(0x50, "=", "eq") 63fffe8c66SAdrian Prantldefine_opcode(0x51, "!=", "neq") 64fffe8c66SAdrian Prantldefine_opcode(0x52, "<", "lt") 65fffe8c66SAdrian Prantldefine_opcode(0x53, ">", "gt") 66fffe8c66SAdrian Prantldefine_opcode(0x54, "=<", "le") 67fffe8c66SAdrian Prantldefine_opcode(0x55, ">=", "ge") 68fffe8c66SAdrian Prantl 69fffe8c66SAdrian Prantldefine_opcode(0x60, "call", "call") 70fffe8c66SAdrian Prantl 71fffe8c66SAdrian Prantl# Function signatures 72fffe8c66SAdrian Prantlsig_summary = 0 73fffe8c66SAdrian Prantlsig_init = 1 74fffe8c66SAdrian Prantlsig_get_num_children = 2 75fffe8c66SAdrian Prantlsig_get_child_index = 3 76fffe8c66SAdrian Prantlsig_get_child_at_index = 4 77fffe8c66SAdrian Prantl 78fffe8c66SAdrian Prantl# Selectors 79fffe8c66SAdrian Prantlselector = dict() 80fffe8c66SAdrian Prantl 81fffe8c66SAdrian Prantl 82fffe8c66SAdrian Prantldef define_selector(n, name): 83fffe8c66SAdrian Prantl globals()["sel_" + name] = n 84fffe8c66SAdrian Prantl selector["@" + name] = n 85fffe8c66SAdrian Prantl selector[n] = "@" + name 86fffe8c66SAdrian Prantl 87fffe8c66SAdrian Prantl 88fffe8c66SAdrian Prantldefine_selector(0, "summary") 89fffe8c66SAdrian Prantldefine_selector(1, "type_summary") 90fffe8c66SAdrian Prantl 91fffe8c66SAdrian Prantldefine_selector(0x10, "get_num_children") 92fffe8c66SAdrian Prantldefine_selector(0x11, "get_child_at_index") 93fffe8c66SAdrian Prantldefine_selector(0x12, "get_child_with_name") 94fffe8c66SAdrian Prantldefine_selector(0x13, "get_child_index") 95fffe8c66SAdrian Prantldefine_selector(0x15, "get_type") 96fffe8c66SAdrian Prantldefine_selector(0x16, "get_template_argument_type") 97fffe8c66SAdrian Prantldefine_selector(0x17, "cast") 98fffe8c66SAdrian Prantldefine_selector(0x20, "get_value") 99fffe8c66SAdrian Prantldefine_selector(0x21, "get_value_as_unsigned") 100fffe8c66SAdrian Prantldefine_selector(0x22, "get_value_as_signed") 101fffe8c66SAdrian Prantldefine_selector(0x23, "get_value_as_address") 102fffe8c66SAdrian Prantl 103fffe8c66SAdrian Prantldefine_selector(0x40, "read_memory_byte") 104fffe8c66SAdrian Prantldefine_selector(0x41, "read_memory_uint32") 105fffe8c66SAdrian Prantldefine_selector(0x42, "read_memory_int32") 106fffe8c66SAdrian Prantldefine_selector(0x43, "read_memory_unsigned") 107fffe8c66SAdrian Prantldefine_selector(0x44, "read_memory_signed") 108fffe8c66SAdrian Prantldefine_selector(0x45, "read_memory_address") 109fffe8c66SAdrian Prantldefine_selector(0x46, "read_memory") 110fffe8c66SAdrian Prantl 111fffe8c66SAdrian Prantldefine_selector(0x50, "fmt") 112fffe8c66SAdrian Prantldefine_selector(0x51, "sprintf") 113fffe8c66SAdrian Prantldefine_selector(0x52, "strlen") 114fffe8c66SAdrian Prantl 115fffe8c66SAdrian Prantl 116fffe8c66SAdrian Prantl################################################################################ 117fffe8c66SAdrian Prantl# Compiler. 118fffe8c66SAdrian Prantl################################################################################ 119fffe8c66SAdrian Prantl 120fffe8c66SAdrian Prantl 121fffe8c66SAdrian Prantldef compile(assembler: str) -> bytearray: 122fffe8c66SAdrian Prantl """Compile assembler into bytecode""" 123fffe8c66SAdrian Prantl # This is a stack of all in-flight/unterminated blocks. 124fffe8c66SAdrian Prantl bytecode = [bytearray()] 125fffe8c66SAdrian Prantl 126fffe8c66SAdrian Prantl def emit(byte): 127fffe8c66SAdrian Prantl bytecode[-1].append(byte) 128fffe8c66SAdrian Prantl 129fffe8c66SAdrian Prantl tokens = list(assembler.split(" ")) 130fffe8c66SAdrian Prantl tokens.reverse() 131fffe8c66SAdrian Prantl while tokens: 132fffe8c66SAdrian Prantl tok = tokens.pop() 133fffe8c66SAdrian Prantl if tok == "": 134fffe8c66SAdrian Prantl pass 135fffe8c66SAdrian Prantl elif tok == "{": 136fffe8c66SAdrian Prantl bytecode.append(bytearray()) 137fffe8c66SAdrian Prantl elif tok == "}": 138fffe8c66SAdrian Prantl block = bytecode.pop() 139fffe8c66SAdrian Prantl emit(op_begin) 140fffe8c66SAdrian Prantl emit(len(block)) # FIXME: uleb 141fffe8c66SAdrian Prantl bytecode[-1].extend(block) 142fffe8c66SAdrian Prantl elif tok[0].isdigit(): 143fffe8c66SAdrian Prantl if tok[-1] == "u": 144fffe8c66SAdrian Prantl emit(op_lit_uint) 145fffe8c66SAdrian Prantl emit(int(tok[:-1])) # FIXME 146fffe8c66SAdrian Prantl else: 147fffe8c66SAdrian Prantl emit(op_lit_int) 148fffe8c66SAdrian Prantl emit(int(tok)) # FIXME 149fffe8c66SAdrian Prantl elif tok[0] == "@": 150fffe8c66SAdrian Prantl emit(op_lit_selector) 151fffe8c66SAdrian Prantl emit(selector[tok]) 152fffe8c66SAdrian Prantl elif tok[0] == '"': 153fffe8c66SAdrian Prantl s = bytearray() 154fffe8c66SAdrian Prantl done = False 155fffe8c66SAdrian Prantl chrs = tok[1:] 156fffe8c66SAdrian Prantl while not done: 157fffe8c66SAdrian Prantl quoted = False 158fffe8c66SAdrian Prantl for c in chrs: 159fffe8c66SAdrian Prantl if quoted: 160fffe8c66SAdrian Prantl s.append(ord(c)) # FIXME 161fffe8c66SAdrian Prantl quoted = False 162fffe8c66SAdrian Prantl elif c == "\\": 163fffe8c66SAdrian Prantl quoted = True 164fffe8c66SAdrian Prantl elif c == '"': 165fffe8c66SAdrian Prantl done = True 166fffe8c66SAdrian Prantl break 167fffe8c66SAdrian Prantl # FIXME assert this is last in token 168fffe8c66SAdrian Prantl else: 169fffe8c66SAdrian Prantl s.append(ord(c)) 170fffe8c66SAdrian Prantl if not done: 171fffe8c66SAdrian Prantl s.append(ord(" ")) 172fffe8c66SAdrian Prantl chrs = tokens.pop() 173fffe8c66SAdrian Prantl 174fffe8c66SAdrian Prantl emit(op_lit_string) 175fffe8c66SAdrian Prantl emit(len(s)) 176fffe8c66SAdrian Prantl bytecode[-1].extend(s) 177fffe8c66SAdrian Prantl else: 178fffe8c66SAdrian Prantl emit(opcode[tok]) 179fffe8c66SAdrian Prantl assert len(bytecode) == 1 # unterminated { 180fffe8c66SAdrian Prantl return bytecode[0] 181fffe8c66SAdrian Prantl 182fffe8c66SAdrian Prantl 183fffe8c66SAdrian Prantl################################################################################ 184fffe8c66SAdrian Prantl# Disassembler. 185fffe8c66SAdrian Prantl################################################################################ 186fffe8c66SAdrian Prantl 187fffe8c66SAdrian Prantl 188fffe8c66SAdrian Prantldef disassemble(bytecode: bytearray) -> (str, int): 189fffe8c66SAdrian Prantl """Disassemble bytecode into (assembler, token starts)""" 190fffe8c66SAdrian Prantl asm = "" 191fffe8c66SAdrian Prantl all_bytes = list(bytecode) 192fffe8c66SAdrian Prantl all_bytes.reverse() 193fffe8c66SAdrian Prantl blocks = [] 194fffe8c66SAdrian Prantl tokens = [0] 195fffe8c66SAdrian Prantl 196fffe8c66SAdrian Prantl def next_byte(): 197fffe8c66SAdrian Prantl """Fetch the next byte in the bytecode and keep track of all 198fffe8c66SAdrian Prantl in-flight blocks""" 199fffe8c66SAdrian Prantl for i in range(len(blocks)): 200fffe8c66SAdrian Prantl blocks[i] -= 1 201fffe8c66SAdrian Prantl tokens.append(len(asm)) 202fffe8c66SAdrian Prantl return all_bytes.pop() 203fffe8c66SAdrian Prantl 204fffe8c66SAdrian Prantl while all_bytes: 205fffe8c66SAdrian Prantl b = next_byte() 206fffe8c66SAdrian Prantl if b == op_begin: 207fffe8c66SAdrian Prantl asm += "{" 208fffe8c66SAdrian Prantl length = next_byte() 209fffe8c66SAdrian Prantl blocks.append(length) 210fffe8c66SAdrian Prantl elif b == op_lit_uint: 211fffe8c66SAdrian Prantl b = next_byte() 212fffe8c66SAdrian Prantl asm += str(b) # FIXME uleb 213fffe8c66SAdrian Prantl asm += "u" 214fffe8c66SAdrian Prantl elif b == op_lit_int: 215fffe8c66SAdrian Prantl b = next_byte() 216fffe8c66SAdrian Prantl asm += str(b) 217fffe8c66SAdrian Prantl elif b == op_lit_selector: 218fffe8c66SAdrian Prantl b = next_byte() 219fffe8c66SAdrian Prantl asm += selector[b] 220fffe8c66SAdrian Prantl elif b == op_lit_string: 221fffe8c66SAdrian Prantl length = next_byte() 222fffe8c66SAdrian Prantl s = "'" 223fffe8c66SAdrian Prantl while length: 224fffe8c66SAdrian Prantl s += chr(next_byte()) 225fffe8c66SAdrian Prantl length -= 1 226fffe8c66SAdrian Prantl asm += '"' + repr(s)[2:] 227fffe8c66SAdrian Prantl else: 228fffe8c66SAdrian Prantl asm += opcode[b] 229fffe8c66SAdrian Prantl 230fffe8c66SAdrian Prantl while blocks and blocks[-1] == 0: 231fffe8c66SAdrian Prantl asm += " }" 232fffe8c66SAdrian Prantl blocks.pop() 233fffe8c66SAdrian Prantl 234fffe8c66SAdrian Prantl if all_bytes: 235fffe8c66SAdrian Prantl asm += " " 236fffe8c66SAdrian Prantl 237fffe8c66SAdrian Prantl if blocks: 238fffe8c66SAdrian Prantl asm += "ERROR" 239fffe8c66SAdrian Prantl return asm, tokens 240fffe8c66SAdrian Prantl 241fffe8c66SAdrian Prantl 242fffe8c66SAdrian Prantl################################################################################ 243fffe8c66SAdrian Prantl# Interpreter. 244fffe8c66SAdrian Prantl################################################################################ 245fffe8c66SAdrian Prantl 246fffe8c66SAdrian Prantl 247fffe8c66SAdrian Prantldef count_fmt_params(fmt: str) -> int: 248fffe8c66SAdrian Prantl """Count the number of parameters in a format string""" 249fffe8c66SAdrian Prantl from string import Formatter 250fffe8c66SAdrian Prantl 251fffe8c66SAdrian Prantl f = Formatter() 252fffe8c66SAdrian Prantl n = 0 253fffe8c66SAdrian Prantl for _, name, _, _ in f.parse(fmt): 254fffe8c66SAdrian Prantl if name > n: 255fffe8c66SAdrian Prantl n = name 256fffe8c66SAdrian Prantl return n 257fffe8c66SAdrian Prantl 258fffe8c66SAdrian Prantl 259fffe8c66SAdrian Prantldef interpret(bytecode: bytearray, control: list, data: list, tracing: bool = False): 260fffe8c66SAdrian Prantl """Interpret bytecode""" 261fffe8c66SAdrian Prantl frame = [] 262fffe8c66SAdrian Prantl frame.append((0, len(bytecode))) 263fffe8c66SAdrian Prantl 264fffe8c66SAdrian Prantl def trace(): 265fffe8c66SAdrian Prantl """print a trace of the execution for debugging purposes""" 266fffe8c66SAdrian Prantl 267fffe8c66SAdrian Prantl def fmt(d): 268fffe8c66SAdrian Prantl if isinstance(d, int): 269fffe8c66SAdrian Prantl return str(d) 270fffe8c66SAdrian Prantl if isinstance(d, str): 271fffe8c66SAdrian Prantl return d 272fffe8c66SAdrian Prantl return repr(type(d)) 273fffe8c66SAdrian Prantl 274fffe8c66SAdrian Prantl pc, end = frame[-1] 275fffe8c66SAdrian Prantl asm, tokens = disassemble(bytecode) 276fffe8c66SAdrian Prantl print( 277fffe8c66SAdrian Prantl "=== frame = {1}, data = {2}, opcode = {0}".format( 278fffe8c66SAdrian Prantl opcode[b], frame, [fmt(d) for d in data] 279fffe8c66SAdrian Prantl ) 280fffe8c66SAdrian Prantl ) 281fffe8c66SAdrian Prantl print(asm) 282fffe8c66SAdrian Prantl print(" " * (tokens[pc]) + "^") 283fffe8c66SAdrian Prantl 284fffe8c66SAdrian Prantl def next_byte(): 285fffe8c66SAdrian Prantl """Fetch the next byte and update the PC""" 286fffe8c66SAdrian Prantl pc, end = frame[-1] 287fffe8c66SAdrian Prantl assert pc < len(bytecode) 288fffe8c66SAdrian Prantl b = bytecode[pc] 289fffe8c66SAdrian Prantl frame[-1] = pc + 1, end 290fffe8c66SAdrian Prantl # At the end of a block? 291fffe8c66SAdrian Prantl while pc >= end: 292fffe8c66SAdrian Prantl frame.pop() 293fffe8c66SAdrian Prantl if not frame: 294fffe8c66SAdrian Prantl return None 295fffe8c66SAdrian Prantl pc, end = frame[-1] 296fffe8c66SAdrian Prantl if pc >= end: 297fffe8c66SAdrian Prantl return None 298fffe8c66SAdrian Prantl b = bytecode[pc] 299fffe8c66SAdrian Prantl frame[-1] = pc + 1, end 300fffe8c66SAdrian Prantl return b 301fffe8c66SAdrian Prantl 302fffe8c66SAdrian Prantl while frame[-1][0] < len(bytecode): 303fffe8c66SAdrian Prantl b = next_byte() 304fffe8c66SAdrian Prantl if b == None: 305fffe8c66SAdrian Prantl break 306fffe8c66SAdrian Prantl if tracing: 307fffe8c66SAdrian Prantl trace() 308fffe8c66SAdrian Prantl # Data stack manipulation. 309fffe8c66SAdrian Prantl if b == op_dup: 310fffe8c66SAdrian Prantl data.append(data[-1]) 311fffe8c66SAdrian Prantl elif b == op_drop: 312fffe8c66SAdrian Prantl data.pop() 313fffe8c66SAdrian Prantl elif b == op_pick: 314fffe8c66SAdrian Prantl data.append(data[data.pop()]) 315fffe8c66SAdrian Prantl elif b == op_over: 316fffe8c66SAdrian Prantl data.append(data[-2]) 317fffe8c66SAdrian Prantl elif b == op_swap: 318fffe8c66SAdrian Prantl x = data.pop() 319fffe8c66SAdrian Prantl y = data.pop() 320fffe8c66SAdrian Prantl data.append(x) 321fffe8c66SAdrian Prantl data.append(y) 322fffe8c66SAdrian Prantl elif b == op_rot: 323fffe8c66SAdrian Prantl z = data.pop() 324fffe8c66SAdrian Prantl y = data.pop() 325fffe8c66SAdrian Prantl x = data.pop() 326fffe8c66SAdrian Prantl data.append(z) 327fffe8c66SAdrian Prantl data.append(x) 328fffe8c66SAdrian Prantl data.append(y) 329fffe8c66SAdrian Prantl 330fffe8c66SAdrian Prantl # Control stack manipulation. 331fffe8c66SAdrian Prantl elif b == op_begin: 332fffe8c66SAdrian Prantl length = next_byte() 333fffe8c66SAdrian Prantl pc, end = frame[-1] 334fffe8c66SAdrian Prantl control.append((pc, pc + length)) 335fffe8c66SAdrian Prantl frame[-1] = pc + length, end 336fffe8c66SAdrian Prantl elif b == op_if: 337fffe8c66SAdrian Prantl if data.pop(): 338fffe8c66SAdrian Prantl frame.append(control.pop()) 339fffe8c66SAdrian Prantl elif b == op_ifelse: 340fffe8c66SAdrian Prantl if data.pop(): 341fffe8c66SAdrian Prantl control.pop() 342fffe8c66SAdrian Prantl frame.append(control.pop()) 343fffe8c66SAdrian Prantl else: 344fffe8c66SAdrian Prantl frame.append(control.pop()) 345fffe8c66SAdrian Prantl control.pop() 346*ee1adc5aSAdrian Prantl elif b == op_return: 347*ee1adc5aSAdrian Prantl control.clear() 348*ee1adc5aSAdrian Prantl return data[-1] 349fffe8c66SAdrian Prantl 350fffe8c66SAdrian Prantl # Literals. 351fffe8c66SAdrian Prantl elif b == op_lit_uint: 352fffe8c66SAdrian Prantl b = next_byte() # FIXME uleb 353fffe8c66SAdrian Prantl data.append(int(b)) 354fffe8c66SAdrian Prantl elif b == op_lit_int: 355fffe8c66SAdrian Prantl b = next_byte() # FIXME uleb 356fffe8c66SAdrian Prantl data.append(int(b)) 357fffe8c66SAdrian Prantl elif b == op_lit_selector: 358fffe8c66SAdrian Prantl b = next_byte() 359fffe8c66SAdrian Prantl data.append(b) 360fffe8c66SAdrian Prantl elif b == op_lit_string: 361fffe8c66SAdrian Prantl length = next_byte() 362fffe8c66SAdrian Prantl s = "" 363fffe8c66SAdrian Prantl while length: 364fffe8c66SAdrian Prantl s += chr(next_byte()) 365fffe8c66SAdrian Prantl length -= 1 366fffe8c66SAdrian Prantl data.append(s) 367fffe8c66SAdrian Prantl 368fffe8c66SAdrian Prantl elif b == op_as_uint: 369fffe8c66SAdrian Prantl pass 370fffe8c66SAdrian Prantl elif b == op_as_int: 371fffe8c66SAdrian Prantl pass 372fffe8c66SAdrian Prantl elif b == op_is_null: 373fffe8c66SAdrian Prantl data.append(1 if data.pop() == None else 0) 374fffe8c66SAdrian Prantl 375fffe8c66SAdrian Prantl # Arithmetic, logic, etc. 376fffe8c66SAdrian Prantl elif b == op_plus: 377fffe8c66SAdrian Prantl data.append(data.pop() + data.pop()) 378fffe8c66SAdrian Prantl elif b == op_minus: 379fffe8c66SAdrian Prantl data.append(-data.pop() + data.pop()) 380fffe8c66SAdrian Prantl elif b == op_mul: 381fffe8c66SAdrian Prantl data.append(data.pop() * data.pop()) 382fffe8c66SAdrian Prantl elif b == op_div: 383fffe8c66SAdrian Prantl y = data.pop() 384fffe8c66SAdrian Prantl data.append(data.pop() / y) 385fffe8c66SAdrian Prantl elif b == op_mod: 386fffe8c66SAdrian Prantl y = data.pop() 387fffe8c66SAdrian Prantl data.append(data.pop() % y) 388fffe8c66SAdrian Prantl elif b == op_shl: 389fffe8c66SAdrian Prantl y = data.pop() 390fffe8c66SAdrian Prantl data.append(data.pop() << y) 391fffe8c66SAdrian Prantl elif b == op_shr: 392fffe8c66SAdrian Prantl y = data.pop() 393fffe8c66SAdrian Prantl data.append(data.pop() >> y) 394fffe8c66SAdrian Prantl elif b == op_and: 395fffe8c66SAdrian Prantl data.append(data.pop() & data.pop()) 396fffe8c66SAdrian Prantl elif b == op_or: 397fffe8c66SAdrian Prantl data.append(data.pop() | data.pop()) 398fffe8c66SAdrian Prantl elif b == op_xor: 399fffe8c66SAdrian Prantl data.append(data.pop() ^ data.pop()) 400fffe8c66SAdrian Prantl elif b == op_not: 401fffe8c66SAdrian Prantl data.append(not data.pop()) 402fffe8c66SAdrian Prantl elif b == op_eq: 403fffe8c66SAdrian Prantl data.append(data.pop() == data.pop()) 404fffe8c66SAdrian Prantl elif b == op_neq: 405fffe8c66SAdrian Prantl data.append(data.pop() != data.pop()) 406fffe8c66SAdrian Prantl elif b == op_lt: 407fffe8c66SAdrian Prantl data.append(data.pop() > data.pop()) 408fffe8c66SAdrian Prantl elif b == op_gt: 409fffe8c66SAdrian Prantl data.append(data.pop() < data.pop()) 410fffe8c66SAdrian Prantl elif b == op_le: 411fffe8c66SAdrian Prantl data.append(data.pop() >= data.pop()) 412fffe8c66SAdrian Prantl elif b == op_ge: 413fffe8c66SAdrian Prantl data.append(data.pop() <= data.pop()) 414fffe8c66SAdrian Prantl 415fffe8c66SAdrian Prantl # Function calls. 416fffe8c66SAdrian Prantl elif b == op_call: 417fffe8c66SAdrian Prantl sel = data.pop() 418fffe8c66SAdrian Prantl if sel == sel_summary: 419fffe8c66SAdrian Prantl data.append(data.pop().GetSummary()) 420fffe8c66SAdrian Prantl elif sel == sel_get_num_children: 421fffe8c66SAdrian Prantl data.append(data.pop().GetNumChildren()) 422fffe8c66SAdrian Prantl elif sel == sel_get_child_at_index: 423fffe8c66SAdrian Prantl index = data.pop() 424fffe8c66SAdrian Prantl valobj = data.pop() 425fffe8c66SAdrian Prantl data.append(valobj.GetChildAtIndex(index)) 426fffe8c66SAdrian Prantl elif sel == sel_get_child_with_name: 427fffe8c66SAdrian Prantl name = data.pop() 428fffe8c66SAdrian Prantl valobj = data.pop() 429fffe8c66SAdrian Prantl data.append(valobj.GetChildMemberWithName(name)) 430fffe8c66SAdrian Prantl elif sel == sel_get_child_index: 431fffe8c66SAdrian Prantl name = data.pop() 432fffe8c66SAdrian Prantl valobj = data.pop() 433fffe8c66SAdrian Prantl data.append(valobj.GetIndexOfChildWithName(name)) 434fffe8c66SAdrian Prantl elif sel == sel_get_type: 435fffe8c66SAdrian Prantl data.append(data.pop().GetType()) 436fffe8c66SAdrian Prantl elif sel == sel_get_template_argument_type: 437fffe8c66SAdrian Prantl n = data.pop() 438fffe8c66SAdrian Prantl valobj = data.pop() 439fffe8c66SAdrian Prantl data.append(valobj.GetTemplateArgumentType(n)) 440fffe8c66SAdrian Prantl elif sel == sel_get_value: 441fffe8c66SAdrian Prantl data.append(data.pop().GetValue()) 442fffe8c66SAdrian Prantl elif sel == sel_get_value_as_unsigned: 443fffe8c66SAdrian Prantl data.append(data.pop().GetValueAsUnsigned()) 444fffe8c66SAdrian Prantl elif sel == sel_get_value_as_signed: 445fffe8c66SAdrian Prantl data.append(data.pop().GetValueAsSigned()) 446fffe8c66SAdrian Prantl elif sel == sel_get_value_as_address: 447fffe8c66SAdrian Prantl data.append(data.pop().GetValueAsAddress()) 448fffe8c66SAdrian Prantl elif sel == sel_cast: 449fffe8c66SAdrian Prantl sbtype = data.pop() 450fffe8c66SAdrian Prantl valobj = data.pop() 451fffe8c66SAdrian Prantl data.append(valobj.Cast(sbtype)) 452fffe8c66SAdrian Prantl elif sel == sel_strlen: 453fffe8c66SAdrian Prantl s = data.pop() 454fffe8c66SAdrian Prantl data.append(len(s) if s else 0) 455fffe8c66SAdrian Prantl elif sel == sel_fmt: 456fffe8c66SAdrian Prantl fmt = data.pop() 457fffe8c66SAdrian Prantl n = count_fmt_params(fmt) 458fffe8c66SAdrian Prantl args = [] 459fffe8c66SAdrian Prantl for i in range(n): 460fffe8c66SAdrian Prantl args.append(data.pop()) 461fffe8c66SAdrian Prantl data.append(fmt.format(*args)) 462fffe8c66SAdrian Prantl else: 463fffe8c66SAdrian Prantl print("not implemented: " + selector[sel]) 464fffe8c66SAdrian Prantl assert False 465fffe8c66SAdrian Prantl pass 466fffe8c66SAdrian Prantl return data[-1] 467fffe8c66SAdrian Prantl 468fffe8c66SAdrian Prantl 469fffe8c66SAdrian Prantlif __name__ == "__main__": 4709f98949cSAdrian Prantl # Work around the fact that one of the local files is called 4719f98949cSAdrian Prantl # types.py, which breaks some versions of python. 4729f98949cSAdrian Prantl import os, sys 4739f98949cSAdrian Prantl 4749f98949cSAdrian Prantl path = os.path.abspath(os.path.dirname(__file__)) 4759f98949cSAdrian Prantl sys.path.remove(path) 476fffe8c66SAdrian Prantl import argparse 477fffe8c66SAdrian Prantl 478fffe8c66SAdrian Prantl parser = argparse.ArgumentParser( 479fffe8c66SAdrian Prantl description=""" 480fffe8c66SAdrian Prantl Compiler, disassembler, and interpreter for LLDB dataformatter bytecode. 481fffe8c66SAdrian Prantl See https://lldb.llvm.org/resources/formatterbytecode.html for more details. 482fffe8c66SAdrian Prantl """ 483fffe8c66SAdrian Prantl ) 484fffe8c66SAdrian Prantl parser.add_argument( 485fffe8c66SAdrian Prantl "-c", "--compile", type=str, help="compile assembler into bytecode" 486fffe8c66SAdrian Prantl ) 487fffe8c66SAdrian Prantl parser.add_argument("-d", "--disassemble", type=str, help="disassemble bytecode") 488fffe8c66SAdrian Prantl parser.add_argument("-t", "--test", action="store_true", help="run unit tests") 489fffe8c66SAdrian Prantl args = parser.parse_args() 490fffe8c66SAdrian Prantl if args.compile: 491fffe8c66SAdrian Prantl print(compile(str(args.compile)).hex()) 492fffe8c66SAdrian Prantl 493fffe8c66SAdrian Prantl if args.disassemble: 494fffe8c66SAdrian Prantl print(disassemble(bytearray.fromhex(str(args.disassemble)))) 495fffe8c66SAdrian Prantl 496fffe8c66SAdrian Prantl ############################################################################ 497fffe8c66SAdrian Prantl # Tests. 498fffe8c66SAdrian Prantl ############################################################################ 499fffe8c66SAdrian Prantl if args.test: 500fffe8c66SAdrian Prantl import unittest 501fffe8c66SAdrian Prantl 502fffe8c66SAdrian Prantl class TestCompiler(unittest.TestCase): 503fffe8c66SAdrian Prantl def test(self): 504fffe8c66SAdrian Prantl self.assertEqual(compile("1u dup").hex(), "200101") 505fffe8c66SAdrian Prantl self.assertEqual(compile('"1u dup"').hex(), "2206317520647570") 506fffe8c66SAdrian Prantl self.assertEqual(compile("16 < { dup } if").hex(), "21105210010111") 507fffe8c66SAdrian Prantl self.assertEqual(compile('{ { " } " } }').hex(), "100710052203207d20") 508fffe8c66SAdrian Prantl 509fffe8c66SAdrian Prantl def roundtrip(asm): 510fffe8c66SAdrian Prantl self.assertEqual(disassemble(compile(asm))[0], asm) 511fffe8c66SAdrian Prantl 512fffe8c66SAdrian Prantl roundtrip("1u dup") 513fffe8c66SAdrian Prantl roundtrip('1u dup "1u dup"') 514fffe8c66SAdrian Prantl roundtrip("16 < { dup } if") 515fffe8c66SAdrian Prantl roundtrip('{ { " } " } }') 516fffe8c66SAdrian Prantl 517fffe8c66SAdrian Prantl self.assertEqual(interpret(compile("1 1 +"), [], []), 2) 518fffe8c66SAdrian Prantl self.assertEqual(interpret(compile("2 1 1 + *"), [], []), 4) 519fffe8c66SAdrian Prantl self.assertEqual( 520fffe8c66SAdrian Prantl interpret(compile('2 1 > { "yes" } { "no" } ifelse'), [], []), "yes" 521fffe8c66SAdrian Prantl ) 522fffe8c66SAdrian Prantl 523fffe8c66SAdrian Prantl import sys 524fffe8c66SAdrian Prantl 525fffe8c66SAdrian Prantl sys.argv.pop() 526fffe8c66SAdrian Prantl path = os.path.dirname(__file__) 527fffe8c66SAdrian Prantl sys.path.remove 528fffe8c66SAdrian Prantl unittest.main() 529