| #!/usr/bin/python | |
| # ---------------------------------------------------------------------- | |
| # | |
| # Be sure to add the python path that points to the LLDB shared library. | |
| # On MacOSX csh, tcsh: | |
| # setenv PYTHONPATH /Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python | |
| # On MacOSX sh, bash: | |
| # export PYTHONPATH=/Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python | |
| # | |
| # This script collect debugging information using LLDB. This script is | |
| # used by TEST=dbg in llvm testsuite to measure quality of debug info in | |
| # optimized builds. | |
| # | |
| # Usage: | |
| # export PYTHONPATH=... | |
| # ./CollectDebugInfUsingLLDB.py program bp_file out_file | |
| # program - Executable program with debug info. | |
| # bp_file - Simple text file listing breakpoints. | |
| # <absolute file name> <line number> | |
| # out_file - Output file where the debug info will be emitted. | |
| # ---------------------------------------------------------------------- | |
| import lldb | |
| import os | |
| import sys | |
| import time | |
| # AlreadyPrintedValues - A place to keep track of recursive values. | |
| AlreadyPrintedValues = {} | |
| # ISAlreadyPrinted - Return true if value is already printed. | |
| def IsAlreadyPrinted(value_name): | |
| if AlreadyPrintedValues.get(value_name) is None: | |
| AlreadyPrintedValues[value_name] = 1 | |
| return False | |
| return True | |
| # print_var_value - Print a variable's value. | |
| def print_var_value(v, file, frame): | |
| if v.IsValid() == False: | |
| return | |
| if IsAlreadyPrinted(v.GetName()): | |
| return | |
| total_children = v.GetNumChildren() | |
| if total_children > 0: | |
| c = 0 | |
| while c < total_children: | |
| child = v.GetChildAtIndex(c) | |
| if child is None: | |
| file.write("None") | |
| else: | |
| if (child.GetName()) is None: | |
| file.write("None") | |
| else: | |
| file.write(child.GetName()) | |
| file.write("=") | |
| print_var_value(child, file, frame) | |
| file.write(",") | |
| c = c + 1 | |
| else: | |
| if v.GetValue(frame) is None: | |
| file.write("None") | |
| else: | |
| file.write(v.GetValue(frame)) | |
| def disable_bp(thread): | |
| # disable this thread. | |
| count = thread.GetStopReasonDataCount() | |
| bid = 0 | |
| tid = 0 | |
| for i in range(count): | |
| id = thread.GetStopReasonDataAtIndex(i) | |
| bp = target.FindBreakpointByID(id) | |
| if bp.IsValid(): | |
| if bp.IsEnabled() == True: | |
| bid = bp.GetID() | |
| tid = bp.GetThreadID() | |
| bp.SetEnabled(False) | |
| # print " disabled [", str(bp.GetThreadID()), ":", str(bp.GetID()), "]" | |
| else: | |
| bp_loc = bp.FindLocationByID(thread.GetStopReasonDataAtIndex(i + 1)) | |
| if bp_loc.IsValid(): | |
| bid = bp_loc.GetBreakPoint().GetID() | |
| tid = bp_loc.ThreadGetID() | |
| bp_loc.SetEnabled(False) | |
| # print " disabled [", str(bp.GetThreadID()), ":", str(bp.GetID()), "]" | |
| # print_vars - Print variable values in output file. | |
| def print_vars(tag, vars, fname, line, file, frame, target, thread): | |
| bid = 0 | |
| tid = 0 | |
| count = thread.GetStopReasonDataCount() | |
| # print "count = ",count | |
| for i in range(count): | |
| # print "i =", i | |
| id = thread.GetStopReasonDataAtIndex(i) | |
| bp = target.FindBreakpointByID(id) | |
| if bp.IsValid(): | |
| bid = bp.GetID() | |
| tid = bp.GetThreadID() | |
| # print "bp is valid", bid, tid | |
| for j in range(vars.GetSize()): | |
| v = vars.GetValueAtIndex(j) | |
| if v.GetName() is not None: | |
| file.write(tag) | |
| file.write(fname) | |
| file.write(":") | |
| file.write(str(line)) | |
| file.write(" ") | |
| file.write(str(tid)) | |
| file.write(":") | |
| file.write(str(bid)) | |
| file.write(" ") | |
| file.write(v.GetName()) | |
| file.write(" ") | |
| AlreadyPrintedValues.clear() | |
| print_var_value(v, file, frame) | |
| file.write("\n") | |
| # set_breakpoints_old - set breakpoints as listed in input file. | |
| def set_breakpoints_old(target, breakpoint_filename, file): | |
| f = open(breakpoint_filename, "r") | |
| lines = f.readlines() | |
| for l in range(len(lines)): | |
| c = lines[l].split() | |
| # print "setting break point - ", c | |
| bp = target.BreakpointCreateByLocation(str(c[0]), int(c[1])) | |
| file.write("#Breakpoint ") | |
| file.write(str(c[0])) | |
| file.write(":") | |
| file.write(str(c[1])) | |
| file.write(" ") | |
| file.write(str(bp.GetThreadID())) | |
| file.write(":") | |
| file.write(str(bp.GetID())) | |
| file.write("\n") | |
| f.close() | |
| # stopeed_at_breakpoint - Return True if process is stopeed at a | |
| # set_breakpoints - set breakpoints as listed in input file. | |
| def set_breakpoints(target, breakpoint_filename, file): | |
| f = open(breakpoint_filename, "r") | |
| lines = f.readlines() | |
| for l in range(len(lines)): | |
| l2 = len(lines[l]) | |
| l3 = l2 - 1 | |
| # print "setting break point - ", lines[l][0:l3] | |
| bp = target.BreakpointCreateByName(str(lines[l][0:l3])) | |
| # print "setting break point - ", lines[l][0:l3], | |
| # print " [", str(bp.GetThreadID()), ":", str(bp.GetID()), "]" | |
| file.write("#Breakpoint ") | |
| file.write(str(1)) | |
| file.write(":") | |
| file.write(str(2)) | |
| file.write(" ") | |
| file.write(str(bp.GetThreadID())) | |
| file.write(":") | |
| file.write(str(bp.GetID())) | |
| file.write(" ") | |
| file.write(str(lines[l][0:l3])) | |
| file.write("\n") | |
| f.close() | |
| # stopeed_at_breakpoint - Return True if process is stopeed at a | |
| # breakpoint. | |
| def stopped_at_breakpoint(process): | |
| # print "stopped" | |
| if process.IsValid(): | |
| # print "stopped process" | |
| state = process.GetState() | |
| # print "stopped process", state | |
| if state == lldb.eStateStopped: | |
| # print "stopped process state is stopped" | |
| thread = process.GetThreadAtIndex(0) | |
| if thread.IsValid(): | |
| # print "thread is valid" | |
| if thread.GetStopReason() == lldb.eStopReasonBreakpoint: | |
| # print "thread stopped at breakpoint" | |
| return True | |
| return False | |
| # Create a new debugger instance | |
| debugger = lldb.SBDebugger.Create() | |
| # When we step or continue, don't return from the function until the process | |
| # stops. We do this by setting the async mode to false. | |
| debugger.SetAsync(False) | |
| # Create a target from a file and arch | |
| # print "Creating a target for '%s'" % sys.argv[1] | |
| target = debugger.CreateTargetWithFileAndArch(sys.argv[1], lldb.LLDB_ARCH_DEFAULT) | |
| if target.IsValid(): | |
| # print "target is valid" | |
| file = open(str(sys.argv[3]), "w") | |
| set_breakpoints(target, sys.argv[2], file) | |
| # Launch the process. Since we specified synchronous mode, we won't return | |
| # from this function until we hit the breakpoint at main | |
| sberror = lldb.SBError() | |
| process = target.LaunchSimple(None, None, None) | |
| # Make sure the launch went ok | |
| while stopped_at_breakpoint(process): | |
| # print "stopped at a bp" | |
| thread = process.GetThreadAtIndex(0) | |
| # print "num of frames ", thread.GetNumFrames() | |
| frame = thread.GetFrameAtIndex(0) | |
| if not frame.IsValid(): | |
| for fi in range(thread.GetNumFrames()): | |
| # print "checking frame no : ", fi | |
| frame = thread.GetFrameAtIndex(fi) | |
| if frame.IsValid(): | |
| fi = thread.GetNumFrames() | |
| if frame.IsValid(): | |
| # #Print some simple frame info | |
| ##print frame | |
| # print "frame is valid" | |
| function = frame.GetFunction() | |
| if function.IsValid(): | |
| fname = function.GetMangledName() | |
| if fname is None: | |
| fname = function.GetName() | |
| # print "function : ",fname | |
| line = frame.GetLineEntry().GetLine() | |
| vars = frame.GetVariables(1, 0, 0, 0) | |
| print_vars("#Argument ", vars, fname, line, file, frame, target, thread) | |
| # vars = frame.GetVariables(0,1,0,0) | |
| # print_vars ("#Variables ", vars, fname, line, file, frame, target, thread) | |
| disable_bp(thread) | |
| process.Continue() | |
| file.close() | |
| lldb.SBDebugger.Terminate() |