forked from qt-creator/qt-creator
Debugger: Add basic breakpoint handling and stepping to LLDB backend
Change-Id: Ib700afa63739e6d26bdd97225265559d7112eadb Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -422,11 +422,34 @@ try:
|
|||||||
|
|
||||||
#warn("LOADING LLDB")
|
#warn("LOADING LLDB")
|
||||||
|
|
||||||
|
# Data members
|
||||||
SimpleValueCode, \
|
SimpleValueCode, \
|
||||||
StructCode, \
|
StructCode, \
|
||||||
PointerCode \
|
PointerCode \
|
||||||
= range(3)
|
= 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):
|
def registerCommand(name, func):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -578,8 +601,133 @@ try:
|
|||||||
return 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
|
||||||
|
|
||||||
except:
|
except:
|
||||||
#warn("LOADING LLDB FAILED")
|
#warn("LOADING LLDB FAILED")
|
||||||
pass
|
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
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
#}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -123,7 +123,8 @@ static QString typeToString(BreakpointType type)
|
|||||||
return BreakHandler::tr("Breakpoint on QML Signal Emit");
|
return BreakHandler::tr("Breakpoint on QML Signal Emit");
|
||||||
case BreakpointAtJavaScriptThrow:
|
case BreakpointAtJavaScriptThrow:
|
||||||
return BreakHandler::tr("Breakpoint at JavaScript throw");
|
return BreakHandler::tr("Breakpoint at JavaScript throw");
|
||||||
case UnknownType:
|
case UnknownBreakpointType:
|
||||||
|
case LastBreakpointType:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return BreakHandler::tr("Unknown Breakpoint Type");
|
return BreakHandler::tr("Unknown Breakpoint Type");
|
||||||
@@ -189,7 +190,7 @@ static bool isSimilarTo(const BreakpointParameters &data, const BreakpointRespon
|
|||||||
{
|
{
|
||||||
// Clear hit.
|
// Clear hit.
|
||||||
// Clear miss.
|
// Clear miss.
|
||||||
if (needle.type != UnknownType && data.type != UnknownType
|
if (needle.type != UnknownBreakpointType && data.type != UnknownBreakpointType
|
||||||
&& data.type != needle.type)
|
&& data.type != needle.type)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -382,7 +383,7 @@ void BreakHandler::loadBreakpoints()
|
|||||||
if (v.isValid())
|
if (v.isValid())
|
||||||
data.tracepoint = bool(v.toInt());
|
data.tracepoint = bool(v.toInt());
|
||||||
v = map.value(_("type"));
|
v = map.value(_("type"));
|
||||||
if (v.isValid() && v.toInt() != UnknownType)
|
if (v.isValid() && v.toInt() != UnknownBreakpointType)
|
||||||
data.type = BreakpointType(v.toInt());
|
data.type = BreakpointType(v.toInt());
|
||||||
v = map.value(_("module"));
|
v = map.value(_("module"));
|
||||||
if (v.isValid())
|
if (v.isValid())
|
||||||
|
@@ -60,6 +60,18 @@ QDebug operator<<(QDebug d, const BreakpointModelId &id)
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BreakpointModelId::BreakpointModelId(const QByteArray &ba)
|
||||||
|
{
|
||||||
|
int pos = ba.indexOf('\'');
|
||||||
|
if (pos == -1) {
|
||||||
|
m_majorPart = ba.toUShort();
|
||||||
|
m_minorPart = 0;
|
||||||
|
} else {
|
||||||
|
m_majorPart = ba.left(pos).toUShort();
|
||||||
|
m_minorPart = ba.mid(pos + 1).toUShort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray BreakpointModelId::toByteArray() const
|
QByteArray BreakpointModelId::toByteArray() const
|
||||||
{
|
{
|
||||||
if (!isValid())
|
if (!isValid())
|
||||||
@@ -239,7 +251,8 @@ bool BreakpointParameters::isValid() const
|
|||||||
break;
|
break;
|
||||||
case WatchpointAtExpression:
|
case WatchpointAtExpression:
|
||||||
return !expression.isEmpty();
|
return !expression.isEmpty();
|
||||||
case UnknownType:
|
case UnknownBreakpointType:
|
||||||
|
case LastBreakpointType:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -315,10 +328,10 @@ QString BreakpointParameters::toString() const
|
|||||||
case BreakpointAtMain:
|
case BreakpointAtMain:
|
||||||
case BreakpointAtFork:
|
case BreakpointAtFork:
|
||||||
case BreakpointAtExec:
|
case BreakpointAtExec:
|
||||||
//case BreakpointAtVFork:
|
|
||||||
case BreakpointAtSysCall:
|
case BreakpointAtSysCall:
|
||||||
case BreakpointAtJavaScriptThrow:
|
case BreakpointAtJavaScriptThrow:
|
||||||
case UnknownType:
|
case UnknownBreakpointType:
|
||||||
|
case LastBreakpointType:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ts << (enabled ? " [enabled]" : " [disabled]");
|
ts << (enabled ? " [enabled]" : " [disabled]");
|
||||||
|
@@ -120,9 +120,11 @@ QDebug operator<<(QDebug d, const BreakpointResponseId &id);
|
|||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//! \enum Debugger::Internal::BreakpointType
|
//! \enum Debugger::Internal::BreakpointType
|
||||||
|
|
||||||
|
// Note: Keep synchronized with similar definitions in bridge.py
|
||||||
enum BreakpointType
|
enum BreakpointType
|
||||||
{
|
{
|
||||||
UnknownType,
|
UnknownBreakpointType,
|
||||||
BreakpointByFileAndLine,
|
BreakpointByFileAndLine,
|
||||||
BreakpointByFunction,
|
BreakpointByFunction,
|
||||||
BreakpointByAddress,
|
BreakpointByAddress,
|
||||||
@@ -131,12 +133,12 @@ enum BreakpointType
|
|||||||
BreakpointAtMain,
|
BreakpointAtMain,
|
||||||
BreakpointAtFork,
|
BreakpointAtFork,
|
||||||
BreakpointAtExec,
|
BreakpointAtExec,
|
||||||
//BreakpointAtVFork,
|
|
||||||
BreakpointAtSysCall,
|
BreakpointAtSysCall,
|
||||||
WatchpointAtAddress,
|
WatchpointAtAddress,
|
||||||
WatchpointAtExpression,
|
WatchpointAtExpression,
|
||||||
BreakpointOnQmlSignalEmit,
|
BreakpointOnQmlSignalEmit,
|
||||||
BreakpointAtJavaScriptThrow
|
BreakpointAtJavaScriptThrow,
|
||||||
|
LastBreakpointType
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \enum Debugger::Internal::BreakpointState
|
//! \enum Debugger::Internal::BreakpointState
|
||||||
@@ -200,7 +202,7 @@ inline void operator|=(BreakpointParts &p, BreakpointParts r)
|
|||||||
class BreakpointParameters
|
class BreakpointParameters
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit BreakpointParameters(BreakpointType = UnknownType);
|
explicit BreakpointParameters(BreakpointType = UnknownBreakpointType);
|
||||||
BreakpointParts differencesTo(const BreakpointParameters &rhs) const;
|
BreakpointParts differencesTo(const BreakpointParameters &rhs) const;
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
bool equals(const BreakpointParameters &rhs) const;
|
bool equals(const BreakpointParameters &rhs) const;
|
||||||
|
@@ -136,7 +136,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent)
|
BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent)
|
||||||
: QDialog(parent), m_enabledParts(~0), m_previousType(UnknownType),
|
: QDialog(parent), m_enabledParts(~0), m_previousType(UnknownBreakpointType),
|
||||||
m_firstTypeChange(true)
|
m_firstTypeChange(true)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Edit Breakpoint Properties"));
|
setWindowTitle(tr("Edit Breakpoint Properties"));
|
||||||
@@ -158,7 +158,8 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent)
|
|||||||
<< tr("Break on data access at address given by expression")
|
<< tr("Break on data access at address given by expression")
|
||||||
<< tr("Break on QML signal emit")
|
<< tr("Break on QML signal emit")
|
||||||
<< tr("Break when JavaScript exception is thrown");
|
<< tr("Break when JavaScript exception is thrown");
|
||||||
QTC_ASSERT(types.size() == BreakpointAtJavaScriptThrow, return);
|
// We don't list UnknownBreakpointType, so 1 less:
|
||||||
|
QTC_CHECK(types.size() + 1 == LastBreakpointType);
|
||||||
m_comboBoxType = new QComboBox(groupBoxBasic);
|
m_comboBoxType = new QComboBox(groupBoxBasic);
|
||||||
m_comboBoxType->setMaxVisibleItems(20);
|
m_comboBoxType->setMaxVisibleItems(20);
|
||||||
m_comboBoxType->addItems(types);
|
m_comboBoxType->addItems(types);
|
||||||
@@ -512,7 +513,8 @@ void BreakpointDialog::typeChanged(int)
|
|||||||
m_previousType = newType;
|
m_previousType = newType;
|
||||||
// Save current state.
|
// Save current state.
|
||||||
switch (previousType) {
|
switch (previousType) {
|
||||||
case UnknownType:
|
case UnknownBreakpointType:
|
||||||
|
case LastBreakpointType:
|
||||||
break;
|
break;
|
||||||
case BreakpointByFileAndLine:
|
case BreakpointByFileAndLine:
|
||||||
getParts(FileAndLinePart|ModulePart|AllConditionParts|TracePointPart, &m_savedParameters);
|
getParts(FileAndLinePart|ModulePart|AllConditionParts|TracePointPart, &m_savedParameters);
|
||||||
@@ -542,7 +544,8 @@ void BreakpointDialog::typeChanged(int)
|
|||||||
|
|
||||||
// Enable and set up new state from saved values.
|
// Enable and set up new state from saved values.
|
||||||
switch (newType) {
|
switch (newType) {
|
||||||
case UnknownType:
|
case UnknownBreakpointType:
|
||||||
|
case LastBreakpointType:
|
||||||
break;
|
break;
|
||||||
case BreakpointByFileAndLine:
|
case BreakpointByFileAndLine:
|
||||||
setParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart, m_savedParameters);
|
setParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart, m_savedParameters);
|
||||||
|
@@ -2586,7 +2586,8 @@ bool CdbEngine::acceptsBreakpoint(BreakpointModelId id) const
|
|||||||
if (!data.isCppBreakpoint())
|
if (!data.isCppBreakpoint())
|
||||||
return false;
|
return false;
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case UnknownType:
|
case UnknownBreakpointType:
|
||||||
|
case LastBreakpointType:
|
||||||
case BreakpointAtFork:
|
case BreakpointAtFork:
|
||||||
case WatchpointAtExpression:
|
case WatchpointAtExpression:
|
||||||
case BreakpointAtSysCall:
|
case BreakpointAtSysCall:
|
||||||
|
@@ -92,7 +92,8 @@ static inline QString cdbBreakPointFileName(const BreakpointParameters &bp,
|
|||||||
static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
|
static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
|
||||||
{
|
{
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
case UnknownType:
|
case UnknownBreakpointType:
|
||||||
|
case LastBreakpointType:
|
||||||
case BreakpointByFileAndLine:
|
case BreakpointByFileAndLine:
|
||||||
case BreakpointByFunction:
|
case BreakpointByFunction:
|
||||||
case BreakpointByAddress:
|
case BreakpointByAddress:
|
||||||
@@ -181,12 +182,13 @@ QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
|
|||||||
case BreakpointAtExec:
|
case BreakpointAtExec:
|
||||||
case WatchpointAtExpression:
|
case WatchpointAtExpression:
|
||||||
case BreakpointAtSysCall:
|
case BreakpointAtSysCall:
|
||||||
case UnknownType:
|
|
||||||
case BreakpointAtCatch:
|
case BreakpointAtCatch:
|
||||||
case BreakpointAtThrow:
|
case BreakpointAtThrow:
|
||||||
case BreakpointAtMain:
|
case BreakpointAtMain:
|
||||||
case BreakpointOnQmlSignalEmit:
|
case BreakpointOnQmlSignalEmit:
|
||||||
case BreakpointAtJavaScriptThrow:
|
case BreakpointAtJavaScriptThrow:
|
||||||
|
case UnknownBreakpointType:
|
||||||
|
case LastBreakpointType:
|
||||||
QTC_ASSERT(false, return QByteArray());
|
QTC_ASSERT(false, return QByteArray());
|
||||||
break;
|
break;
|
||||||
case BreakpointByAddress:
|
case BreakpointByAddress:
|
||||||
|
@@ -2540,7 +2540,7 @@ QByteArray GdbEngine::breakpointLocation(BreakpointModelId id)
|
|||||||
{
|
{
|
||||||
BreakHandler *handler = breakHandler();
|
BreakHandler *handler = breakHandler();
|
||||||
const BreakpointParameters &data = handler->breakpointData(id);
|
const BreakpointParameters &data = handler->breakpointData(id);
|
||||||
QTC_ASSERT(data.type != UnknownType, return QByteArray());
|
QTC_ASSERT(data.type != UnknownBreakpointType, return QByteArray());
|
||||||
// FIXME: Non-GCC-runtime
|
// FIXME: Non-GCC-runtime
|
||||||
if (data.type == BreakpointAtThrow)
|
if (data.type == BreakpointAtThrow)
|
||||||
return "__cxa_throw";
|
return "__cxa_throw";
|
||||||
@@ -3198,7 +3198,7 @@ void GdbEngine::changeBreakpoint(BreakpointModelId id)
|
|||||||
{
|
{
|
||||||
BreakHandler *handler = breakHandler();
|
BreakHandler *handler = breakHandler();
|
||||||
const BreakpointParameters &data = handler->breakpointData(id);
|
const BreakpointParameters &data = handler->breakpointData(id);
|
||||||
QTC_ASSERT(data.type != UnknownType, return);
|
QTC_ASSERT(data.type != UnknownBreakpointType, return);
|
||||||
const BreakpointResponse &response = handler->response(id);
|
const BreakpointResponse &response = handler->response(id);
|
||||||
QTC_ASSERT(response.id.isValid(), return);
|
QTC_ASSERT(response.id.isValid(), return);
|
||||||
const QByteArray bpnr = response.id.toByteArray();
|
const QByteArray bpnr = response.id.toByteArray();
|
||||||
|
@@ -215,6 +215,7 @@ void LldbEngine::setupEngine()
|
|||||||
postCommand("setting set auto-confirm on");
|
postCommand("setting set auto-confirm on");
|
||||||
postCommand("setting set interpreter.prompt-on-quit off");
|
postCommand("setting set interpreter.prompt-on-quit off");
|
||||||
|
|
||||||
|
#if 0
|
||||||
// Default:
|
// Default:
|
||||||
// frame-format (string) = "frame #${frame.index}: ${frame.pc}
|
// frame-format (string) = "frame #${frame.index}: ${frame.pc}
|
||||||
// { ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}
|
// { ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}
|
||||||
@@ -246,6 +247,7 @@ void LldbEngine::setupEngine()
|
|||||||
"stopreason='${thread.stop-reason}'"
|
"stopreason='${thread.stop-reason}'"
|
||||||
//"returnvalue='${thread.return-value}'"
|
//"returnvalue='${thread.return-value}'"
|
||||||
"\\},");
|
"\\},");
|
||||||
|
#endif
|
||||||
|
|
||||||
notifyEngineSetupOk();
|
notifyEngineSetupOk();
|
||||||
}
|
}
|
||||||
@@ -266,7 +268,12 @@ void LldbEngine::handleInferiorSetup(const LldbResponse &response)
|
|||||||
void LldbEngine::runEngine()
|
void LldbEngine::runEngine()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
||||||
|
m_continuations.append(&LldbEngine::runEngine2);
|
||||||
attemptBreakpointSynchronization();
|
attemptBreakpointSynchronization();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LldbEngine::runEngine2()
|
||||||
|
{
|
||||||
showStatusMessage(tr("Running requested..."), 5000);
|
showStatusMessage(tr("Running requested..."), 5000);
|
||||||
postCommand("process launch", CB(handleRunEngine));
|
postCommand("process launch", CB(handleRunEngine));
|
||||||
}
|
}
|
||||||
@@ -280,7 +287,8 @@ void LldbEngine::handleRunEngine(const LldbResponse &response)
|
|||||||
void LldbEngine::interruptInferior()
|
void LldbEngine::interruptInferior()
|
||||||
{
|
{
|
||||||
showStatusMessage(tr("Interrupt requested..."), 5000);
|
showStatusMessage(tr("Interrupt requested..."), 5000);
|
||||||
postCommand("process launch", CB(handleInferiorInterrupt));
|
//postCommand("process interrupt", CB(handleInferiorInterrupt));
|
||||||
|
postCommand("script doInterrupt()", CB(handleInferiorInterrupt));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::handleInferiorInterrupt(const LldbResponse &response)
|
void LldbEngine::handleInferiorInterrupt(const LldbResponse &response)
|
||||||
@@ -288,46 +296,45 @@ void LldbEngine::handleInferiorInterrupt(const LldbResponse &response)
|
|||||||
Q_UNUSED(response);
|
Q_UNUSED(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::executeStep()
|
|
||||||
{
|
|
||||||
resetLocation();
|
|
||||||
notifyInferiorRunRequested();
|
|
||||||
postCommand("thread step-in", CB(handleContinue));
|
|
||||||
}
|
|
||||||
|
|
||||||
void LldbEngine::handleContinue(const LldbResponse &response)
|
void LldbEngine::handleContinue(const LldbResponse &response)
|
||||||
{
|
{
|
||||||
Q_UNUSED(response);
|
Q_UNUSED(response);
|
||||||
notifyInferiorRunOk();
|
notifyInferiorRunOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LldbEngine::executeStep()
|
||||||
|
{
|
||||||
|
resetLocation();
|
||||||
|
notifyInferiorRunRequested();
|
||||||
|
postCommand("script doStep()", CB(handleStepOver));
|
||||||
|
}
|
||||||
|
|
||||||
void LldbEngine::executeStepI()
|
void LldbEngine::executeStepI()
|
||||||
{
|
{
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
postCommand("thread step-inst", CB(handleContinue));
|
postCommand("script doStepInst()", CB(handleStepOver));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::executeStepOut()
|
void LldbEngine::executeStepOut()
|
||||||
{
|
{
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
postCommand("thread step-out", CB(handleContinue));
|
postCommand("script doStepOut()", CB(handleStepOver));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::executeNext()
|
void LldbEngine::executeNext()
|
||||||
{
|
{
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
postCommand("thread step-over", CB(handleContinue));
|
postCommand("script doStepOver()", CB(handleStepOver));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::executeNextI()
|
void LldbEngine::executeNextI()
|
||||||
{
|
{
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
notifyInferiorRunOk();
|
postCommand("script doStepInstOver()", CB(handleStepOver));
|
||||||
postCommand("thread step-inst-over", CB(handleContinue));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::continueInferior()
|
void LldbEngine::continueInferior()
|
||||||
@@ -337,6 +344,14 @@ void LldbEngine::continueInferior()
|
|||||||
postCommand("process continue", CB(handleContinue));
|
postCommand("process continue", CB(handleContinue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LldbEngine::handleStepOver(const LldbResponse &response)
|
||||||
|
{
|
||||||
|
GdbMi all = parseFromString(response.data, "result");
|
||||||
|
refreshAll(all);
|
||||||
|
notifyInferiorRunOk();
|
||||||
|
notifyInferiorSpontaneousStop();
|
||||||
|
}
|
||||||
|
|
||||||
void LldbEngine::executeRunToLine(const ContextData &data)
|
void LldbEngine::executeRunToLine(const ContextData &data)
|
||||||
{
|
{
|
||||||
Q_UNUSED(data)
|
Q_UNUSED(data)
|
||||||
@@ -377,56 +392,188 @@ bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const
|
|||||||
&& startParameters().startMode != AttachCore;
|
&& startParameters().startMode != AttachCore;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::insertBreakpoint(BreakpointModelId id)
|
void LldbEngine::attemptBreakpointSynchronization()
|
||||||
{
|
{
|
||||||
|
showMessage(_("ATTEMPT BREAKPOINT SYNCHRONIZATION"));
|
||||||
|
if (!stateAcceptsBreakpointChanges()) {
|
||||||
|
showMessage(_("BREAKPOINT SYNCHRONIZATION NOT POSSIBLE IN CURRENT STATE"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BreakHandler *handler = breakHandler();
|
BreakHandler *handler = breakHandler();
|
||||||
QTC_CHECK(handler->state(id) == BreakpointInsertRequested);
|
|
||||||
handler->notifyBreakpointInsertProceeding(id);
|
|
||||||
|
|
||||||
QByteArray loc;
|
foreach (BreakpointModelId id, handler->unclaimedBreakpointIds()) {
|
||||||
if (handler->type(id) == BreakpointByFunction)
|
// Take ownership of the breakpoint. Requests insertion.
|
||||||
loc = " --name " + handler->functionName(id).toLatin1();
|
if (acceptsBreakpoint(id)) {
|
||||||
else
|
showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2")
|
||||||
loc = " --file " + handler->fileName(id).toLocal8Bit()
|
.arg(id.toString()).arg(handler->state(id)));
|
||||||
+ " --line " + QByteArray::number(handler->lineNumber(id));
|
handler->setEngine(id, this);
|
||||||
|
} else {
|
||||||
|
showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
|
||||||
|
.arg(id.toString()).arg(handler->state(id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
postCommand("break set " + loc, CB(handleBreakInsert), QVariant(id));
|
QByteArray toAdd;
|
||||||
|
QByteArray toChange;
|
||||||
|
QByteArray toRemove;
|
||||||
|
|
||||||
|
bool done = true;
|
||||||
|
foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) {
|
||||||
|
const BreakpointResponse &response = handler->response(id);
|
||||||
|
switch (handler->state(id)) {
|
||||||
|
case BreakpointNew:
|
||||||
|
// Should not happen once claimed.
|
||||||
|
QTC_CHECK(false);
|
||||||
|
break;
|
||||||
|
case BreakpointInsertRequested:
|
||||||
|
done = false;
|
||||||
|
toAdd += "{\"modelid\":" + id.toByteArray();
|
||||||
|
toAdd += ",\"type\":" + QByteArray::number(handler->type(id));
|
||||||
|
toAdd += ",\"ignorecount\":" + QByteArray::number(handler->ignoreCount(id));
|
||||||
|
toAdd += ",\"condition\":\"" + handler->condition(id) + '"';
|
||||||
|
toAdd += ",\"function\":\"" + handler->functionName(id).toUtf8() + '"';
|
||||||
|
toAdd += ",\"oneshot\":" + QByteArray::number(int(handler->isOneShot(id)));
|
||||||
|
toAdd += ",\"enabled\":" + QByteArray::number(int(handler->isEnabled(id)));
|
||||||
|
toAdd += ",\"file\":\"" + handler->fileName(id).toUtf8() + '"';
|
||||||
|
toAdd += ",\"line\":" + QByteArray::number(handler->lineNumber(id)) + "},";
|
||||||
|
handler->notifyBreakpointInsertProceeding(id);
|
||||||
|
break;
|
||||||
|
case BreakpointChangeRequested:
|
||||||
|
done = false;
|
||||||
|
toChange += "{\"modelid\":" + id.toByteArray();
|
||||||
|
toChange += ",\"lldbid\":" + response.id.toByteArray();
|
||||||
|
toChange += ",\"type\":" + QByteArray::number(handler->type(id));
|
||||||
|
toChange += ",\"ignorecount\":" + QByteArray::number(handler->ignoreCount(id));
|
||||||
|
toChange += ",\"condition\":\"" + handler->condition(id) + '"';
|
||||||
|
toChange += ",\"function\":\"" + handler->functionName(id).toUtf8() + '"';
|
||||||
|
toChange += ",\"oneshot\":" + QByteArray::number(int(handler->isOneShot(id)));
|
||||||
|
toChange += ",\"enabled\":" + QByteArray::number(int(handler->isEnabled(id)));
|
||||||
|
toChange += ",\"file\":\"" + handler->fileName(id).toUtf8() + '"';
|
||||||
|
toChange += ",\"line\":" + QByteArray::number(handler->lineNumber(id)) + "},";
|
||||||
|
handler->notifyBreakpointChangeProceeding(id);
|
||||||
|
break;
|
||||||
|
case BreakpointRemoveRequested:
|
||||||
|
done = false;
|
||||||
|
toRemove += "{\"modelid\":" + id.toByteArray();
|
||||||
|
toRemove += ",\"lldbid\":" + response.id.toByteArray() + "},";
|
||||||
|
handler->notifyBreakpointRemoveProceeding(id);
|
||||||
|
break;
|
||||||
|
case BreakpointChangeProceeding:
|
||||||
|
case BreakpointInsertProceeding:
|
||||||
|
case BreakpointRemoveProceeding:
|
||||||
|
case BreakpointInserted:
|
||||||
|
case BreakpointDead:
|
||||||
|
QTC_CHECK(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << id << state());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!done) {
|
||||||
|
showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED"));
|
||||||
|
if (!toAdd.isEmpty())
|
||||||
|
toAdd.chop(1);
|
||||||
|
if (!toChange.isEmpty())
|
||||||
|
toChange.chop(1);
|
||||||
|
if (!toRemove.isEmpty())
|
||||||
|
toRemove.chop(1);
|
||||||
|
|
||||||
|
QByteArray cmd = "script handleBreakpoints('";
|
||||||
|
cmd += "{\"add\":[" + toAdd + "]";
|
||||||
|
cmd += ",\"change\":[" + toChange + "]";
|
||||||
|
cmd += ",\"remove\":[" + toRemove + "]}')";
|
||||||
|
postCommand(cmd, CB(handleBreakpointsSynchronized));
|
||||||
|
} else {
|
||||||
|
showMessage(_("BREAKPOINTS ARE SYNCHRONIZED"));
|
||||||
|
// d->m_disassemblerAgent.updateBreakpointMarkers();
|
||||||
|
//LldbResponse dummy;
|
||||||
|
//handleBreakpointsSynchronized(dummy);
|
||||||
|
performContinuation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::handleBreakInsert(const LldbResponse &response)
|
void LldbEngine::performContinuation()
|
||||||
{
|
{
|
||||||
//qDebug() << "BP RESPONSE: " << response.data;
|
if (!m_continuations.isEmpty()) {
|
||||||
// Breakpoint 1: where = simple_test_app`main + 62 at simple_test_app.cpp:6699,
|
LldbCommandContinuation cont = m_continuations.pop();
|
||||||
// address = 0x08061664
|
(this->*cont)();
|
||||||
BreakpointModelId id(response.cookie.toInt());
|
}
|
||||||
BreakHandler *handler = breakHandler();
|
|
||||||
QTC_ASSERT(response.data.startsWith("Breakpoint "), return);
|
|
||||||
int pos1 = response.data.indexOf(':');
|
|
||||||
QTC_ASSERT(pos1 != -1, return);
|
|
||||||
QByteArray bpnr = response.data.mid(11, pos1 - 11);
|
|
||||||
int pos2 = response.data.lastIndexOf(':');
|
|
||||||
QByteArray file = response.data.mid(pos1 + 4, pos2 - pos1 - 4);
|
|
||||||
QByteArray line = response.data.mid(pos2 + 1);
|
|
||||||
BreakpointResponse br;
|
|
||||||
br.id = BreakpointResponseId(bpnr);
|
|
||||||
br.fileName = _(file);
|
|
||||||
br.lineNumber = line.toInt();
|
|
||||||
handler->setResponse(id, br);
|
|
||||||
QTC_CHECK(!handler->needsChange(id));
|
|
||||||
handler->notifyBreakpointInsertOk(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::removeBreakpoint(BreakpointModelId id)
|
void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
|
||||||
{
|
{
|
||||||
BreakHandler *handler = breakHandler();
|
BreakHandler *handler = breakHandler();
|
||||||
QTC_CHECK(handler->state(id) == BreakpointRemoveRequested);
|
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
|
||||||
handler->notifyBreakpointRemoveProceeding(id);
|
BreakpointResponse response = handler->response(id);
|
||||||
BreakpointResponse br = handler->response(id);
|
BreakpointResponseId rid = BreakpointResponseId(bkpt.findChild("lldbid").data());
|
||||||
showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString())
|
if (added)
|
||||||
.arg(handler->fileName(id)));
|
response.id = rid;
|
||||||
postCommand("break delete " + br.id.toByteArray());
|
QTC_CHECK(response.id == rid);
|
||||||
// Pretend it succeeds without waiting for response.
|
response.address = 0;
|
||||||
handler->notifyBreakpointRemoveOk(id);
|
response.enabled = bkpt.findChild("enabled").data().toInt();
|
||||||
|
response.ignoreCount = bkpt.findChild("ignorecount").data().toInt();
|
||||||
|
response.condition = bkpt.findChild("condition").data();
|
||||||
|
response.hitCount = bkpt.findChild("hitcount").data().toInt();
|
||||||
|
|
||||||
|
if (added) {
|
||||||
|
// Added.
|
||||||
|
GdbMi locations = bkpt.findChild("locations");
|
||||||
|
const int numChild = locations.children().size();
|
||||||
|
if (numChild > 1) {
|
||||||
|
foreach (const GdbMi &location, locations.children()) {
|
||||||
|
BreakpointResponse sub;
|
||||||
|
sub.id = BreakpointResponseId(rid.majorPart(),
|
||||||
|
location.findChild("subid").data().toUShort());
|
||||||
|
sub.type = response.type;
|
||||||
|
sub.address = location.findChild("addr").toAddress();
|
||||||
|
sub.functionName = QString::fromUtf8(location.findChild("func").data());
|
||||||
|
handler->insertSubBreakpoint(id, sub);
|
||||||
|
}
|
||||||
|
} else if (numChild == 1) {
|
||||||
|
const GdbMi location = locations.childAt(0);
|
||||||
|
response.address = location.findChild("addr").toAddress();
|
||||||
|
response.functionName = QString::fromUtf8(location.findChild("func").data());
|
||||||
|
} else {
|
||||||
|
QTC_CHECK(false);
|
||||||
|
}
|
||||||
|
handler->setResponse(id, response);
|
||||||
|
handler->notifyBreakpointInsertOk(id);
|
||||||
|
} else {
|
||||||
|
// Changed.
|
||||||
|
handler->setResponse(id, response);
|
||||||
|
handler->notifyBreakpointChangeOk(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LldbEngine::handleBreakpointsSynchronized(const LldbResponse &response)
|
||||||
|
{
|
||||||
|
BreakHandler *handler = breakHandler();
|
||||||
|
GdbMi all = parseFromString(response.data, "bkpts");
|
||||||
|
GdbMi bkpts = all.findChild("bkpts");
|
||||||
|
GdbMi added = bkpts.findChild("added");
|
||||||
|
GdbMi changed = bkpts.findChild("changed");
|
||||||
|
GdbMi removed = bkpts.findChild("removed");
|
||||||
|
foreach (const GdbMi &bkpt, added.children()) {
|
||||||
|
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
|
||||||
|
QTC_CHECK(handler->state(id) == BreakpointInsertRequested);
|
||||||
|
updateBreakpointData(bkpt, true);
|
||||||
|
}
|
||||||
|
foreach (const GdbMi &bkpt, changed.children()) {
|
||||||
|
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
|
||||||
|
QTC_CHECK(handler->state(id) == BreakpointChangeRequested);
|
||||||
|
updateBreakpointData(bkpt, false);
|
||||||
|
}
|
||||||
|
foreach (const GdbMi &bkpt, removed.children()) {
|
||||||
|
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
|
||||||
|
QTC_CHECK(handler->state(id) == BreakpointRemoveRequested);
|
||||||
|
handler->notifyBreakpointRemoveOk(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop.
|
||||||
|
//attemptBreakpointSynchronization();
|
||||||
|
performContinuation();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::loadSymbols(const QString &moduleName)
|
void LldbEngine::loadSymbols(const QString &moduleName)
|
||||||
@@ -715,14 +862,24 @@ void LldbEngine::readLldbStandardOutput()
|
|||||||
// "<Esc>[KProcess 5564 stopped"
|
// "<Esc>[KProcess 5564 stopped"
|
||||||
// "* thread #1: tid = 0x15bc, 0x0804a17d untitled11`main(argc=1,
|
// "* thread #1: tid = 0x15bc, 0x0804a17d untitled11`main(argc=1,
|
||||||
// argv=0xbfffeff4) + 61 at main.cpp:52, stop reason = breakpoint 1.1 ..."
|
// argv=0xbfffeff4) + 61 at main.cpp:52, stop reason = breakpoint 1.1 ..."
|
||||||
const int pos = m_inbuffer.indexOf("\x1b[KProcess");
|
int pos = m_inbuffer.indexOf("\x1b[KProcess");
|
||||||
if (pos != -1) {
|
if (pos != -1) {
|
||||||
int pid = 0;
|
pos += 11;
|
||||||
const char *format = "\x1b[KProcess %d stopped";
|
const int pos1 = m_inbuffer.indexOf(' ', pos);
|
||||||
if (::sscanf(m_inbuffer.constData() + pos, format, &pid) == 1) {
|
if (pos1 != -1) {
|
||||||
notifyInferiorSpontaneousStop();
|
const int pid = m_inbuffer.mid(pos, pos1 - pos).toInt();
|
||||||
m_inbuffer.clear();
|
if (pid) {
|
||||||
updateAll();
|
if (m_inbuffer.mid(pos1 + 1).startsWith("stopped")) {
|
||||||
|
m_inbuffer.clear();
|
||||||
|
notifyInferiorSpontaneousStop();
|
||||||
|
gotoLocation(stackHandler()->currentFrame());
|
||||||
|
updateAll();
|
||||||
|
} else if (m_inbuffer.mid(pos1 + 1).startsWith("exited")) {
|
||||||
|
m_inbuffer.clear();
|
||||||
|
notifyInferiorExited();
|
||||||
|
//updateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -808,7 +965,7 @@ void LldbEngine::updateData(DataKind kind)
|
|||||||
int maxdepth = debuggerCore()->action(MaximalStackDepth)->value().toInt();
|
int maxdepth = debuggerCore()->action(MaximalStackDepth)->value().toInt();
|
||||||
ThreadId curthread = threadsHandler()->currentThread();
|
ThreadId curthread = threadsHandler()->currentThread();
|
||||||
stackOptions += "maxdepth:" + QByteArray::number(maxdepth);
|
stackOptions += "maxdepth:" + QByteArray::number(maxdepth);
|
||||||
stackOptions += "curthread:" + QByteArray::number(curthread.raw());
|
stackOptions += ",curthread:" + QByteArray::number(curthread.raw());
|
||||||
}
|
}
|
||||||
|
|
||||||
postCommand("script updateData(" + QByteArray::number(kind) + ','
|
postCommand("script updateData(" + QByteArray::number(kind) + ','
|
||||||
@@ -848,35 +1005,15 @@ void LldbEngine::handleUpdateData(const LldbResponse &response)
|
|||||||
{
|
{
|
||||||
//qDebug() << " LOCALS: '" << response.data << "'";
|
//qDebug() << " LOCALS: '" << response.data << "'";
|
||||||
GdbMi all = parseFromString(response.data, "data");
|
GdbMi all = parseFromString(response.data, "data");
|
||||||
GdbMi vars = all.findChild("data");
|
refreshAll(all);
|
||||||
if (vars.isValid()) {
|
}
|
||||||
const bool partial = response.cookie.toBool();
|
|
||||||
WatchHandler *handler = watchHandler();
|
|
||||||
QList<WatchData> list;
|
|
||||||
|
|
||||||
if (!partial) {
|
void LldbEngine::refreshAll(const GdbMi &all)
|
||||||
list.append(*handler->findData("local"));
|
{
|
||||||
list.append(*handler->findData("watch"));
|
|
||||||
list.append(*handler->findData("return"));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const GdbMi &child, vars.children()) {
|
|
||||||
WatchData dummy;
|
|
||||||
dummy.iname = child.findChild("iname").data();
|
|
||||||
GdbMi wname = child.findChild("wname");
|
|
||||||
if (wname.isValid()) {
|
|
||||||
// Happens (only) for watched expressions. They are encoded as
|
|
||||||
// base64 encoded 8 bit data, without quotes
|
|
||||||
dummy.name = decodeData(wname.data(), Base64Encoded8Bit);
|
|
||||||
dummy.exp = dummy.name.toUtf8();
|
|
||||||
} else {
|
|
||||||
dummy.name = _(child.findChild("name").data());
|
|
||||||
}
|
|
||||||
parseWatchData(handler->expandedINames(), dummy, child, &list);
|
|
||||||
}
|
|
||||||
handler->insertData(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
refreshLocals(all.findChild("data"));
|
||||||
|
refreshStack(all.findChild("stack"));
|
||||||
|
refreshThreads(all.findChild("threads"));
|
||||||
// const GdbMi typeInfo = all.findChild("typeinfo");
|
// const GdbMi typeInfo = all.findChild("typeinfo");
|
||||||
// if (typeInfo.type() == GdbMi::List) {
|
// if (typeInfo.type() == GdbMi::List) {
|
||||||
// foreach (const GdbMi &s, typeInfo.children()) {
|
// foreach (const GdbMi &s, typeInfo.children()) {
|
||||||
@@ -892,40 +1029,78 @@ void LldbEngine::handleUpdateData(const LldbResponse &response)
|
|||||||
// if (ti.size)
|
// if (ti.size)
|
||||||
// list[i].size = ti.size;
|
// list[i].size = ti.size;
|
||||||
// }
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
GdbMi stack = all.findChild("stack");
|
void LldbEngine::refreshLocals(const GdbMi &vars)
|
||||||
if (stack.isValid()) {
|
{
|
||||||
//if (!partial)
|
if (!vars.isValid())
|
||||||
// emit stackFrameCompleted();
|
return;
|
||||||
StackHandler *handler = stackHandler();
|
|
||||||
StackFrames frames;
|
|
||||||
foreach (const GdbMi &item, stack.findChild("frames").children()) {
|
|
||||||
StackFrame frame;
|
|
||||||
frame.level = item.findChild("level").data().toInt();
|
|
||||||
frame.file = QString::fromLatin1(item.findChild("file").data());
|
|
||||||
frame.function = QString::fromLatin1(item.findChild("func").data());
|
|
||||||
frame.from = QString::fromLatin1(item.findChild("func").data());
|
|
||||||
frame.line = item.findChild("line").data().toInt();
|
|
||||||
frame.address = item.findChild("addr").data().toULongLong();
|
|
||||||
frame.usable = QFileInfo(frame.file).isReadable();
|
|
||||||
frames.append(frame);
|
|
||||||
}
|
|
||||||
bool canExpand = stack.findChild("hasmore").data().toInt();
|
|
||||||
debuggerCore()->action(ExpandStack)->setEnabled(canExpand);
|
|
||||||
handler->setFrames(frames);
|
|
||||||
}
|
|
||||||
|
|
||||||
GdbMi threads = all.findChild("threads");
|
//const bool partial = response.cookie.toBool();
|
||||||
if (threads.isValid()) {
|
WatchHandler *handler = watchHandler();
|
||||||
ThreadsHandler *handler = threadsHandler();
|
QList<WatchData> list;
|
||||||
handler->updateThreads(threads);
|
|
||||||
if (!handler->currentThread().isValid()) {
|
//if (!partial) {
|
||||||
ThreadId other = handler->threadAt(0);
|
list.append(*handler->findData("local"));
|
||||||
if (other.isValid())
|
list.append(*handler->findData("watch"));
|
||||||
selectThread(other);
|
list.append(*handler->findData("return"));
|
||||||
|
//}
|
||||||
|
|
||||||
|
foreach (const GdbMi &child, vars.children()) {
|
||||||
|
WatchData dummy;
|
||||||
|
dummy.iname = child.findChild("iname").data();
|
||||||
|
GdbMi wname = child.findChild("wname");
|
||||||
|
if (wname.isValid()) {
|
||||||
|
// Happens (only) for watched expressions. They are encoded as
|
||||||
|
// base64 encoded 8 bit data, without quotes
|
||||||
|
dummy.name = decodeData(wname.data(), Base64Encoded8Bit);
|
||||||
|
dummy.exp = dummy.name.toUtf8();
|
||||||
|
} else {
|
||||||
|
dummy.name = _(child.findChild("name").data());
|
||||||
}
|
}
|
||||||
updateViews(); // Adjust Threads combobox.
|
parseWatchData(handler->expandedINames(), dummy, child, &list);
|
||||||
}
|
}
|
||||||
|
handler->insertData(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LldbEngine::refreshStack(const GdbMi &stack)
|
||||||
|
{
|
||||||
|
if (!stack.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
//if (!partial)
|
||||||
|
// emit stackFrameCompleted();
|
||||||
|
StackHandler *handler = stackHandler();
|
||||||
|
StackFrames frames;
|
||||||
|
foreach (const GdbMi &item, stack.findChild("frames").children()) {
|
||||||
|
StackFrame frame;
|
||||||
|
frame.level = item.findChild("level").data().toInt();
|
||||||
|
frame.file = QString::fromLatin1(item.findChild("file").data());
|
||||||
|
frame.function = QString::fromLatin1(item.findChild("func").data());
|
||||||
|
frame.from = QString::fromLatin1(item.findChild("func").data());
|
||||||
|
frame.line = item.findChild("line").data().toInt();
|
||||||
|
frame.address = item.findChild("addr").data().toULongLong();
|
||||||
|
frame.usable = QFileInfo(frame.file).isReadable();
|
||||||
|
frames.append(frame);
|
||||||
|
}
|
||||||
|
bool canExpand = stack.findChild("hasmore").data().toInt();
|
||||||
|
debuggerCore()->action(ExpandStack)->setEnabled(canExpand);
|
||||||
|
handler->setFrames(frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LldbEngine::refreshThreads(const GdbMi &threads)
|
||||||
|
{
|
||||||
|
if (!threads.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThreadsHandler *handler = threadsHandler();
|
||||||
|
handler->updateThreads(threads);
|
||||||
|
if (!handler->currentThread().isValid()) {
|
||||||
|
ThreadId other = handler->threadAt(0);
|
||||||
|
if (other.isValid())
|
||||||
|
selectThread(other);
|
||||||
|
}
|
||||||
|
updateViews(); // Adjust Threads combobox.
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::loadPythonDumpers()
|
void LldbEngine::loadPythonDumpers()
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include "debuggerengine.h"
|
#include "debuggerengine.h"
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QStack>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
@@ -60,6 +61,7 @@ class LldbEngine : public DebuggerEngine
|
|||||||
public:
|
public:
|
||||||
explicit LldbEngine(const DebuggerStartParameters &startParameters);
|
explicit LldbEngine(const DebuggerStartParameters &startParameters);
|
||||||
~LldbEngine();
|
~LldbEngine();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// DebuggerEngine implementation
|
// DebuggerEngine implementation
|
||||||
void executeStep();
|
void executeStep();
|
||||||
@@ -71,6 +73,7 @@ private:
|
|||||||
void setupEngine();
|
void setupEngine();
|
||||||
void setupInferior();
|
void setupInferior();
|
||||||
void runEngine();
|
void runEngine();
|
||||||
|
void runEngine2();
|
||||||
void shutdownInferior();
|
void shutdownInferior();
|
||||||
void shutdownEngine();
|
void shutdownEngine();
|
||||||
|
|
||||||
@@ -88,8 +91,7 @@ private:
|
|||||||
void selectThread(ThreadId threadId);
|
void selectThread(ThreadId threadId);
|
||||||
|
|
||||||
bool acceptsBreakpoint(BreakpointModelId id) const;
|
bool acceptsBreakpoint(BreakpointModelId id) const;
|
||||||
void insertBreakpoint(BreakpointModelId id);
|
void attemptBreakpointSynchronization();
|
||||||
void removeBreakpoint(BreakpointModelId id);
|
|
||||||
|
|
||||||
void assignValueInDebugger(const WatchData *data,
|
void assignValueInDebugger(const WatchData *data,
|
||||||
const QString &expr, const QVariant &value);
|
const QString &expr, const QVariant &value);
|
||||||
@@ -107,6 +109,9 @@ private:
|
|||||||
bool isSynchronous() const { return true; }
|
bool isSynchronous() const { return true; }
|
||||||
void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
|
void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
|
||||||
|
|
||||||
|
void performContinuation();
|
||||||
|
void handleStepOver(const LldbResponse &response);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void outputReady(const QByteArray &data);
|
void outputReady(const QByteArray &data);
|
||||||
|
|
||||||
@@ -120,6 +125,10 @@ private:
|
|||||||
Q_SLOT void readLldbStandardError();
|
Q_SLOT void readLldbStandardError();
|
||||||
Q_SLOT void handleOutput2(const QByteArray &data);
|
Q_SLOT void handleOutput2(const QByteArray &data);
|
||||||
void handleResponse(const QByteArray &ba);
|
void handleResponse(const QByteArray &ba);
|
||||||
|
void refreshAll(const GdbMi &all);
|
||||||
|
void refreshThreads(const GdbMi &threads);
|
||||||
|
void refreshStack(const GdbMi &stack);
|
||||||
|
void refreshLocals(const GdbMi &vars);
|
||||||
|
|
||||||
enum DataKind { LocalsData = 1, StackData = 2, ThreadData = 4 };
|
enum DataKind { LocalsData = 1, StackData = 2, ThreadData = 4 };
|
||||||
|
|
||||||
@@ -137,6 +146,7 @@ private:
|
|||||||
|
|
||||||
typedef void (LldbEngine::*LldbCommandCallback)
|
typedef void (LldbEngine::*LldbCommandCallback)
|
||||||
(const LldbResponse &response);
|
(const LldbResponse &response);
|
||||||
|
typedef void (LldbEngine::*LldbCommandContinuation)();
|
||||||
|
|
||||||
struct LldbCommand
|
struct LldbCommand
|
||||||
{
|
{
|
||||||
@@ -153,7 +163,8 @@ private:
|
|||||||
void handleListLocals(const LldbResponse &response);
|
void handleListLocals(const LldbResponse &response);
|
||||||
void handleListModules(const LldbResponse &response);
|
void handleListModules(const LldbResponse &response);
|
||||||
void handleListSymbols(const LldbResponse &response);
|
void handleListSymbols(const LldbResponse &response);
|
||||||
void handleBreakInsert(const LldbResponse &response);
|
void handleBreakpointsSynchronized(const LldbResponse &response);
|
||||||
|
void updateBreakpointData(const GdbMi &bkpt, bool added);
|
||||||
void handleUpdateStack(const LldbResponse &response);
|
void handleUpdateStack(const LldbResponse &response);
|
||||||
void handleUpdateThreads(const LldbResponse &response);
|
void handleUpdateThreads(const LldbResponse &response);
|
||||||
|
|
||||||
@@ -167,6 +178,7 @@ private:
|
|||||||
GdbMi parseFromString(QByteArray out, const QByteArray &firstTopLevel);
|
GdbMi parseFromString(QByteArray out, const QByteArray &firstTopLevel);
|
||||||
|
|
||||||
QQueue<LldbCommand> m_commands;
|
QQueue<LldbCommand> m_commands;
|
||||||
|
QStack<LldbCommandContinuation> m_continuations;
|
||||||
|
|
||||||
QByteArray m_inbuffer;
|
QByteArray m_inbuffer;
|
||||||
QString m_scriptFileName;
|
QString m_scriptFileName;
|
||||||
|
Reference in New Issue
Block a user