| """ | |
| Test the lldb disassemble command on lib stdc++. | |
| """ | |
| import os | |
| import re | |
| import lldb | |
| from lldbsuite.test.lldbtest import * | |
| import lldbsuite.test.lldbutil as lldbutil | |
| from lldbsuite.test.decorators import * | |
| class StdCXXDisassembleTestCase(TestBase): | |
| @skipIfWindows | |
| def test_stdcxx_disasm(self): | |
| """Do 'disassemble' on each and every 'Code' symbol entry from the std c++ lib.""" | |
| self.build() | |
| (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( | |
| self, "// Set break point at this line", lldb.SBFileSpec("main.cpp") | |
| ) | |
| # Disassemble the functions on the call stack. | |
| self.runCmd("thread backtrace") | |
| thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) | |
| self.assertIsNotNone(thread) | |
| depth = thread.GetNumFrames() | |
| for i in range(depth - 1): | |
| frame = thread.GetFrameAtIndex(i) | |
| function = frame.GetFunction() | |
| if function.GetName(): | |
| self.runCmd("disassemble -n '%s'" % function.GetName()) | |
| lib_stdcxx = "FAILHORRIBLYHERE" | |
| # Find the stdc++ library... | |
| stdlib_regex = re.compile(r"/lib(std)?c\+\+") | |
| for module in target.module[stdlib_regex]: | |
| lib_stdcxx = module.file.fullpath | |
| break | |
| # At this point, lib_stdcxx is the full path to the stdc++ library and | |
| # module is the corresponding SBModule. | |
| if "lib" not in lib_stdcxx: | |
| self.skipTest( | |
| "This test requires libstdc++.so or libc++.dylib in the target's module list." | |
| ) | |
| self.runCmd("image dump symtab '%s'" % lib_stdcxx) | |
| raw_output = self.res.GetOutput() | |
| # Now, look for every 'Code' symbol and feed its load address into the | |
| # command: 'disassemble -s load_address -e end_address', where the | |
| # end_address is taken from the next consecutive 'Code' symbol entry's | |
| # load address. | |
| # | |
| # The load address column comes after the file address column, with both | |
| # looks like '0xhhhhhhhh', i.e., 8 hexadecimal digits. | |
| codeRE = re.compile( | |
| r""" | |
| \ Code\ {9} # ' Code' followed by 9 SPCs, | |
| 0x[0-9a-f]{16} # the file address column, and | |
| \ # a SPC, and | |
| (0x[0-9a-f]{16}) # the load address column, and | |
| .* # the rest. | |
| """, | |
| re.VERBOSE, | |
| ) | |
| # Maintain a start address variable; if we arrive at a consecutive Code | |
| # entry, then the load address of the that entry is fed as the end | |
| # address to the 'disassemble -s SA -e LA' command. | |
| SA = None | |
| for line in raw_output.split(os.linesep): | |
| match = codeRE.search(line) | |
| if match: | |
| LA = match.group(1) | |
| if self.TraceOn(): | |
| print("line:", line) | |
| print("load address:", LA) | |
| print("SA:", SA) | |
| if SA and LA: | |
| if int(LA, 16) > int(SA, 16): | |
| self.runCmd("disassemble -s %s -e %s" % (SA, LA)) | |
| SA = LA | |
| else: | |
| # This entry is not a Code entry. Reset SA = None. | |
| SA = None |