From 17e8631dfb0d5b3e7184fe4f8687dc80751e71fd Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 Apr 2013 13:55:15 +0200 Subject: [PATCH] Debugger: Reorganize python dumper loading - Split off GDB and LLDB specific parts into separate files, - Trigger loading of dumpers.py and qttypes.py from bridge.py - Read start up script at startup, not as part of dumper loading Change-Id: I7941ee535121fa0f43a466e5bb75a18c9bb19764 Reviewed-by: hjk --- share/qtcreator/dumper/bridge.py | 721 ++--------------------- share/qtcreator/dumper/dumper.py | 9 + share/qtcreator/dumper/gbridge.py | 322 ++++++++++ share/qtcreator/dumper/lbridge.py | 306 ++++++++++ src/plugins/debugger/gdb/gdbengine.cpp | 19 +- src/plugins/debugger/lldb/lldbengine.cpp | 3 - 6 files changed, 684 insertions(+), 696 deletions(-) create mode 100644 share/qtcreator/dumper/gbridge.py create mode 100644 share/qtcreator/dumper/lbridge.py diff --git a/share/qtcreator/dumper/bridge.py b/share/qtcreator/dumper/bridge.py index 2de5cdbf986..68eeb71fc55 100644 --- a/share/qtcreator/dumper/bridge.py +++ b/share/qtcreator/dumper/bridge.py @@ -1,5 +1,8 @@ import binascii +import inspect +import os +import traceback cdbLoaded = False lldbLoaded = False @@ -11,14 +14,11 @@ gdbLoaded = False # ####################################################################### -def showException(msg, exType, exValue, exTraceback): - warn("**** CAUGHT EXCEPTION: %s ****" % msg) - try: - import traceback - for line in traceback.format_exception(exType, exValue, exTraceback): - warn("%s" % line) - except: - pass +currentDir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +#print "DIR: %s " % currentDir + +def warn(message): + print "XXX: %s\n" % message.encode("latin1") PointerCode = None ArrayCode = None @@ -46,688 +46,49 @@ TypedefCode = None NamespaceCode = None SimpleValueCode = None # LLDB only +failReasons = [] - -####################################################################### -# # CDB -# -####################################################################### +if False: + try: + import cdb_bridge + cdbLoaded = True -try: - import cdb_bridge - cdbLoaded = True + except: + failReasons.append(traceback.format_exc()) -except: - #warn("LOADING CDB FAILED") - pass - - -####################################################################### -# # GDB -# -####################################################################### - -try: - if cdbLoaded: - raise "Not needed" - - import gdb - gdbLoaded = True - - def warn(message): - print "XXX: %s\n" % message.encode("latin1") - - #warn("LOADING GDB") - - ####################################################################### - # - # Infrastructure - # - ####################################################################### - - def savePrint(output): - try: - print(output) - except: - out = "" - for c in output: - cc = ord(c) - if cc > 127: - out += "\\\\%d" % cc - elif cc < 0: - out += "\\\\%d" % (cc + 256) - else: - out += c - print(out) - - def registerCommand(name, func): - - class Command(gdb.Command): - def __init__(self): - super(Command, self).__init__(name, gdb.COMMAND_OBSCURE) - def invoke(self, args, from_tty): - savePrint(func(args)) - - Command() - - def parseAndEvaluate(exp): - return gdb.parse_and_eval(exp) - - def extractFields(value): - return value.type.fields() - ## Insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=10953: - ##fields = type.fields() - ## Insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=11777: - ##fields = defsype).fields() - ## This seems to work. - ##warn("TYPE 0: %s" % type) - #type = stripTypedefs(type) - #fields = type.fields() - #if len(fields): - # return fields - ##warn("TYPE 1: %s" % type) - ## This fails for arrays. See comment in lookupType. - #type0 = lookupType(str(type)) - #if not type0 is None: - # type = type0 - #if type.code == FunctionCode: - # return [] - ##warn("TYPE 2: %s" % type) - #fields = type.fields() - ##warn("FIELDS: %s" % fields) - #return fields - - def fieldCount(type): - return len(type.fields()) - - def listOfLocals(varList): - frame = gdb.selected_frame() - try: - frame = gdb.selected_frame() - #warn("FRAME %s: " % frame) - except RuntimeError, error: - warn("FRAME NOT ACCESSIBLE: %s" % error) - return [] - except: - warn("FRAME NOT ACCESSIBLE FOR UNKNOWN REASONS") - return [] - - try: - block = frame.block() - #warn("BLOCK: %s " % block) - except RuntimeError, error: - warn("BLOCK IN FRAME NOT ACCESSIBLE: %s" % error) - return items - except: - warn("BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS") - return items - - items = [] - shadowed = {} - while True: - if block is None: - warn("UNEXPECTED 'None' BLOCK") - break - for symbol in block: - name = symbol.print_name - - if name == "__in_chrg": - continue - - # "NotImplementedError: Symbol type not yet supported in - # Python scripts." - #warn("SYMBOL %s (%s): " % (symbol, name)) - if name in shadowed: - level = shadowed[name] - name1 = "%s@%s" % (name, level) - shadowed[name] = level + 1 - else: - name1 = name - shadowed[name] = 1 - #warn("SYMBOL %s (%s, %s)): " % (symbol, name, symbol.name)) - item = LocalItem() - item.iname = "local." + name1 - item.name = name1 - try: - item.value = frame.read_var(name, block) - #warn("READ 1: %s" % item.value) - if not item.value.is_optimized_out: - #warn("ITEM 1: %s" % item.value) - items.append(item) - continue - except: - pass - - try: - item.value = frame.read_var(name) - #warn("READ 2: %s" % item.value) - if not item.value.is_optimized_out: - #warn("ITEM 2: %s" % item.value) - items.append(item) - continue - except: - # RuntimeError: happens for - # void foo() { std::string s; std::wstring w; } - # ValueError: happens for (as of 2010/11/4) - # a local struct as found e.g. in - # gcc sources in gcc.c, int execute() - pass - - try: - #warn("READ 3: %s %s" % (name, item.value)) - item.value = gdb.parse_and_eval(name) - #warn("ITEM 3: %s" % item.value) - items.append(item) - except: - # Can happen in inlined code (see last line of - # RowPainter::paintChars(): "RuntimeError: - # No symbol \"__val\" in current context.\n" - pass - - # The outermost block in a function has the function member - # FIXME: check whether this is guaranteed. - if not block.function is None: - break - - block = block.superblock - - return items +if not cdbLoaded: + try: + import gdb + gdbLoaded = True + execfile(os.path.join(currentDir, "gbridge.py")) + except: + failReasons.append(traceback.format_exc()) - def catchCliOutput(command): - try: - return gdb.execute(command, to_string=True).split("\n") - except: - pass - filename = createTempFile() - gdb.execute("set logging off") -# gdb.execute("set logging redirect off") - gdb.execute("set logging file %s" % filename) -# gdb.execute("set logging redirect on") - gdb.execute("set logging on") - msg = "" - try: - gdb.execute(command) - except RuntimeError, error: - # For the first phase of core file loading this yield - # "No symbol table is loaded. Use the \"file\" command." - msg = str(error) - except: - msg = "Unknown error" - gdb.execute("set logging off") -# gdb.execute("set logging redirect off") - if len(msg): - # Having that might confuse result handlers in the gdbengine. - #warn("CLI ERROR: %s " % msg) - removeTempFile(filename) - return "CLI ERROR: %s " % msg - temp = open(filename, "r") - lines = [] - for line in temp: - lines.append(line) - temp.close() - removeTempFile(filename) - return lines - - def selectedInferior(): - try: - # Does not exist in 7.3. - return gdb.selected_inferior() - except: - pass - # gdb.Inferior is new in gdb 7.2 - return gdb.inferiors()[0] - - def readRawMemory(base, size): - try: - inferior = selectedInferior() - return binascii.hexlify(inferior.read_memory(base, size)) - except: - pass - s = "" - t = lookupType("unsigned char").pointer() - base = base.cast(t) - for i in xrange(size): - s += "%02x" % int(base.dereference()) - base += 1 - return s - - - ####################################################################### - # - # Types - # - ####################################################################### - - PointerCode = gdb.TYPE_CODE_PTR - ArrayCode = gdb.TYPE_CODE_ARRAY - StructCode = gdb.TYPE_CODE_STRUCT - UnionCode = gdb.TYPE_CODE_UNION - EnumCode = gdb.TYPE_CODE_ENUM - FlagsCode = gdb.TYPE_CODE_FLAGS - FunctionCode = gdb.TYPE_CODE_FUNC - IntCode = gdb.TYPE_CODE_INT - FloatCode = gdb.TYPE_CODE_FLT # Parts of GDB assume that this means complex. - VoidCode = gdb.TYPE_CODE_VOID - #SetCode = gdb.TYPE_CODE_SET - RangeCode = gdb.TYPE_CODE_RANGE - StringCode = gdb.TYPE_CODE_STRING - #BitStringCode = gdb.TYPE_CODE_BITSTRING - #ErrorTypeCode = gdb.TYPE_CODE_ERROR - MethodCode = gdb.TYPE_CODE_METHOD - MethodPointerCode = gdb.TYPE_CODE_METHODPTR - MemberPointerCode = gdb.TYPE_CODE_MEMBERPTR - ReferenceCode = gdb.TYPE_CODE_REF - CharCode = gdb.TYPE_CODE_CHAR - BoolCode = gdb.TYPE_CODE_BOOL - ComplexCode = gdb.TYPE_CODE_COMPLEX - TypedefCode = gdb.TYPE_CODE_TYPEDEF - NamespaceCode = gdb.TYPE_CODE_NAMESPACE - #Code = gdb.TYPE_CODE_DECFLOAT # Decimal floating point. - #Code = gdb.TYPE_CODE_MODULE # Fortran - #Code = gdb.TYPE_CODE_INTERNAL_FUNCTION - - ####################################################################### - # - # Step Command - # - ####################################################################### - - def sal(args): - (cmd, addr) = args.split(",") - lines = catchCliOutput("info line *" + addr) - fromAddr = "0x0" - toAddr = "0x0" - for line in lines: - pos0from = line.find(" starts at address") + 19 - pos1from = line.find(" ", pos0from) - pos0to = line.find(" ends at", pos1from) + 9 - pos1to = line.find(" ", pos0to) - if pos1to > 0: - fromAddr = line[pos0from : pos1from] - toAddr = line[pos0to : pos1to] - gdb.execute("maint packet sal%s,%s,%s" % (cmd,fromAddr, toAddr)) - - registerCommand("sal", sal) - - - ####################################################################### - # - # Convenience - # - ####################################################################### - - # Just convienience for 'python print ...' - class PPCommand(gdb.Command): - def __init__(self): - super(PPCommand, self).__init__("pp", gdb.COMMAND_OBSCURE) - def invoke(self, args, from_tty): - print(eval(args)) - - PPCommand() - - # Just convienience for 'python print gdb.parse_and_eval(...)' - class PPPCommand(gdb.Command): - def __init__(self): - super(PPPCommand, self).__init__("ppp", gdb.COMMAND_OBSCURE) - def invoke(self, args, from_tty): - print(gdb.parse_and_eval(args)) - - PPPCommand() - - - def scanStack(p, n): - p = long(p) - r = [] - for i in xrange(n): - f = gdb.parse_and_eval("{void*}%s" % p) - m = gdb.execute("info symbol %s" % f, to_string=True) - if not m.startswith("No symbol matches"): - r.append(m) - p += f.type.sizeof - return r - - class ScanStackCommand(gdb.Command): - def __init__(self): - super(ScanStackCommand, self).__init__("scanStack", gdb.COMMAND_OBSCURE) - def invoke(self, args, from_tty): - if len(args) == 0: - args = 20 - savePrint(scanStack(gdb.parse_and_eval("$sp"), int(args))) - - ScanStackCommand() - - -except: - #warn("LOADING GDB FAILED") - pass - - -####################################################################### -# # LLDB -# -####################################################################### +if not gdbLoaded and not cdbLoaded: + try: + execfile(os.path.join(currentDir, "lbridge.py")) + lldbLoaded = True + except: + failReasons.append(traceback.format_exc()) + + +# One is sufficient. +if cdbLoaded or gdbLoaded or lldbLoaded: + failReasons = [] try: - if gdbLoaded or cdbLoaded: - raise "Not needed" - - lldbLoaded = True - - def warn(message): - print "XXX: %s\n" % message.encode("latin1") - - #warn("LOADING LLDB") - - # Data members - SimpleValueCode, \ - StructCode, \ - PointerCode \ - = range(3) - - # Breakpoints. Keep synchronized with BreakpointType in breakpoint.h - UnknownType = 0 - BreakpointByFileAndLine = 1 - BreakpointByFunction = 2 - BreakpointByAddress = 3 - BreakpointAtThrow = 4 - BreakpointAtCatch = 5 - BreakpointAtMain = 6 - BreakpointAtFork = 7 - BreakpointAtExec = 8 - BreakpointAtSysCall = 10 - WatchpointAtAddress = 11 - WatchpointAtExpression = 12 - BreakpointOnQmlSignalEmit = 13 - BreakpointAtJavaScriptThrow = 14 - - - import json - - def dumpJson(stuff): - warn("%s" % json.dumps(stuff, sort_keys=True, indent=4, separators=(',', ': '))) - - def registerCommand(name, func): - pass - - class Type: - def __init__(self, var): - self.raw = var - if var.num_children == 0: - self.code = SimpleValueCode - else: - self.code = StructCode - self.value_type = var.value_type - - def __str__(self): - #try: - return self.raw.type.name - #except: - # return "" - - def fieldCount(self): - return self.raw.num_children - - def unqualified(self): - return self - - class Value: - def __init__(self, var): - self.raw = var - self.is_optimized_out = False - self.address = var.addr - self.type = Type(var) - self.name = var.name - - def __str__(self): - return str(self.raw.value) - - def fields(self): - return [Value(self.raw.GetChildAtIndex(i)) for i in range(self.raw.num_children)] - - currentThread = None - currentFrame = None - - def listOfLocals(varList): - global currentThread - global currentFrame - - items = [] - currentThread = lldb.process.GetThreadAtIndex(0) - currentFrame = currentThread.GetFrameAtIndex(0) - for var in currentFrame.variables: - item = LocalItem() - item.iname = "local." + var.name - item.name = var.name - item.value = Value(var) - items.append(item) - return items - - def extractFields(value): - return value.fields() - - def fieldCount(type): - return type.fieldCount(); - - def threadsData(options): - result = "threads={threads=[" - for thread in lldb.process.threads: - result += "{id=\"%d\"" % thread.id - result += ",target-id=\"%s\"" % thread.id - result += ",index=\"%s\"" % thread.idx - result += ",stop-reason=\"%s\"" % thread.stop_reason - - if thread.IsSuspended(): - result += ",state=\"stopped\"" - else: - result += ",state=\"running\"" - - if not thread.name is None: - result += ",name=\"%s\"" % thread.name - - result += ",frame={" - frame = thread.GetFrameAtIndex(0) - result += "pc=\"%s\"" % frame.pc - result += ",addr=\"%s\"" % frame.pc - result += ",fp=\"%s\"" % frame.fp - result += ",func=\"%s\"" % frame.function.name - result += ",line=\"%s\"" % frame.line_entry.line - result += ",fullname=\"%s\"" % frame.line_entry.file - result += ",file=\"%s\"" % frame.line_entry.file - result += "}}," - - result += "],current-thread-id=\"%s\"}" % lldb.process.selected_thread.id - return result - - def stackData(options): - try: - thread = lldb.process.GetThreadById(options["threadid"]) - except: - thread = lldb.process.GetThreadAtIndex(0) - result = "stack={frames=[" - for frame in thread.frames: - result += "{pc=\"%s\"" % frame.pc - result += ",level=\"%d\"" % frame.idx - result += ",addr=\"%s\"" % frame.pc - result += ",fp=\"%s\"" % frame.fp - result += ",func=\"%s\"" % frame.function.name - result += ",line=\"%s\"" % frame.line_entry.line - result += ",fullname=\"%s\"" % frame.line_entry.file - result += ",usable=\"1\"" - result += ",file=\"%s\"}," % frame.line_entry.file - - hasmore = "0" - result += "],hasmore=\"%s\"}, " % hasmore - return result - - def parseOptions(optionstring): - options = {} - for opt in optionstring.split(","): - try: - key, value = opt.split(":") - options[key] = value - except: - pass - return options - - def updateData(parts, localsOptions, stackOptions, threadOptions): - result = ""; - if parts & 1: - result += bb(localsOptions) + "," - if parts & 2: - result += stackData(parseOptions(stackOptions)) - if parts & 4: - result += threadsData(parseOptions(threadOptions)) - return result - - def listModules(): - result = "modules={" - for module in lldb.target.modules: - result += "{file=\"%s\"" % module.file.fullpath - result += ",name=\"%s\"" % module.file.basename - #result += ",addrsize=\"%s\"" % module.addr_size - #result += ",triple=\"%s\"" % module.triple - #result += ",sections={" - #for section in module.sections: - # result += "[name=\"%s\"" % section.name - # result += ",addr=\"%s\"" % section.addr - # result += ",size=\"%s\"]," % section.size - #result += "}" - result += "}," - result += "]" - return result - - - def breakpoint_function_wrapper(baton, process, frame, bp_loc): - result = "*stopped" - result += ",line=\"%s\"" % frame.line_entry.line - result += ",file=\"%s\"" % frame.line_entry.file - warn("WRAPPER: %s " %result) - return result - - def initLldb(): - pass - - def dumpBreakpoint(bp, modelId): - cond = bp.GetCondition() - result = "{lldbid=\"%s\"" % bp.GetID() - result += ",modelid=\"%s\"" % modelId - result += ",hitcount=\"%s\"" % bp.GetHitCount() - result += ",threadid=\"%s\"" % bp.GetThreadID() - result += ",oneshot=\"%s\"" % (1 if bp.IsOneShot() else 0) - result += ",enabled=\"%s\"" % (1 if bp.IsEnabled() else 0) - result += ",valid=\"%s\"" % (1 if bp.IsValid() else 0) - result += ",condition=\"%s\"" % ("" if cond is None else cond) - result += ",ignorecount=\"%s\"" % bp.GetIgnoreCount() - result += ",locations=[" - for i in range(bp.GetNumLocations()): - loc = bp.GetLocationAtIndex(i) - addr = loc.GetAddress() - result += "{locid=\"%s\"" % loc.GetID() - result += ",func=\"%s\"" % addr.GetFunction().GetName() - result += ",enabled=\"%s\"" % (1 if loc.IsEnabled() else 0) - result += ",resolved=\"%s\"" % (1 if loc.IsResolved() else 0) - result += ",valid=\"%s\"" % (1 if loc.IsValid() else 0) - result += ",ignorecount=\"%s\"" % loc.GetIgnoreCount() - result += ",addr=\"%s\"}," % loc.GetLoadAddress() - result += "]}," - return result - - def onBreak(): - lldb.debugger.HandleCommand("settings set frame-format ''") - lldb.debugger.HandleCommand("settings set thread-format ''") - result = "*stopped,frame={....}" - print result - - def handleBreakpoints(stuff): - todo = json.loads(stuff) - #dumpJson(todo) - #target = lldb.debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT) - target = lldb.debugger.GetTargetAtIndex(0) - #target = lldb.target - - result = "bkpts={added=[" - - for bp in todo["add"]: - bpType = bp["type"] - if bpType == BreakpointByFileAndLine: - bpNew = target.BreakpointCreateByLocation(str(bp["file"]), int(bp["line"])) - elif bpType == BreakpointByFunction: - bpNew = target.BreakpointCreateByName(bp["function"]) - elif bpType == BreakpointAtMain: - bpNew = target.BreakpointCreateByName("main", target.GetExecutable().GetFilename()) - bpNew.SetIgnoreCount(int(bp["ignorecount"])) - bpNew.SetCondition(str(bp["condition"])) - bpNew.SetEnabled(int(bp["enabled"])) - bpNew.SetOneShot(int(bp["oneshot"])) - #bpNew.SetCallback(breakpoint_function_wrapper, None) - #bpNew.SetCallback(breakpoint_function_wrapper, None) - #"breakpoint command add 1 -o \"import time; print time.asctime()\" - #cmd = "script print(11111111)" - cmd = "continue" - lldb.debugger.HandleCommand( - "breakpoint command add -o 'script onBreak()' %s" % bpNew.GetID()) - - result += dumpBreakpoint(bpNew, bp["modelid"]) - - result += "],changed=[" - - for bp in todo["change"]: - bpChange = target.FindBreakpointByID(int(bp["lldbid"])) - bpChange.SetIgnoreCount(int(bp["ignorecount"])) - bpChange.SetCondition(str(bp["condition"])) - bpChange.SetEnabled(int(bp["enabled"])) - bpChange.SetOneShot(int(bp["oneshot"])) - result += dumpBreakpoint(bpChange, bp["modelid"]) - - result += "],removed=[" - - for bp in todo["remove"]: - bpDead = target.BreakpointDelete(int(bp["lldbid"])) - result += "{modelid=\"%s\"}" % bp["modelid"] - - result += "]}" - return result - - def doStepOver(): - lldb.debugger.SetAsync(False) - lldb.thread.StepOver() - lldb.debugger.SetAsync(True) - result = "result={" - result += "}," - result += stackData({'threadid': lldb.process.selected_thread.id}) - result += threadsData({}) - return result - - def doInterrupt(): - lldb.debugger.SetAsync(False) - lldb.process.Stop() - lldb.debugger.SetAsync(True) - result = "result={" - result += "}" - return result - + execfile(os.path.join(currentDir, "dumper.py")) + execfile(os.path.join(currentDir, "qttypes.py")) + bbsetup() except: - #warn("LOADING LLDB FAILED") - pass - -#lldb.debugger.HandleCommand('command script add -f ls.ls ls') - -# -#SBEvent data; -#while (!stop) { -#if (self->m_listener.WaitForEvent(UINT32_MAX, data)) { -# if (data.getType() == SBProcess::eBroadcastBitStateChanged && -#m_process.GetStateFromEvent (data) == eStateStopped) { -# SBThread th = m_process.GetSelectedThread(); -# if (th.GetStopReason() == eStopReasonBreakpoint) { -# // th.GetStopReasonDataAtIndex(0) should have the breakpoint id -# } -# } -#} -#} + failReasons.append(traceback.format_exc()) + + +if len(failReasons): + print "CANNOT ACCESS ANY DEBUGGER BACKEND:\n %s" % "\n".join(failReasons) diff --git a/share/qtcreator/dumper/dumper.py b/share/qtcreator/dumper/dumper.py index 9852a3b7b99..038da6af673 100644 --- a/share/qtcreator/dumper/dumper.py +++ b/share/qtcreator/dumper/dumper.py @@ -45,6 +45,15 @@ def removeTempFile(name): except: pass +def showException(msg, exType, exValue, exTraceback): + warn("**** CAUGHT EXCEPTION: %s ****" % msg) + try: + import traceback + for line in traceback.format_exception(exType, exValue, exTraceback): + warn("%s" % line) + except: + pass + verbosity = 0 verbosity = 1 diff --git a/share/qtcreator/dumper/gbridge.py b/share/qtcreator/dumper/gbridge.py new file mode 100644 index 00000000000..6e5ee188c19 --- /dev/null +++ b/share/qtcreator/dumper/gbridge.py @@ -0,0 +1,322 @@ +def warn(message): + print "XXX: %s\n" % message.encode("latin1") + +####################################################################### +# +# Infrastructure +# +####################################################################### + +def savePrint(output): + try: + print(output) + except: + out = "" + for c in output: + cc = ord(c) + if cc > 127: + out += "\\\\%d" % cc + elif cc < 0: + out += "\\\\%d" % (cc + 256) + else: + out += c + print(out) + +def registerCommand(name, func): + + class Command(gdb.Command): + def __init__(self): + super(Command, self).__init__(name, gdb.COMMAND_OBSCURE) + def invoke(self, args, from_tty): + savePrint(func(args)) + + Command() + +def parseAndEvaluate(exp): + return gdb.parse_and_eval(exp) + +def extractFields(value): + return value.type.fields() + ## Insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=10953: + ##fields = type.fields() + ## Insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=11777: + ##fields = defsype).fields() + ## This seems to work. + ##warn("TYPE 0: %s" % type) + #type = stripTypedefs(type) + #fields = type.fields() + #if len(fields): + # return fields + ##warn("TYPE 1: %s" % type) + ## This fails for arrays. See comment in lookupType. + #type0 = lookupType(str(type)) + #if not type0 is None: + # type = type0 + #if type.code == FunctionCode: + # return [] + ##warn("TYPE 2: %s" % type) + #fields = type.fields() + ##warn("FIELDS: %s" % fields) + #return fields + +def fieldCount(type): + return len(type.fields()) + +def listOfLocals(varList): + frame = gdb.selected_frame() + try: + frame = gdb.selected_frame() + #warn("FRAME %s: " % frame) + except RuntimeError, error: + warn("FRAME NOT ACCESSIBLE: %s" % error) + return [] + except: + warn("FRAME NOT ACCESSIBLE FOR UNKNOWN REASONS") + return [] + + try: + block = frame.block() + #warn("BLOCK: %s " % block) + except RuntimeError, error: + warn("BLOCK IN FRAME NOT ACCESSIBLE: %s" % error) + return items + except: + warn("BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS") + return items + + items = [] + shadowed = {} + while True: + if block is None: + warn("UNEXPECTED 'None' BLOCK") + break + for symbol in block: + name = symbol.print_name + + if name == "__in_chrg": + continue + + # "NotImplementedError: Symbol type not yet supported in + # Python scripts." + #warn("SYMBOL %s (%s): " % (symbol, name)) + if name in shadowed: + level = shadowed[name] + name1 = "%s@%s" % (name, level) + shadowed[name] = level + 1 + else: + name1 = name + shadowed[name] = 1 + #warn("SYMBOL %s (%s, %s)): " % (symbol, name, symbol.name)) + item = LocalItem() + item.iname = "local." + name1 + item.name = name1 + try: + item.value = frame.read_var(name, block) + #warn("READ 1: %s" % item.value) + if not item.value.is_optimized_out: + #warn("ITEM 1: %s" % item.value) + items.append(item) + continue + except: + pass + + try: + item.value = frame.read_var(name) + #warn("READ 2: %s" % item.value) + if not item.value.is_optimized_out: + #warn("ITEM 2: %s" % item.value) + items.append(item) + continue + except: + # RuntimeError: happens for + # void foo() { std::string s; std::wstring w; } + # ValueError: happens for (as of 2010/11/4) + # a local struct as found e.g. in + # gcc sources in gcc.c, int execute() + pass + + try: + #warn("READ 3: %s %s" % (name, item.value)) + item.value = gdb.parse_and_eval(name) + #warn("ITEM 3: %s" % item.value) + items.append(item) + except: + # Can happen in inlined code (see last line of + # RowPainter::paintChars(): "RuntimeError: + # No symbol \"__val\" in current context.\n" + pass + + # The outermost block in a function has the function member + # FIXME: check whether this is guaranteed. + if not block.function is None: + break + + block = block.superblock + + return items + + +def catchCliOutput(command): + try: + return gdb.execute(command, to_string=True).split("\n") + except: + pass + filename = createTempFile() + gdb.execute("set logging off") +# gdb.execute("set logging redirect off") + gdb.execute("set logging file %s" % filename) +# gdb.execute("set logging redirect on") + gdb.execute("set logging on") + msg = "" + try: + gdb.execute(command) + except RuntimeError, error: + # For the first phase of core file loading this yield + # "No symbol table is loaded. Use the \"file\" command." + msg = str(error) + except: + msg = "Unknown error" + gdb.execute("set logging off") +# gdb.execute("set logging redirect off") + if len(msg): + # Having that might confuse result handlers in the gdbengine. + #warn("CLI ERROR: %s " % msg) + removeTempFile(filename) + return "CLI ERROR: %s " % msg + temp = open(filename, "r") + lines = [] + for line in temp: + lines.append(line) + temp.close() + removeTempFile(filename) + return lines + +def selectedInferior(): + try: + # Does not exist in 7.3. + return gdb.selected_inferior() + except: + pass + # gdb.Inferior is new in gdb 7.2 + return gdb.inferiors()[0] + +def readRawMemory(base, size): + try: + inferior = selectedInferior() + return binascii.hexlify(inferior.read_memory(base, size)) + except: + pass + s = "" + t = lookupType("unsigned char").pointer() + base = base.cast(t) + for i in xrange(size): + s += "%02x" % int(base.dereference()) + base += 1 + return s + + +####################################################################### +# +# Types +# +####################################################################### + +PointerCode = gdb.TYPE_CODE_PTR +ArrayCode = gdb.TYPE_CODE_ARRAY +StructCode = gdb.TYPE_CODE_STRUCT +UnionCode = gdb.TYPE_CODE_UNION +EnumCode = gdb.TYPE_CODE_ENUM +FlagsCode = gdb.TYPE_CODE_FLAGS +FunctionCode = gdb.TYPE_CODE_FUNC +IntCode = gdb.TYPE_CODE_INT +FloatCode = gdb.TYPE_CODE_FLT # Parts of GDB assume that this means complex. +VoidCode = gdb.TYPE_CODE_VOID +#SetCode = gdb.TYPE_CODE_SET +RangeCode = gdb.TYPE_CODE_RANGE +StringCode = gdb.TYPE_CODE_STRING +#BitStringCode = gdb.TYPE_CODE_BITSTRING +#ErrorTypeCode = gdb.TYPE_CODE_ERROR +MethodCode = gdb.TYPE_CODE_METHOD +MethodPointerCode = gdb.TYPE_CODE_METHODPTR +MemberPointerCode = gdb.TYPE_CODE_MEMBERPTR +ReferenceCode = gdb.TYPE_CODE_REF +CharCode = gdb.TYPE_CODE_CHAR +BoolCode = gdb.TYPE_CODE_BOOL +ComplexCode = gdb.TYPE_CODE_COMPLEX +TypedefCode = gdb.TYPE_CODE_TYPEDEF +NamespaceCode = gdb.TYPE_CODE_NAMESPACE +#Code = gdb.TYPE_CODE_DECFLOAT # Decimal floating point. +#Code = gdb.TYPE_CODE_MODULE # Fortran +#Code = gdb.TYPE_CODE_INTERNAL_FUNCTION + + +####################################################################### +# +# Step Command +# +####################################################################### + +def sal(args): + (cmd, addr) = args.split(",") + lines = catchCliOutput("info line *" + addr) + fromAddr = "0x0" + toAddr = "0x0" + for line in lines: + pos0from = line.find(" starts at address") + 19 + pos1from = line.find(" ", pos0from) + pos0to = line.find(" ends at", pos1from) + 9 + pos1to = line.find(" ", pos0to) + if pos1to > 0: + fromAddr = line[pos0from : pos1from] + toAddr = line[pos0to : pos1to] + gdb.execute("maint packet sal%s,%s,%s" % (cmd,fromAddr, toAddr)) + +registerCommand("sal", sal) + + +####################################################################### +# +# Convenience +# +####################################################################### + +# Just convienience for 'python print ...' +class PPCommand(gdb.Command): + def __init__(self): + super(PPCommand, self).__init__("pp", gdb.COMMAND_OBSCURE) + def invoke(self, args, from_tty): + print(eval(args)) + +PPCommand() + +# Just convienience for 'python print gdb.parse_and_eval(...)' +class PPPCommand(gdb.Command): + def __init__(self): + super(PPPCommand, self).__init__("ppp", gdb.COMMAND_OBSCURE) + def invoke(self, args, from_tty): + print(gdb.parse_and_eval(args)) + +PPPCommand() + + +def scanStack(p, n): + p = long(p) + r = [] + for i in xrange(n): + f = gdb.parse_and_eval("{void*}%s" % p) + m = gdb.execute("info symbol %s" % f, to_string=True) + if not m.startswith("No symbol matches"): + r.append(m) + p += f.type.sizeof + return r + +class ScanStackCommand(gdb.Command): + def __init__(self): + super(ScanStackCommand, self).__init__("scanStack", gdb.COMMAND_OBSCURE) + def invoke(self, args, from_tty): + if len(args) == 0: + args = 20 + savePrint(scanStack(gdb.parse_and_eval("$sp"), int(args))) + +ScanStackCommand() + diff --git a/share/qtcreator/dumper/lbridge.py b/share/qtcreator/dumper/lbridge.py new file mode 100644 index 00000000000..90935636565 --- /dev/null +++ b/share/qtcreator/dumper/lbridge.py @@ -0,0 +1,306 @@ +import json + + +#warn("LOADING LLDB") + +# Data members +SimpleValueCode, \ +StructCode, \ +PointerCode \ + = range(3) + +# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h +UnknownType = 0 +BreakpointByFileAndLine = 1 +BreakpointByFunction = 2 +BreakpointByAddress = 3 +BreakpointAtThrow = 4 +BreakpointAtCatch = 5 +BreakpointAtMain = 6 +BreakpointAtFork = 7 +BreakpointAtExec = 8 +BreakpointAtSysCall = 10 +WatchpointAtAddress = 11 +WatchpointAtExpression = 12 +BreakpointOnQmlSignalEmit = 13 +BreakpointAtJavaScriptThrow = 14 + + +def dumpJson(stuff): + warn("%s" % json.dumps(stuff, sort_keys=True, indent=4, separators=(',', ': '))) + +def registerCommand(name, func): + pass + +class Type: + def __init__(self, var): + self.raw = var + if var.num_children == 0: + self.code = SimpleValueCode + else: + self.code = StructCode + self.value_type = var.value_type + + def __str__(self): + #try: + return self.raw.type.name + #except: + # return "" + + def fieldCount(self): + return self.raw.num_children + + def unqualified(self): + return self + +class Value: + def __init__(self, var): + self.raw = var + self.is_optimized_out = False + self.address = var.addr + self.type = Type(var) + self.name = var.name + + def __str__(self): + return str(self.raw.value) + + def fields(self): + return [Value(self.raw.GetChildAtIndex(i)) for i in range(self.raw.num_children)] + +currentThread = None +currentFrame = None + +def listOfLocals(varList): + global currentThread + global currentFrame + + items = [] + currentThread = lldb.process.GetThreadAtIndex(0) + currentFrame = currentThread.GetFrameAtIndex(0) + for var in currentFrame.variables: + item = LocalItem() + item.iname = "local." + var.name + item.name = var.name + item.value = Value(var) + items.append(item) + return items + +def extractFields(value): + return value.fields() + +def fieldCount(type): + return type.fieldCount(); + +def threadsData(options): + result = "threads={threads=[" + for thread in lldb.process.threads: + result += "{id=\"%d\"" % thread.id + result += ",target-id=\"%s\"" % thread.id + result += ",index=\"%s\"" % thread.idx + result += ",stop-reason=\"%s\"" % thread.stop_reason + + if thread.IsSuspended(): + result += ",state=\"stopped\"" + else: + result += ",state=\"running\"" + + if not thread.name is None: + result += ",name=\"%s\"" % thread.name + + result += ",frame={" + frame = thread.GetFrameAtIndex(0) + result += "pc=\"%s\"" % frame.pc + result += ",addr=\"%s\"" % frame.pc + result += ",fp=\"%s\"" % frame.fp + result += ",func=\"%s\"" % frame.function.name + result += ",line=\"%s\"" % frame.line_entry.line + result += ",fullname=\"%s\"" % frame.line_entry.file + result += ",file=\"%s\"" % frame.line_entry.file + result += "}}," + + result += "],current-thread-id=\"%s\"}" % lldb.process.selected_thread.id + return result + +def stackData(options): + try: + thread = lldb.process.GetThreadById(options["threadid"]) + except: + thread = lldb.process.GetThreadAtIndex(0) + result = "stack={frames=[" + for frame in thread.frames: + result += "{pc=\"%s\"" % frame.pc + result += ",level=\"%d\"" % frame.idx + result += ",addr=\"%s\"" % frame.pc + result += ",fp=\"%s\"" % frame.fp + result += ",func=\"%s\"" % frame.function.name + result += ",line=\"%s\"" % frame.line_entry.line + result += ",fullname=\"%s\"" % frame.line_entry.file + result += ",usable=\"1\"" + result += ",file=\"%s\"}," % frame.line_entry.file + + hasmore = "0" + result += "],hasmore=\"%s\"}, " % hasmore + return result + +def parseOptions(optionstring): + options = {} + for opt in optionstring.split(","): + try: + key, value = opt.split(":") + options[key] = value + except: + pass + return options + +def updateData(parts, localsOptions, stackOptions, threadOptions): + result = ""; + if parts & 1: + result += bb(localsOptions) + "," + if parts & 2: + result += stackData(parseOptions(stackOptions)) + if parts & 4: + result += threadsData(parseOptions(threadOptions)) + return result + +def listModules(): + result = "modules={" + for module in lldb.target.modules: + result += "{file=\"%s\"" % module.file.fullpath + result += ",name=\"%s\"" % module.file.basename + #result += ",addrsize=\"%s\"" % module.addr_size + #result += ",triple=\"%s\"" % module.triple + #result += ",sections={" + #for section in module.sections: + # result += "[name=\"%s\"" % section.name + # result += ",addr=\"%s\"" % section.addr + # result += ",size=\"%s\"]," % section.size + #result += "}" + result += "}," + result += "]" + return result + + +def breakpoint_function_wrapper(baton, process, frame, bp_loc): + result = "*stopped" + result += ",line=\"%s\"" % frame.line_entry.line + result += ",file=\"%s\"" % frame.line_entry.file + warn("WRAPPER: %s " %result) + return result + +def initLldb(): + pass + +def dumpBreakpoint(bp, modelId): + cond = bp.GetCondition() + result = "{lldbid=\"%s\"" % bp.GetID() + result += ",modelid=\"%s\"" % modelId + result += ",hitcount=\"%s\"" % bp.GetHitCount() + result += ",threadid=\"%s\"" % bp.GetThreadID() + result += ",oneshot=\"%s\"" % (1 if bp.IsOneShot() else 0) + result += ",enabled=\"%s\"" % (1 if bp.IsEnabled() else 0) + result += ",valid=\"%s\"" % (1 if bp.IsValid() else 0) + result += ",condition=\"%s\"" % ("" if cond is None else cond) + result += ",ignorecount=\"%s\"" % bp.GetIgnoreCount() + result += ",locations=[" + for i in range(bp.GetNumLocations()): + loc = bp.GetLocationAtIndex(i) + addr = loc.GetAddress() + result += "{locid=\"%s\"" % loc.GetID() + result += ",func=\"%s\"" % addr.GetFunction().GetName() + result += ",enabled=\"%s\"" % (1 if loc.IsEnabled() else 0) + result += ",resolved=\"%s\"" % (1 if loc.IsResolved() else 0) + result += ",valid=\"%s\"" % (1 if loc.IsValid() else 0) + result += ",ignorecount=\"%s\"" % loc.GetIgnoreCount() + result += ",addr=\"%s\"}," % loc.GetLoadAddress() + result += "]}," + return result + +def onBreak(): + lldb.debugger.HandleCommand("settings set frame-format ''") + lldb.debugger.HandleCommand("settings set thread-format ''") + result = "*stopped,frame={....}" + print result + +def handleBreakpoints(stuff): + todo = json.loads(stuff) + #dumpJson(todo) + #target = lldb.debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT) + target = lldb.debugger.GetTargetAtIndex(0) + #target = lldb.target + + result = "bkpts={added=[" + + for bp in todo["add"]: + bpType = bp["type"] + if bpType == BreakpointByFileAndLine: + bpNew = target.BreakpointCreateByLocation(str(bp["file"]), int(bp["line"])) + elif bpType == BreakpointByFunction: + bpNew = target.BreakpointCreateByName(bp["function"]) + elif bpType == BreakpointAtMain: + bpNew = target.BreakpointCreateByName("main", target.GetExecutable().GetFilename()) + bpNew.SetIgnoreCount(int(bp["ignorecount"])) + bpNew.SetCondition(str(bp["condition"])) + bpNew.SetEnabled(int(bp["enabled"])) + bpNew.SetOneShot(int(bp["oneshot"])) + #bpNew.SetCallback(breakpoint_function_wrapper, None) + #bpNew.SetCallback(breakpoint_function_wrapper, None) + #"breakpoint command add 1 -o \"import time; print time.asctime()\" + #cmd = "script print(11111111)" + cmd = "continue" + lldb.debugger.HandleCommand( + "breakpoint command add -o 'script onBreak()' %s" % bpNew.GetID()) + + result += dumpBreakpoint(bpNew, bp["modelid"]) + + result += "],changed=[" + + for bp in todo["change"]: + bpChange = target.FindBreakpointByID(int(bp["lldbid"])) + bpChange.SetIgnoreCount(int(bp["ignorecount"])) + bpChange.SetCondition(str(bp["condition"])) + bpChange.SetEnabled(int(bp["enabled"])) + bpChange.SetOneShot(int(bp["oneshot"])) + result += dumpBreakpoint(bpChange, bp["modelid"]) + + result += "],removed=[" + + for bp in todo["remove"]: + bpDead = target.BreakpointDelete(int(bp["lldbid"])) + result += "{modelid=\"%s\"}" % bp["modelid"] + + result += "]}" + return result + +def doStepOver(): + lldb.debugger.SetAsync(False) + lldb.thread.StepOver() + lldb.debugger.SetAsync(True) + result = "result={" + result += "}," + result += stackData({'threadid': lldb.process.selected_thread.id}) + result += threadsData({}) + return result + +def doInterrupt(): + lldb.debugger.SetAsync(False) + lldb.process.Stop() + lldb.debugger.SetAsync(True) + result = "result={" + result += "}" + return result + +#lldb.debugger.HandleCommand('command script add -f ls.ls ls') + +# +#SBEvent data; +#while (!stop) { +#if (self->m_listener.WaitForEvent(UINT32_MAX, data)) { +# if (data.getType() == SBProcess::eBroadcastBitStateChanged && +#m_process.GetStateFromEvent (data) == eStateStopped) { +# SBThread th = m_process.GetSelectedThread(); +# if (th.GetStopReason() == eStopReasonBreakpoint) { +# // th.GetStopReasonDataAtIndex(0) should have the breakpoint id +# } +# } +#} +#} diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 380777d12cc..8611c61c987 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1840,6 +1840,10 @@ void GdbEngine::handleHasPython(const GdbResponse &response) void GdbEngine::handlePythonSetup(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { + postCommand("python qqStringCutOff = " + + debuggerCore()->action(MaximalStringLength)->value().toByteArray(), + ConsoleCommand|NonCriticalResponse); + m_hasPython = true; GdbMi data; data.fromStringMultiple(response.consoleStreamOutput); @@ -4902,6 +4906,7 @@ void GdbEngine::startGdb(const QStringList &args) void GdbEngine::reportEngineSetupOk(const GdbResponse &response) { + loadInitScript(); Q_UNUSED(response); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); showMessage(_("ENGINE SUCCESSFULLY STARTED")); @@ -4948,19 +4953,7 @@ void GdbEngine::tryLoadPythonDumpers() Core::ICore::resourcePath().toLocal8Bit() + "/dumper/"; postCommand("python execfile('" + dumperSourcePath + "bridge.py')", - ConsoleCommand|NonCriticalResponse); - postCommand("python execfile('" + dumperSourcePath + "dumper.py')", - ConsoleCommand|NonCriticalResponse); - postCommand("python execfile('" + dumperSourcePath + "qttypes.py')", - ConsoleCommand|NonCriticalResponse); - - postCommand("python qqStringCutOff = " - + debuggerCore()->action(MaximalStringLength)->value().toByteArray(), - ConsoleCommand|NonCriticalResponse); - - loadInitScript(); - - postCommand("bbsetup", ConsoleCommand, CB(handlePythonSetup)); + ConsoleCommand, CB(handlePythonSetup)); } void GdbEngine::reloadDebuggingHelpers() diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 06aa88165e0..5044d43c9aa 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -1113,9 +1113,6 @@ void LldbEngine::loadPythonDumpers() Core::ICore::resourcePath().toLocal8Bit() + "/dumper/"; postCommand("script execfile('" + dumperSourcePath + "bridge.py')"); - postCommand("script execfile('" + dumperSourcePath + "dumper.py')"); - postCommand("script execfile('" + dumperSourcePath + "qttypes.py')"); - postCommand("script bbsetup('')"); } bool LldbEngine::hasCapability(unsigned cap) const