1""" 2Test the lldb disassemble command on lib stdc++. 3""" 4 5import os, time 6import unittest2 7import lldb 8from lldbtest import * 9import lldbutil 10 11class StdCXXDisassembleTestCase(TestBase): 12 13 mydir = os.path.join("lang", "cpp", "stl") 14 15 def setUp(self): 16 # Call super's setUp(). 17 TestBase.setUp(self) 18 # Find the line number to break inside main(). 19 self.line = line_number('main.cpp', '// Set break point at this line.') 20 21 # rdar://problem/8504895 22 # Crash while doing 'disassemble -n "-[NSNumber descriptionWithLocale:]" 23 @unittest2.skipIf(TestBase.skipLongRunningTest(), "Skip this long running test") 24 def test_stdcxx_disasm(self): 25 """Do 'disassemble' on each and every 'Code' symbol entry from the std c++ lib.""" 26 self.buildDefault() 27 exe = os.path.join(os.getcwd(), "a.out") 28 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 29 30 # rdar://problem/8543077 31 # test/stl: clang built binaries results in the breakpoint locations = 3, 32 # is this a problem with clang generated debug info? 33 # 34 # Break on line 13 of main.cpp. 35 lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True) 36 37 self.runCmd("run", RUN_SUCCEEDED) 38 39 # Now let's get the target as well as the process objects. 40 target = self.dbg.GetSelectedTarget() 41 process = target.GetProcess() 42 43 # The process should be in a 'stopped' state. 44 self.expect(str(process), STOPPED_DUE_TO_BREAKPOINT, exe=False, 45 substrs = ["a.out", 46 "stopped"]) 47 48 # Disassemble the functions on the call stack. 49 self.runCmd("thread backtrace") 50 thread = process.GetThreadAtIndex(0) 51 depth = thread.GetNumFrames() 52 for i in range(depth - 1): 53 frame = thread.GetFrameAtIndex(i) 54 function = frame.GetFunction() 55 self.runCmd("disassemble -n '%s'" % function.GetName()) 56 57 # Iterate through the available modules, looking for stdc++ library... 58 for i in range(target.GetNumModules()): 59 module = target.GetModuleAtIndex(i) 60 fs = module.GetFileSpec() 61 if (fs.GetFilename().startswith("libstdc++")): 62 lib_stdcxx = str(fs) 63 break 64 65 # At this point, lib_stdcxx is the full path to the stdc++ library and 66 # module is the corresponding SBModule. 67 68 self.expect(fs.GetFilename(), "Libraray StdC++ is located", exe=False, 69 substrs = ["libstdc++"]) 70 71 self.runCmd("image dump symtab %s" % str(fs)) 72 raw_output = self.res.GetOutput() 73 # Now, look for every 'Code' symbol and feed its load address into the 74 # command: 'disassemble -s load_address -e end_address', where the 75 # end_address is taken from the next consecutive 'Code' symbol entry's 76 # load address. 77 # 78 # The load address column comes after the file address column, with both 79 # looks like '0xhhhhhhhh', i.e., 8 hexadecimal digits. 80 codeRE = re.compile(r""" 81 \ Code\ {9} # ' Code' followed by 9 SPCs, 82 0x[0-9a-f]{16} # the file address column, and 83 \ # a SPC, and 84 (0x[0-9a-f]{16}) # the load address column, and 85 .* # the rest. 86 """, re.VERBOSE) 87 # Maintain a start address variable; if we arrive at a consecutive Code 88 # entry, then the load address of the that entry is fed as the end 89 # address to the 'disassemble -s SA -e LA' command. 90 SA = None 91 for line in raw_output.split(os.linesep): 92 match = codeRE.search(line) 93 if match: 94 LA = match.group(1) 95 if self.TraceOn(): 96 print "line:", line 97 print "load address:", LA 98 print "SA:", SA 99 if SA and LA: 100 if int(LA, 16) > int(SA, 16): 101 self.runCmd("disassemble -s %s -e %s" % (SA, LA)) 102 SA = LA 103 else: 104 # This entry is not a Code entry. Reset SA = None. 105 SA = None 106 107 108if __name__ == '__main__': 109 import atexit 110 lldb.SBDebugger.Initialize() 111 atexit.register(lambda: lldb.SBDebugger.Terminate()) 112 unittest2.main() 113