Commit 87f2d83e authored by hjk's avatar hjk
Browse files

Debugger: Add basic breakpoint handling and stepping to LLDB backend



Change-Id: Ib700afa63739e6d26bdd97225265559d7112eadb
Reviewed-by: default avatarhjk <hjk121@nokiamail.com>
parent 46b9c03c
......@@ -422,11 +422,34 @@ try:
#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
......@@ -578,8 +601,133 @@ try:
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:
#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
# }
# }
#}
#}
......@@ -123,7 +123,8 @@ static QString typeToString(BreakpointType type)
return BreakHandler::tr("Breakpoint on QML Signal Emit");
case BreakpointAtJavaScriptThrow:
return BreakHandler::tr("Breakpoint at JavaScript throw");
case UnknownType:
case UnknownBreakpointType:
case LastBreakpointType:
break;
}
return BreakHandler::tr("Unknown Breakpoint Type");
......@@ -189,7 +190,7 @@ static bool isSimilarTo(const BreakpointParameters &data, const BreakpointRespon
{
// Clear hit.
// Clear miss.
if (needle.type != UnknownType && data.type != UnknownType
if (needle.type != UnknownBreakpointType && data.type != UnknownBreakpointType
&& data.type != needle.type)
return false;
......@@ -382,7 +383,7 @@ void BreakHandler::loadBreakpoints()
if (v.isValid())
data.tracepoint = bool(v.toInt());
v = map.value(_("type"));
if (v.isValid() && v.toInt() != UnknownType)
if (v.isValid() && v.toInt() != UnknownBreakpointType)
data.type = BreakpointType(v.toInt());
v = map.value(_("module"));
if (v.isValid())
......
......@@ -60,6 +60,18 @@ QDebug operator<<(QDebug d, const BreakpointModelId &id)
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
{
if (!isValid())
......@@ -239,7 +251,8 @@ bool BreakpointParameters::isValid() const
break;
case WatchpointAtExpression:
return !expression.isEmpty();
case UnknownType:
case UnknownBreakpointType:
case LastBreakpointType:
return false;
}
return true;
......@@ -315,10 +328,10 @@ QString BreakpointParameters::toString() const
case BreakpointAtMain:
case BreakpointAtFork:
case BreakpointAtExec:
//case BreakpointAtVFork:
case BreakpointAtSysCall:
case BreakpointAtJavaScriptThrow:
case UnknownType:
case UnknownBreakpointType:
case LastBreakpointType:
break;
}
ts << (enabled ? " [enabled]" : " [disabled]");
......
......@@ -120,9 +120,11 @@ QDebug operator<<(QDebug d, const BreakpointResponseId &id);
//////////////////////////////////////////////////////////////////
//! \enum Debugger::Internal::BreakpointType
// Note: Keep synchronized with similar definitions in bridge.py
enum BreakpointType
{
UnknownType,
UnknownBreakpointType,
BreakpointByFileAndLine,
BreakpointByFunction,
BreakpointByAddress,
......@@ -131,12 +133,12 @@ enum BreakpointType
BreakpointAtMain,
BreakpointAtFork,
BreakpointAtExec,
//BreakpointAtVFork,
BreakpointAtSysCall,
WatchpointAtAddress,
WatchpointAtExpression,
BreakpointOnQmlSignalEmit,
BreakpointAtJavaScriptThrow
BreakpointAtJavaScriptThrow,
LastBreakpointType
};
//! \enum Debugger::Internal::BreakpointState
......@@ -200,7 +202,7 @@ inline void operator|=(BreakpointParts &p, BreakpointParts r)
class BreakpointParameters
{
public:
explicit BreakpointParameters(BreakpointType = UnknownType);
explicit BreakpointParameters(BreakpointType = UnknownBreakpointType);
BreakpointParts differencesTo(const BreakpointParameters &rhs) const;
bool isValid() const;
bool equals(const BreakpointParameters &rhs) const;
......
......@@ -136,7 +136,7 @@ private:
};
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)
{
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 QML signal emit")
<< 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->setMaxVisibleItems(20);
m_comboBoxType->addItems(types);
......@@ -512,7 +513,8 @@ void BreakpointDialog::typeChanged(int)
m_previousType = newType;
// Save current state.
switch (previousType) {
case UnknownType:
case UnknownBreakpointType:
case LastBreakpointType:
break;
case BreakpointByFileAndLine:
getParts(FileAndLinePart|ModulePart|AllConditionParts|TracePointPart, &m_savedParameters);
......@@ -542,7 +544,8 @@ void BreakpointDialog::typeChanged(int)
// Enable and set up new state from saved values.
switch (newType) {
case UnknownType:
case UnknownBreakpointType:
case LastBreakpointType:
break;
case BreakpointByFileAndLine:
setParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart, m_savedParameters);
......
......@@ -2586,7 +2586,8 @@ bool CdbEngine::acceptsBreakpoint(BreakpointModelId id) const
if (!data.isCppBreakpoint())
return false;
switch (data.type) {
case UnknownType:
case UnknownBreakpointType:
case LastBreakpointType:
case BreakpointAtFork:
case WatchpointAtExpression:
case BreakpointAtSysCall:
......
......@@ -92,7 +92,8 @@ static inline QString cdbBreakPointFileName(const BreakpointParameters &bp,
static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
{
switch (p.type) {
case UnknownType:
case UnknownBreakpointType:
case LastBreakpointType:
case BreakpointByFileAndLine:
case BreakpointByFunction:
case BreakpointByAddress:
......@@ -181,12 +182,13 @@ QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
case BreakpointAtExec:
case WatchpointAtExpression:
case BreakpointAtSysCall:
case UnknownType:
case BreakpointAtCatch:
case BreakpointAtThrow:
case BreakpointAtMain:
case BreakpointOnQmlSignalEmit:
case BreakpointAtJavaScriptThrow:
case UnknownBreakpointType:
case LastBreakpointType:
QTC_ASSERT(false, return QByteArray());
break;
case BreakpointByAddress:
......
......@@ -2540,7 +2540,7 @@ QByteArray GdbEngine::breakpointLocation(BreakpointModelId id)
{
BreakHandler *handler = breakHandler();
const BreakpointParameters &data = handler->breakpointData(id);
QTC_ASSERT(data.type != UnknownType, return QByteArray());
QTC_ASSERT(data.type != UnknownBreakpointType, return QByteArray());
// FIXME: Non-GCC-runtime
if (data.type == BreakpointAtThrow)
return "__cxa_throw";
......@@ -3198,7 +3198,7 @@ void GdbEngine::changeBreakpoint(BreakpointModelId id)
{
BreakHandler *handler = breakHandler();
const BreakpointParameters &data = handler->breakpointData(id);
QTC_ASSERT(data.type != UnknownType, return);
QTC_ASSERT(data.type != UnknownBreakpointType, return);
const BreakpointResponse &response = handler->response(id);
QTC_ASSERT(response.id.isValid(), return);
const QByteArray bpnr = response.id.toByteArray();
......
This diff is collapsed.
......@@ -33,6 +33,7 @@
#include "debuggerengine.h"
#include <QProcess>
#include <QStack>
#include <QQueue>
#include <QVariant>
......@@ -60,6 +61,7 @@ class LldbEngine : public DebuggerEngine
public:
explicit LldbEngine(const DebuggerStartParameters &startParameters);
~LldbEngine();
private:
// DebuggerEngine implementation
void executeStep();
......@@ -71,6 +73,7 @@ private:
void setupEngine();
void setupInferior();
void runEngine();
void runEngine2();
void shutdownInferior();
void shutdownEngine();
......@@ -88,8 +91,7 @@ private:
void selectThread(ThreadId threadId);
bool acceptsBreakpoint(BreakpointModelId id) const;
void insertBreakpoint(BreakpointModelId id);
void removeBreakpoint(BreakpointModelId id);
void attemptBreakpointSynchronization();
void assignValueInDebugger(const WatchData *data,
const QString &expr, const QVariant &value);
......@@ -107,6 +109,9 @@ private:
bool isSynchronous() const { return true; }
void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
void performContinuation();
void handleStepOver(const LldbResponse &response);
signals:
void outputReady(const QByteArray &data);
......@@ -120,6 +125,10 @@ private:
Q_SLOT void readLldbStandardError();
Q_SLOT void handleOutput2(const QByteArray &data);
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 };
......@@ -137,6 +146,7 @@ private:
typedef void (LldbEngine::*LldbCommandCallback)
(const LldbResponse &response);
typedef void (LldbEngine::*LldbCommandContinuation)();
struct LldbCommand
{
......@@ -153,7 +163,8 @@ private:
void handleListLocals(const LldbResponse &response);
void handleListModules(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 handleUpdateThreads(const LldbResponse &response);
......@@ -167,6 +178,7 @@ private:
GdbMi parseFromString(QByteArray out, const QByteArray &firstTopLevel);
QQueue<LldbCommand> m_commands;
QStack<LldbCommandContinuation> m_continuations;
QByteArray m_inbuffer;
QString m_scriptFileName;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment