From bca8952fc7e31e3d325e70368db2c83f4f701709 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 8 Oct 2020 16:29:17 -0700 Subject: Fix lldb disassembler so it works with core files This fixes the lldb disassembler script so that it doesn't need a live process when disassembling rb_iseq_t. I also added the PC to the output so you can tell what the VM is executing when it crashed. For example: ``` (lldb) rbdisasm ec->cfp->iseq PC IDX insn_name(operands) 0x56039f0a1720 0000 nop 0x56039f0a1728 0001 getlocal_WC_1( 5 ) 0x56039f0a1738 0003 branchunless( 7 ) 0x56039f0a1748 0005 getlocal_WC_0( 3 ) 0x56039f0a1758 0007 putstring( (VALUE)0x56039f0c7eb8 ) 0x56039f0a1768 0009 opt_send_without_block( (struct rb_call_data *)0x56039f09f140 ) 0x56039f0a1778 0011 pop 0x56039f0a1780 0012 getglobal( ID: 0x7fd7 ) 0x56039f0a1790 0014 branchunless( 7 ) 0x56039f0a17a0 0016 getlocal_WC_0( 3 ) 0x56039f0a17b0 0018 putstring( (VALUE)0x56039f0c7e90 ) 0x56039f0a17c0 0020 opt_send_without_block( (struct rb_call_data *)0x56039f09f150 ) 0x56039f0a17d0 0022 pop 0x56039f0a17d8 0023 getlocal_WC_0( 3 ) 0x56039f0a17e8 0025 putobject( (VALUE)0x56039f0c7e68 ) 0x56039f0a17f8 0027 getlocal_WC_1( 6 ) 0x56039f0a1808 0029 dup 0x56039f0a1810 0030 checktype( 5 ) 0x56039f0a1820 0032 branchif( 4 ) 0x56039f0a1830 0034 dup 0x56039f0a1838 0035 opt_send_without_block( (struct rb_call_data *)0x56039f09f160 ) 0x56039f0a1848 0037 tostring 0x56039f0a1850 0038 putobject( (VALUE)0x56039f0c7e40 ) 0x56039f0a1860 0040 concatstrings( 3 ) 0x56039f0a1870 0042 opt_send_without_block( (struct rb_call_data *)0x56039f09f170 ) 0x56039f0a1880 0044 nop 0x56039f0a1888 0045 leave (lldb) p ec->cfp->pc (const VALUE *) $146 = 0x000056039f0a1848 ``` Here we can see the VM is currently executing `opt_send_without_block` (because the PC is one ahead of the current instruction) --- misc/lldb_disasm.py | 90 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 24 deletions(-) (limited to 'misc') diff --git a/misc/lldb_disasm.py b/misc/lldb_disasm.py index 936d63fb3c..b46d097910 100644 --- a/misc/lldb_disasm.py +++ b/misc/lldb_disasm.py @@ -73,8 +73,14 @@ class IseqDissassembler: iseq_size = val.GetValueForExpressionPath("->body->iseq_size").GetValueAsUnsigned() iseqs = val.GetValueForExpressionPath("->body->iseq_encoded") idx = 0 + print("PC IDX insn_name(operands) ", file=self.result) while idx < iseq_size: - idx += self.iseq_extract_values(self.debugger, self.target, self.process, self.result, iseqs, idx) + m = self.iseq_extract_values(self.debugger, self.target, self.process, self.result, iseqs, idx) + if m < 1: + print("Error decoding", file=self.result) + return + else: + idx += m def build_addr2insn(self, target): tIntPtr = target.FindFirstType("intptr_t") @@ -98,16 +104,21 @@ class IseqDissassembler: def iseq_extract_values(self, debugger, target, process, result, iseqs, n): tValueP = target.FindFirstType("VALUE") sizeofValueP = tValueP.GetByteSize() - insn = target.CreateValueFromAddress( - "i", lldb.SBAddress(iseqs.unsigned + (n * sizeofValueP), target), tValueP) + pc = iseqs.unsigned + (n * sizeofValueP) + insn = target.CreateValueFromAddress("i", lldb.SBAddress(pc, target), tValueP) addr = insn.GetValueAsUnsigned() orig_insn = self.rb_vm_insn_addr2insn2(target, result, addr) name = self.insn_name(target, process, result, orig_insn) length = self.insn_len(target, orig_insn) - op_types = bytes(self.insn_op_types(target, process, result, orig_insn), 'utf-8') + op_str = self.insn_op_types(target, process, result, orig_insn) + op_types = bytes(op_str, 'utf-8') + + if length != (len(op_types) + 1): + print("error decoding iseqs", file=result) + return -1 - print("%04d %s" % (n, name), file=result, end="") + print("%0#14x %04d %s" % (pc, n, name), file=result, end="") if length == 1: print("", file=result) @@ -131,50 +142,81 @@ class IseqDissassembler: def insn_len(self, target, offset): size_of_char = self.tChar.GetByteSize() - addr_of_table = target.FindSymbols("insn_len.t")[0].GetSymbol().GetStartAddress().GetLoadAddress(target) + symbol = target.FindSymbols("insn_len.t")[0].GetSymbol() + section = symbol.GetStartAddress().GetSection() + addr_of_table = symbol.GetStartAddress().GetOffset() - addr_in_table = addr_of_table + (offset * size_of_char) - addr = lldb.SBAddress(addr_in_table, target) + error = lldb.SBError() + length = section.GetSectionData().GetUnsignedInt8(error, addr_of_table + (offset * size_of_char)) - return target.CreateValueFromAddress("y", addr, self.tChar).GetValueAsUnsigned() + if error.Success(): + return length + else: + print("error getting length: ", error) def insn_op_types(self, target, process, result, insn): tUShort = target.FindFirstType("unsigned short") - self.tChar = target.FindFirstType("char") size_of_short = tUShort.GetByteSize() size_of_char = self.tChar.GetByteSize() - addr_of_table = target.FindSymbols("insn_op_types.y")[0].GetSymbol().GetStartAddress().GetLoadAddress(target) + symbol = target.FindSymbols("insn_op_types.y")[0].GetSymbol() + section = symbol.GetStartAddress().GetSection() + addr_of_table = symbol.GetStartAddress().GetOffset() + addr_in_table = addr_of_table + (insn * size_of_short) - addr = lldb.SBAddress(addr_in_table, target) - offset = target.CreateValueFromAddress("y", addr, tUShort).GetValueAsUnsigned() - addr_of_table = target.FindSymbols("insn_op_types.x")[0].GetSymbol().GetStartAddress().GetLoadAddress(target) + error = lldb.SBError() + offset = section.GetSectionData().GetUnsignedInt16(error, addr_in_table) + + if not error.Success(): + print("error getting op type offset: ", error) + + symbol = target.FindSymbols("insn_op_types.x")[0].GetSymbol() + section = symbol.GetStartAddress().GetSection() + addr_of_table = symbol.GetStartAddress().GetOffset() addr_in_name_table = addr_of_table + (offset * size_of_char) error = lldb.SBError() - return process.ReadCStringFromMemory(addr_in_name_table, 256, error) + types = section.GetSectionData().GetString(error, addr_in_name_table) + if error.Success(): + return types + else: + print("error getting op types: ", error) def insn_name_table_offset(self, target, offset): tUShort = target.FindFirstType("unsigned short") size_of_short = tUShort.GetByteSize() - addr_of_table = target.FindSymbols("insn_name.y")[0].GetSymbol().GetStartAddress().GetLoadAddress(target) + symbol = target.FindSymbols("insn_name.y")[0].GetSymbol() + section = symbol.GetStartAddress().GetSection() + table_offset = symbol.GetStartAddress().GetOffset() + + table_offset = table_offset + (offset * size_of_short) - addr_in_table = addr_of_table + (offset * size_of_short) - addr = lldb.SBAddress(addr_in_table, target) + error = lldb.SBError() + offset = section.GetSectionData().GetUnsignedInt16(error, table_offset) - return target.CreateValueFromAddress("y", addr, tUShort).GetValueAsUnsigned() + if error.Success(): + return offset + else: + print("error getting insn name table offset: ", error) def insn_name(self, target, process, result, offset): - tCharP = target.FindFirstType("char*") - addr_of_table = target.FindSymbols("insn_name.x")[0].GetSymbol().GetStartAddress().GetLoadAddress(target) + symbol = target.FindSymbols("insn_name.x")[0].GetSymbol() + section = symbol.GetStartAddress().GetSection() + addr_of_table = symbol.GetStartAddress().GetOffset() + + name_table_offset = self.insn_name_table_offset(target, offset) + addr_in_name_table = addr_of_table + name_table_offset - addr_in_name_table = addr_of_table + self.insn_name_table_offset(target, offset) - addr = lldb.SBAddress(addr_in_name_table, target) error = lldb.SBError() - return process.ReadCStringFromMemory(addr_in_name_table, 256, error) + name = section.GetSectionData().GetString(error, addr_in_name_table) + + if error.Success(): + return name + else: + print('error getting insn name', error) def disasm(debugger, command, result, internal_dict): disassembler = IseqDissassembler(debugger, command, result, internal_dict) -- cgit v1.2.3