void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) { BreakHandler *handler = breakHandler(); BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data()); BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); Breakpoint bp = handler->breakpointById(id); if (!bp.isValid()) bp = handler->findBreakpointByResponseId(rid); BreakpointResponse response = bp.response(); if (added) response.id = rid; QTC_CHECK(response.id == rid); response.address = 0; response.enabled = bkpt["enabled"].toInt(); response.ignoreCount = bkpt["ignorecount"].toInt(); response.condition = QByteArray::fromHex(bkpt["condition"].data()); response.hitCount = bkpt["hitcount"].toInt(); response.fileName = bkpt["file"].toUtf8(); response.lineNumber = bkpt["line"].toInt(); GdbMi locations = bkpt["locations"]; const int numChild = int(locations.children().size()); if (numChild > 1) { foreach (const GdbMi &location, locations.children()) { const int locid = location["locid"].toInt(); BreakpointResponse sub; sub.id = BreakpointResponseId(rid.majorPart(), locid); sub.type = response.type; sub.address = location["addr"].toAddress(); sub.functionName = location["func"].toUtf8(); sub.fileName = location["file"].toUtf8(); sub.lineNumber = location["line"].toInt(); bp.insertSubBreakpoint(sub); } } else if (numChild == 1) {
void TermGdbAdapter::handleEntryPoint(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { GdbMi stack = response.data.findChild("stack"); if (stack.isValid() && stack.childCount() == 1) m_engine->m_entryPoint = stack.childAt(0).findChild("addr").data(); } }
// Helper to retrieve an bool child from GDBMI static inline bool gdbmiChildToBool(const GdbMi &parent, const char *childName, bool *target) { const GdbMi childBA = parent[childName]; if (childBA.isValid()) { *target = childBA.data() == "true"; return true; } return false; }
inline ModelId cdbIdToBreakpointId(const GdbMi &data) { if (data.isValid()) { // Might not be valid if there is not id bool ok; const int id = data.data().toInt(&ok); if (ok) return cdbIdToBreakpointId<ModelId>(id); } return ModelId(); }
void LldbEngine::handleContinuation(const GdbMi &data) { if (data.data() == "updateLocals") { updateLocals(); } else if (data.data() == "updateAll") { updateAll(); } else { QTC_ASSERT(false, qDebug() << "Unknown continuation: " << data.data()); } }
void LldbEngine::handleResponse(const QByteArray &response) { GdbMi all; all.fromStringMultiple(response); foreach (const GdbMi &item, all.children()) { const QByteArray name = item.name(); if (name == "all") { updateLocalsView(item); watchHandler()->notifyUpdateFinished(); } else if (name == "dumpers") { watchHandler()->addDumpers(item); setupInferiorStage2(); } else if (name == "stack") refreshStack(item); else if (name == "registers") refreshRegisters(item); else if (name == "threads") refreshThreads(item); else if (name == "current-thread") refreshCurrentThread(item); else if (name == "typeinfo") refreshTypeInfo(item); else if (name == "state") refreshState(item); else if (name == "location") refreshLocation(item); else if (name == "modules") refreshModules(item); else if (name == "symbols") refreshSymbols(item); else if (name == "breakpoint-added") refreshAddedBreakpoint(item); else if (name == "breakpoint-changed") refreshChangedBreakpoint(item); else if (name == "breakpoint-removed") refreshRemovedBreakpoint(item); else if (name == "output") refreshOutput(item); else if (name == "disassembly") refreshDisassembly(item); else if (name == "memory") refreshMemory(item); else if (name == "full-backtrace") showFullBacktrace(item); else if (name == "continuation") handleContinuation(item); else if (name == "statusmessage") { QString msg = QString::fromUtf8(item.data()); if (msg.size()) msg[0] = msg.at(0).toUpper(); showStatusMessage(msg); } } }
// Helper to retrieve an int child from GDBMI static inline bool gdbmiChildToInt(const GdbMi &parent, const char *childName, int *target) { const GdbMi childBA = parent[childName]; if (childBA.isValid()) { bool ok; const int v = childBA.data().toInt(&ok); if (ok) { *target = v; return true; } } return false; }
void PdbEngine::handleListSymbols(const PdbResponse &response) { GdbMi out; out.fromString(response.data.trimmed()); Symbols symbols; QString moduleName = response.cookie.toString(); foreach (const GdbMi &item, out.children()) { Symbol symbol; symbol.name = _(item.findChild("name").data()); symbols.append(symbol); } debuggerCore()->showModuleSymbols(moduleName, symbols); }
void WatchItem::parse(const GdbMi &data) { iname = data["iname"].data(); GdbMi wname = data["wname"]; if (wname.isValid()) // Happens (only) for watched expressions. name = QString::fromUtf8(QByteArray::fromHex(wname.data())); else name = QString::fromLatin1(data["name"].data()); parseHelper(data); if (wname.isValid()) exp = name.toUtf8(); }
void ThreadsHandler::updateThreads(const GdbMi &data) { // ^done,threads=[{id="1",target-id="Thread 0xb7fdc710 (LWP 4264)", // frame={level="0",addr="0x080530bf",func="testQString",args=[], // file="/.../app.cpp",fullname="/../app.cpp",line="1175"}, // state="stopped",core="0"}],current-thread-id="1" // Emit changed for previous frame. if (m_currentIndex != -1) { dataChanged(m_currentIndex); m_currentIndex = -1; } ThreadId currentId; const GdbMi current = data["current-thread-id"]; if (current.isValid()) currentId = ThreadId(current.data().toLongLong()); const QList<GdbMi> items = data["threads"].children(); const int n = items.size(); for (int index = 0; index != n; ++index) { const GdbMi item = items.at(index); const GdbMi frame = item["frame"]; ThreadData thread; thread.id = ThreadId(item["id"].toInt()); thread.targetId = item["target-id"].toLatin1(); thread.details = item["details"].toLatin1(); thread.core = item["core"].toLatin1(); thread.state = item["state"].toLatin1(); thread.address = frame["addr"].toAddress(); thread.function = frame["func"].toLatin1(); thread.fileName = frame["fullname"].toLatin1(); thread.lineNumber = frame["line"].toInt(); thread.module = QString::fromLocal8Bit(frame["from"].data()); thread.stopped = true; thread.name = item["name"].toLatin1(); if (thread.state == QLatin1String("running")) thread.stopped = false; if (thread.id == currentId) m_currentIndex = index; updateThread(thread); } if (m_currentIndex != -1) dataChanged(m_currentIndex); updateThreadBox(); }
void GdbMi::parseTuple_helper(const char *&from, const char *to) { skipCommas(from, to); //qDebug() << "parseTuple_helper: " << QByteArray(from, to - from); m_type = Tuple; while (from < to) { if (*from == '}') { ++from; break; } GdbMi child; child.parseResultOrValue(from, to); //qDebug() << "\n=======\n" << qPrintable(child.toString()) << "\n========\n"; if (!child.isValid()) return; m_children += child; skipCommas(from, to); } }
void PdbEngine::refreshState(const GdbMi &reportedState) { QByteArray newState = reportedState.data(); if (newState == "stopped") { notifyInferiorSpontaneousStop(); updateAll(); } else if (newState == "inferiorexited") { notifyInferiorExited(); } }
void GdbMi::parseList(const char *&from, const char *to) { //qDebug() << "parseList: " << QByteArray(from, to - from); QTC_CHECK(*from == '['); ++from; m_type = List; skipCommas(from, to); while (from < to) { if (*from == ']') { ++from; break; } GdbMi child; child.parseResultOrValue(from, to); if (child.isValid()) m_children += child; skipCommas(from, to); } }
void StackHandler::setFramesAndCurrentIndex(const GdbMi &frames, bool isFull) { int targetFrame = -1; StackFrames stackFrames; const int n = frames.childCount(); for (int i = 0; i != n; ++i) { stackFrames.append(StackFrame::parseFrame(frames.childAt(i), m_engine->runParameters())); const StackFrame &frame = stackFrames.back(); // Initialize top frame to the first valid frame. const bool isValid = frame.isUsable() && !frame.function.isEmpty(); if (isValid && targetFrame == -1) targetFrame = i; } bool canExpand = !isFull && (n >= action(MaximalStackDepth)->value().toInt()); action(ExpandStack)->setEnabled(canExpand); setFrames(stackFrames, canExpand); // We can't jump to any file if we don't have any frames. if (stackFrames.isEmpty()) return; // targetFrame contains the top most frame for which we have source // information. That's typically the frame we'd like to jump to, with // a few exceptions: // Always jump to frame #0 when stepping by instruction. if (m_engine->operatesByInstruction()) targetFrame = 0; // If there is no frame with source, jump to frame #0. if (targetFrame == -1) targetFrame = 0; setCurrentIndex(targetFrame); }
void PdbEngine::handleListModules(const PdbResponse &response) { GdbMi out; out.fromString(response.data.trimmed()); Modules modules; foreach (const GdbMi &item, out.children()) { Module module; module.moduleName = _(item.findChild("name").data()); QString path = _(item.findChild("value").data()); int pos = path.indexOf(_("' from '")); if (pos != -1) { path = path.mid(pos + 8); if (path.size() >= 2) path.chop(2); } else if (path.startsWith(_("<module '")) && path.endsWith(_("' (built-in)>"))) { path = _("(builtin)"); } module.modulePath = path; modules.append(module); } modulesHandler()->setModules(modules); }
void WinException::fromGdbMI(const GdbMi &gdbmi) { exceptionCode = gdbmi["exceptionCode"].data().toUInt(); exceptionFlags = gdbmi["exceptionFlags"].data().toUInt(); exceptionAddress = gdbmi["exceptionAddress"].data().toULongLong(); firstChance = gdbmi["firstChance"].data() != "0"; const GdbMi ginfo1 = gdbmi["exceptionInformation0"]; if (ginfo1.isValid()) { info1 = ginfo1.data().toULongLong(); const GdbMi ginfo2 = gdbmi["exceptionInformation1"]; if (ginfo2.isValid()) info2 = ginfo1.data().toULongLong(); } const GdbMi gLineNumber = gdbmi["exceptionLine"]; if (gLineNumber.isValid()) { lineNumber = gLineNumber.toInt(); file = gdbmi["exceptionFile"].data(); } function = gdbmi["exceptionFunction"].data(); }
void PdbEngine::refreshModules(const GdbMi &modules) { ModulesHandler *handler = modulesHandler(); handler->beginUpdateAll(); foreach (const GdbMi &item, modules.children()) { Module module; module.moduleName = _(item["name"].data()); QString path = _(item["value"].data()); int pos = path.indexOf(_("' from '")); if (pos != -1) { path = path.mid(pos + 8); if (path.size() >= 2) path.chop(2); } else if (path.startsWith(_("<module '")) && path.endsWith(_("' (built-in)>"))) { path = _("(builtin)"); } module.modulePath = path; handler->updateModule(module); } handler->endUpdateAll(); }
// Parse extension command listing breakpoints. // Note that not all fields are returned, since file, line, function are encoded // in the expression (that is in addition deleted on resolving for a bp-type breakpoint). void parseBreakPoint(const GdbMi &gdbmi, BreakpointResponse *r, QString *expression /* = 0 */) { gdbmiChildToBool(gdbmi, "enabled", &(r->enabled)); gdbmiChildToBool(gdbmi, "deferred", &(r->pending)); r->id = BreakpointResponseId(); const GdbMi idG = gdbmi.findChild("id"); if (idG.isValid()) { // Might not be valid if there is not id bool ok; const int id = idG.data().toInt(&ok); if (ok) r->id = BreakpointResponseId(id); } const GdbMi moduleG = gdbmi.findChild("module"); if (moduleG.isValid()) r->module = QString::fromLocal8Bit(moduleG.data()); if (expression) { const GdbMi expressionG = gdbmi.findChild("expression"); if (expressionG.isValid()) *expression = QString::fromLocal8Bit(expressionG.data()); } const GdbMi addressG = gdbmi.findChild("address"); if (addressG.isValid()) r->address = addressG.data().toULongLong(0, 0); if (gdbmiChildToInt(gdbmi, "passcount", &(r->ignoreCount))) r->ignoreCount--; gdbmiChildToInt(gdbmi, "thread", &(r->threadSpec)); }
Threads ThreadsHandler::parseGdbmiThreads(const GdbMi &data, int *currentThread) { // ^done,threads=[{id="1",target-id="Thread 0xb7fdc710 (LWP 4264)", // frame={level="0",addr="0x080530bf",func="testQString",args=[], // file="/.../app.cpp",fullname="/../app.cpp",line="1175"}, // state="stopped",core="0"}],current-thread-id="1" const QList<GdbMi> items = data.findChild("threads").children(); const int n = items.size(); Threads threads; threads.reserve(n); for (int index = 0; index != n; ++index) { bool ok = false; const GdbMi item = items.at(index); const GdbMi frame = item.findChild("frame"); ThreadData thread; thread.id = item.findChild("id").data().toInt(); thread.targetId = QString::fromLatin1(item.findChild("target-id").data()); thread.core = QString::fromLatin1(item.findChild("core").data()); thread.state = QString::fromLatin1(item.findChild("state").data()); thread.address = frame.findChild("addr").data().toULongLong(&ok, 0); thread.function = QString::fromLatin1(frame.findChild("func").data()); thread.fileName = QString::fromLatin1(frame.findChild("fullname").data()); thread.lineNumber = frame.findChild("line").data().toInt(); thread.module = QString::fromLocal8Bit(frame.findChild("from").data()); // Non-GDB (Cdb2) output name here. thread.name = QString::fromLatin1(frame.findChild("name").data()); threads.append(thread); } if (currentThread) *currentThread = data.findChild("current-thread-id").data().toInt(); return threads; }
void LldbEngine::showFullBacktrace(const GdbMi &data) { Internal::openTextEditor(_("Backtrace $"), QString::fromUtf8(QByteArray::fromHex(data.data()))); }
// Parse extension command listing breakpoints. // Note that not all fields are returned, since file, line, function are encoded // in the expression (that is in addition deleted on resolving for a bp-type breakpoint). void parseBreakPoint(const GdbMi &gdbmi, BreakpointResponse *r, QString *expression /* = 0 */) { gdbmiChildToBool(gdbmi, "enabled", &(r->enabled)); gdbmiChildToBool(gdbmi, "deferred", &(r->pending)); r->id = BreakpointResponseId(); // Might not be valid if there is not id r->id = cdbIdToBreakpointResponseId(gdbmi["id"]); const GdbMi moduleG = gdbmi["module"]; if (moduleG.isValid()) r->module = QString::fromLocal8Bit(moduleG.data()); const GdbMi sourceFileName = gdbmi["srcfile"]; if (sourceFileName.isValid()) { r->fileName = QString::fromLocal8Bit(sourceFileName.data()); const GdbMi lineNumber = gdbmi["srcline"]; if (lineNumber.isValid()) r->lineNumber = lineNumber.data().toULongLong(0, 0); } if (expression) { const GdbMi expressionG = gdbmi["expression"]; if (expressionG.isValid()) *expression = QString::fromLocal8Bit(expressionG.data()); } const GdbMi addressG = gdbmi["address"]; if (addressG.isValid()) r->address = addressG.data().toULongLong(0, 0); if (gdbmiChildToInt(gdbmi, "passcount", &(r->ignoreCount))) r->ignoreCount--; gdbmiChildToInt(gdbmi, "thread", &(r->threadSpec)); }
void WatchItem::parseHelper(const GdbMi &input) { setChildrenUnneeded(); GdbMi mi = input["type"]; if (mi.isValid()) setType(mi.data()); editvalue = input["editvalue"].data(); editformat = DebuggerDisplay(input["editformat"].toInt()); editencoding = DebuggerEncoding(input["editencoding"].data()); mi = input["valueelided"]; if (mi.isValid()) elided = mi.toInt(); mi = input["bitpos"]; if (mi.isValid()) bitpos = mi.toInt(); mi = input["bitsize"]; if (mi.isValid()) bitsize = mi.toInt(); mi = input["origaddr"]; if (mi.isValid()) origaddr = mi.toAddress(); mi = input["address"]; if (mi.isValid()) { address = mi.toAddress(); if (exp.isEmpty()) { if (iname.startsWith("local.") && iname.count('.') == 1) // Solve one common case of adding 'class' in // *(class X*)0xdeadbeef for gdb. exp = name.toLatin1(); else exp = "*(" + gdbQuoteTypes(type) + "*)" + hexAddress(); } } mi = input["value"]; QByteArray enc = input["valueencoded"].data(); if (mi.isValid() || !enc.isEmpty()) { setValue(decodeData(mi.data(), enc)); } else { setValueNeeded(); } mi = input["size"]; if (mi.isValid()) size = mi.toInt(); mi = input["exp"]; if (mi.isValid()) exp = mi.data(); mi = input["valueenabled"]; if (mi.data() == "true") valueEnabled = true; else if (mi.data() == "false") valueEnabled = false; mi = input["valueeditable"]; if (mi.data() == "true") valueEditable = true; else if (mi.data() == "false") valueEditable = false; mi = input["numchild"]; // GDB/MI if (mi.isValid()) setHasChildren(mi.toInt() > 0); mi = input["haschild"]; // native-mixed if (mi.isValid()) setHasChildren(mi.toInt() > 0); mi = input["arraydata"]; if (mi.isValid()) { DebuggerEncoding encoding(input["arrayencoding"].data()); QByteArray childType = input["childtype"].data(); decodeArrayData(this, mi.data(), encoding, childType); } else { const GdbMi children = input["children"]; if (children.isValid()) { bool ok = false; // Try not to repeat data too often. const GdbMi childType = input["childtype"]; const GdbMi childNumChild = input["childnumchild"]; qulonglong addressBase = input["addrbase"].data().toULongLong(&ok, 0); qulonglong addressStep = input["addrstep"].data().toULongLong(&ok, 0); for (int i = 0, n = int(children.children().size()); i != n; ++i) { const GdbMi &subinput = children.children().at(i); WatchItem *child = new WatchItem; if (childType.isValid()) child->setType(childType.data()); if (childNumChild.isValid()) child->setHasChildren(childNumChild.toInt() > 0); GdbMi name = subinput["name"]; QByteArray nn; if (name.isValid()) { nn = name.data(); child->name = QString::fromLatin1(nn); } else { nn.setNum(i); child->name = QString::fromLatin1("[%1]").arg(i); } GdbMi iname = subinput["iname"]; if (iname.isValid()) child->iname = iname.data(); else child->iname = this->iname + '.' + nn; if (addressStep) { child->address = addressBase + i * addressStep; child->exp = "*(" + gdbQuoteTypes(child->type) + "*)" + child->hexAddress(); } QByteArray key = subinput["key"].data(); if (!key.isEmpty()) child->name = decodeData(key, subinput["keyencoded"].data()); child->parseHelper(subinput); appendChild(child); } } } }