forked from qt-creator/qt-creator
Debugger: Initial shot at native Qml-and-C++ debugging
Only for GDB now, requires a debug build of Qt, not feature complete. To enable it, run with QTC_DEBUGGER_NATIVE_MIXED=1 and press the 'oo' button in the debugger toolbar. Change-Id: I28aac9db13f7067e03cc364b89cc8046fa213dae Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
@@ -285,6 +285,7 @@ class Dumper(DumperBase):
|
||||
self.typesReported = {}
|
||||
self.typesToReport = {}
|
||||
self.qtNamespaceToReport = None
|
||||
self.qmlEngines = []
|
||||
|
||||
def prepare(self, args):
|
||||
self.output = []
|
||||
@@ -301,6 +302,7 @@ class Dumper(DumperBase):
|
||||
self.formats = {}
|
||||
self.useDynamicType = True
|
||||
self.expandedINames = {}
|
||||
self.qmlcontext = ""
|
||||
|
||||
# The guess does not need to be updated during a run()
|
||||
# as the result is fixed during that time (ignoring "active"
|
||||
@@ -340,12 +342,14 @@ class Dumper(DumperBase):
|
||||
self.formats[f[0:pos]] = int(f[pos+1:])
|
||||
elif arg.startswith("watchers:"):
|
||||
self.watchers = self.hexdecode(arg[pos:])
|
||||
elif arg.startswith("qmlcontext:"):
|
||||
self.qmlcontext = int(arg[pos:], 0)
|
||||
|
||||
self.useDynamicType = "dyntype" in self.options
|
||||
self.useFancy = "fancy" in self.options
|
||||
self.forceQtNamespace = "forcens" in self.options
|
||||
self.passExceptions = "pe" in self.options
|
||||
#self.passExceptions = True
|
||||
self.nativeMixed = "nativemixed" in self.options
|
||||
self.autoDerefPointers = "autoderef" in self.options
|
||||
self.partialUpdate = "partial" in self.options
|
||||
self.tooltipOnly = "tooltiponly" in self.options
|
||||
@@ -366,6 +370,68 @@ class Dumper(DumperBase):
|
||||
def listOfLocals(self):
|
||||
frame = gdb.selected_frame()
|
||||
|
||||
if self.qmlcontext:
|
||||
items = []
|
||||
|
||||
contextType = self.lookupQtType("QV4::Heap::CallContext")
|
||||
context = self.createPointerValue(self.qmlcontext, contextType)
|
||||
|
||||
contextItem = LocalItem()
|
||||
contextItem.iname = "local.@context"
|
||||
contextItem.name = "[context]"
|
||||
contextItem.value = context.dereference()
|
||||
items.append(contextItem)
|
||||
|
||||
argsItem = LocalItem()
|
||||
argsItem.iname = "local.@args"
|
||||
argsItem.name = "[args]"
|
||||
argsItem.value = context["callData"]
|
||||
items.append(argsItem)
|
||||
|
||||
functionObject = context["function"].dereference()
|
||||
functionPtr = functionObject["function"]
|
||||
if not self.isNull(functionPtr):
|
||||
compilationUnit = context["compilationUnit"]
|
||||
compiledFunction = functionPtr["compiledFunction"]
|
||||
base = int(compiledFunction)
|
||||
|
||||
formalsOffset = int(compiledFunction["formalsOffset"])
|
||||
formalsCount = int(compiledFunction["nFormals"])
|
||||
for index in range(formalsCount):
|
||||
stringIndex = self.extractInt(base + formalsOffset + 4 * index)
|
||||
name = self.extractQmlRuntimeString(compilationUnit, stringIndex)
|
||||
item = LocalItem()
|
||||
item.iname = "local." + name
|
||||
item.name = name
|
||||
item.value = argsItem.value["args"][index]
|
||||
items.append(item)
|
||||
|
||||
localsOffset = int(compiledFunction["localsOffset"])
|
||||
localsCount = int(compiledFunction["nLocals"])
|
||||
for index in range(localsCount):
|
||||
stringIndex = self.extractInt(base + localsOffset + 4 * index)
|
||||
name = self.extractQmlRuntimeString(compilationUnit, stringIndex)
|
||||
item = LocalItem()
|
||||
item.iname = "local." + name
|
||||
item.name = name
|
||||
item.value = contextData["locals"][index]
|
||||
items.append(item)
|
||||
|
||||
for engine in self.qmlEngines:
|
||||
engineItem = LocalItem()
|
||||
engineItem.iname = "local.@qmlengine"
|
||||
engineItem.name = "[engine]"
|
||||
engineItem.value = engine
|
||||
items.append(engineItem)
|
||||
|
||||
rootContext = LocalItem()
|
||||
rootContext.iname = "local.@rootContext"
|
||||
rootContext.name = "[rootContext]"
|
||||
rootContext.value = engine["d_ptr"]
|
||||
items.append(rootContext)
|
||||
break
|
||||
|
||||
return items
|
||||
|
||||
try:
|
||||
block = frame.block()
|
||||
@@ -452,7 +518,8 @@ class Dumper(DumperBase):
|
||||
# Locals
|
||||
#
|
||||
self.output.append('data=[')
|
||||
if self.partialUpdate and len(self.varList) == 1:
|
||||
if self.partialUpdate and len(self.varList) == 1 \
|
||||
and not self.qmlcontext:
|
||||
#warn("PARTIAL: %s" % self.varList)
|
||||
parts = self.varList[0].split('.')
|
||||
#warn("PARTIAL PARTS: %s" % parts)
|
||||
@@ -1699,6 +1766,59 @@ class Dumper(DumperBase):
|
||||
self.typesToReport[typestring] = typeobj
|
||||
return typeobj
|
||||
|
||||
def extractQmlData(self, value):
|
||||
if value.type.code == PointerCode:
|
||||
value = value.dereference()
|
||||
data = value["data"]
|
||||
return data.cast(self.lookupType(str(value.type).replace("QV4::", "QV4::Heap::")))
|
||||
|
||||
def extractQmlRuntimeString(self, compilationUnitPtr, index):
|
||||
# This mimics compilationUnit->runtimeStrings[index]
|
||||
runtimeStrings = compilationUnitPtr.dereference()["runtimeStrings"] # QV4.StringValue *
|
||||
entry = (runtimeStrings + index) # QV4.StringValue *
|
||||
text = entry["text"]
|
||||
(elided, fn) = self.encodeStringHelper(toInteger(text), 100)
|
||||
return self.encodedUtf16ToUtf8(fn) # string
|
||||
|
||||
def putQmlLocation(self, level, frame, sal):
|
||||
engine = frame.read_var("engine") # QV4.ExecutionEngine *
|
||||
if self.currentCallContext is None:
|
||||
context = engine["current"] # QV4.ExecutionContext * or derived
|
||||
self.currentCallContext = context
|
||||
else:
|
||||
context = self.currentCallContext["parent"]
|
||||
ctxCode = int(context["type"])
|
||||
compilationUnit = context["compilationUnit"] # QV4.CompiledData.CompilationUnit *
|
||||
functionName = "### JS ###";
|
||||
ns = self.qtNamespace()
|
||||
|
||||
# QV4.ExecutionContext.Type_SimpleCallContext - 4
|
||||
# QV4.ExecutionContext.Type_CallContext - 5
|
||||
if ctxCode == 4 or ctxCode == 5:
|
||||
callContextDataType = self.lookupQtType("QV4::Heap::CallContext")
|
||||
callContext = context.cast(callContextDataType.pointer())
|
||||
functionObject = callContext["function"]
|
||||
function = functionObject["function"]
|
||||
compiledFunction = function["compiledFunction"].dereference() # QV4.CompiledData.Function
|
||||
index = int(compiledFunction["nameIndex"])
|
||||
functionName = "### JS ### " + self.extractQmlRuntimeString(compilationUnit, index)
|
||||
|
||||
string = gdb.parse_and_eval("((%s)0x%x)->fileName()"
|
||||
% (compilationUnit.type, compilationUnit))
|
||||
fileName = self.encodeStringUtf8(string)
|
||||
|
||||
lineNumber = int(context["lineNumber"])
|
||||
self.put(('frame={level="%s",func="%s",file="%s",'
|
||||
'fullname="%s",line="%s",language="js",addr="0x%x"}')
|
||||
% (level, functionName, fileName, fileName, lineNumber, context))
|
||||
|
||||
def isInternalQmlFrame(self, functionName):
|
||||
if functionName.startswith("qt_v4"):
|
||||
return True
|
||||
return functionName.startswith(self.qtNamespace() + "QV4::")
|
||||
|
||||
def isReportableQmlFrame(self, functionName):
|
||||
return functionName.find("QV4::Moth::VME::exec") >= 0
|
||||
|
||||
def stackListFrames(self, n, options):
|
||||
self.prepare("options:" + options + ",pe")
|
||||
@@ -1706,8 +1826,7 @@ class Dumper(DumperBase):
|
||||
|
||||
frame = gdb.newest_frame()
|
||||
i = 0
|
||||
t1 = 'frame={level="%s",addr="0x%x",func="%s",'
|
||||
t1 += 'file="%s",fullname="%s",line="%s",from="%s"}'
|
||||
self.currentCallContext = None
|
||||
while i < n and frame:
|
||||
with OutputSafer(self):
|
||||
name = frame.name()
|
||||
@@ -1725,7 +1844,28 @@ class Dumper(DumperBase):
|
||||
objfile = symtab.objfile.filename
|
||||
fileName = symtab.filename
|
||||
fullName = symtab.fullname()
|
||||
self.put(t1 % (i, pc, functionName, fileName, fullName, line, objfile))
|
||||
|
||||
if self.nativeMixed:
|
||||
if self.isReportableQmlFrame(functionName):
|
||||
self.putQmlLocation(i, frame, sal)
|
||||
i += 1
|
||||
frame = frame.older()
|
||||
continue
|
||||
|
||||
if self.isInternalQmlFrame(functionName):
|
||||
frame = frame.older()
|
||||
self.put(('frame={level="%s",addr="0x%x",func="%s",'
|
||||
'file="%s",fullname="%s",line="%s",'
|
||||
'from="%s",language="c",usable="0"}') %
|
||||
(i, pc, functionName, fileName, fullName, line, objfile))
|
||||
i += 1
|
||||
frame = frame.older()
|
||||
continue
|
||||
|
||||
self.put(('frame={level="%s",addr="0x%x",func="%s",'
|
||||
'file="%s",fullname="%s",line="%s",'
|
||||
'from="%s",language="c"}') %
|
||||
(i, pc, functionName, fileName, fullName, line, objfile))
|
||||
|
||||
frame = frame.older()
|
||||
i += 1
|
||||
@@ -1941,3 +2081,104 @@ def addExtraDumper(args):
|
||||
return str((head, tail))
|
||||
|
||||
registerCommand("addExtraDumper", addExtraDumper)
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# Native Mixed
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
class QmlEngineCreationTracker(gdb.Breakpoint):
|
||||
def __init__(self):
|
||||
spec = "QQmlEnginePrivate::init"
|
||||
super(QmlEngineCreationTracker, self).\
|
||||
__init__(spec, gdb.BP_BREAKPOINT, internal=True)
|
||||
|
||||
def stop(self):
|
||||
engine = gdb.parse_and_eval("q_ptr")
|
||||
print("QML engine created: %s" % engine)
|
||||
theDumper.qmlEngines.append(engine)
|
||||
return False
|
||||
|
||||
#QmlEngineCreationTracker()
|
||||
|
||||
class TriggeredBreakpointHookBreakpoint(gdb.Breakpoint):
|
||||
def __init__(self):
|
||||
spec = "qt_v4TriggeredBreakpointHook"
|
||||
super(TriggeredBreakpointHookBreakpoint, self).\
|
||||
__init__(spec, gdb.BP_BREAKPOINT, internal=True)
|
||||
|
||||
def stop(self):
|
||||
print("QML engine stopped.")
|
||||
return True
|
||||
|
||||
TriggeredBreakpointHookBreakpoint()
|
||||
|
||||
|
||||
class ResolvePendingBreakpointsHookBreakpoint(gdb.Breakpoint):
|
||||
def __init__(self, fullName, lineNumber):
|
||||
self.fullName = fullName
|
||||
self.lineNumber = lineNumber
|
||||
spec = "qt_v4ResolvePendingBreakpointsHook"
|
||||
print("Preparing hook to resolve pending QML breakpoint at %s:%s"
|
||||
% (self.fullName, self.lineNumber))
|
||||
super(ResolvePendingBreakpointsHookBreakpoint, self).\
|
||||
__init__(spec, gdb.BP_BREAKPOINT, internal=True, temporary=False)
|
||||
|
||||
def stop(self):
|
||||
bp = doInsertQmlBreakPoint(self.fullName, self.lineNumber)
|
||||
print("Resolving QML breakpoint %s:%s -> %s"
|
||||
% (self.fullName, self.lineNumber, bp))
|
||||
self.enabled = False
|
||||
return False
|
||||
|
||||
def doInsertQmlBreakPoint(fullName, lineNumber):
|
||||
pos = fullName.rfind('/')
|
||||
engineName = "qrc:/" + fullName[pos+1:]
|
||||
cmd = 'qt_v4InsertBreakpoint("%s",%s,"%s","")' \
|
||||
% (fullName, lineNumber, engineName)
|
||||
try:
|
||||
bp = gdb.parse_and_eval(cmd)
|
||||
print("Resolving QML breakpoint: %s" % bp)
|
||||
return int(bp)
|
||||
except RuntimeError as error:
|
||||
print("Direct QML breakpoint insertion failed: %s" % error)
|
||||
print("Make pending.")
|
||||
ResolvePendingBreakpointsHookBreakpoint(fullName, lineNumber)
|
||||
return 0
|
||||
|
||||
def insertQmlBreakpoint(arg):
|
||||
(fullName, lineNumber) = arg.split(' ')
|
||||
print("Insert QML breakpoint %s:%s" % (fullName, lineNumber))
|
||||
bp = doInsertQmlBreakPoint(fullName, lineNumber)
|
||||
try:
|
||||
gdb.execute("set variable qt_v4IsStepping=0")
|
||||
except RuntimeError as error:
|
||||
print("Resetting stepping failed: %s" % error)
|
||||
return str(bp)
|
||||
|
||||
registerCommand("insertQmlBreakpoint", insertQmlBreakpoint)
|
||||
|
||||
def removeQmlBreakpoint(arg):
|
||||
(fullName, lineNumber) = arg.split(' ')
|
||||
pos = fullName.rfind('/')
|
||||
engineName = "qrc:/" + fullName[pos+1:]
|
||||
fsName = fullName
|
||||
cmd = 'qt_v4RemoveBreakpoint("%s",%s)' % (fullName, lineNumber)
|
||||
print("Remove QML breakpoint %s:%s" % (fullName, lineNumber))
|
||||
try:
|
||||
res = gdb.parse_and_eval(cmd)
|
||||
print("Removing QML breakpoint: %s" % (cmd, res))
|
||||
return int(res)
|
||||
except RuntimeError as error:
|
||||
print("Direct QML breakpoint removal failed: %s." % error)
|
||||
return 0
|
||||
return str(bp)
|
||||
|
||||
registerCommand("removeQmlBreakpoint", removeQmlBreakpoint)
|
||||
|
||||
def prepareQmlStep(arg):
|
||||
gdb.execute("set variable qt_v4IsStepping=1")
|
||||
return ""
|
||||
|
||||
registerCommand("prepareQmlStep", prepareQmlStep)
|
||||
|
@@ -2255,19 +2255,49 @@ def qdump__QXmlStreamAttribute(d, value):
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
def qdump__QV4__Object(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
d.putItem(d.extractQmlData(value))
|
||||
|
||||
def qdump__QV4__FunctionObject(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
d.putItem(d.extractQmlData(value))
|
||||
|
||||
def qdump__QV4__CompilationUnit(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
d.putItem(d.extractQmlData(value))
|
||||
|
||||
def qdump__QV4__CallContext(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
d.putItem(d.extractQmlData(value))
|
||||
|
||||
def qdump__QV4__ScriptFunction(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
d.putItem(d.extractQmlData(value))
|
||||
|
||||
def qdump__QV4__SimpleScriptFunction(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
d.putItem(d.extractQmlData(value))
|
||||
|
||||
def qdump__QV4__ExecutionContext(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
d.putItem(d.extractQmlData(value))
|
||||
|
||||
def qdump__QV4__TypedValue(d, value):
|
||||
d.putBetterType(d.currentType)
|
||||
qdump__QV4__Value(d, d.directBaseObject(value))
|
||||
d.putBetterType(value.type)
|
||||
|
||||
def qdump__QV4__CallData(d, value):
|
||||
argc = toInteger(value["argc"])
|
||||
d.putValue("<%s args>" % argc)
|
||||
d.putNumChild(1)
|
||||
d.putItemCount(argc)
|
||||
if d.isExpanded():
|
||||
with Children(d):
|
||||
for i in range(0, argc + 1):
|
||||
d.putSubItem("[this]", value["thisObject"])
|
||||
for i in range(0, argc):
|
||||
d.putSubItem(i, value["args"][i])
|
||||
d.putFields(value)
|
||||
|
||||
def qdump__QV4__String(d, value):
|
||||
d.putStringValue(d.addressOf(value) + 2 * d.ptrSize())
|
||||
|
||||
def qdump__QV4__Value(d, value):
|
||||
v = toInteger(str(value["val"]))
|
||||
@@ -2295,7 +2325,7 @@ def qdump__QV4__Value(d, value):
|
||||
d.putBetterType("%sQV4::Value (null/bool)" % ns)
|
||||
d.putValue("(null/bool)")
|
||||
else:
|
||||
vtable = value["m"]["data"]["internalClass"]["vtable"]
|
||||
vtable = value["m"]["vtable"]
|
||||
if toInteger(vtable["isString"]):
|
||||
d.putBetterType("%sQV4::Value (string)" % ns)
|
||||
d.putStringValue(d.extractPointer(value) + 2 * d.ptrSize())
|
||||
|
@@ -1379,8 +1379,10 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
||||
|
||||
int lineNumber = 0;
|
||||
QString fullName;
|
||||
QByteArray function;
|
||||
if (frame.isValid()) {
|
||||
const GdbMi lineNumberG = frame["line"];
|
||||
function = frame["func"].data();
|
||||
if (lineNumberG.isValid()) {
|
||||
lineNumber = lineNumberG.toInt();
|
||||
fullName = cleanupFullName(QString::fromLocal8Bit(frame["fullname"].data()));
|
||||
@@ -1411,7 +1413,8 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
||||
// Quickly set the location marker.
|
||||
if (lineNumber && !boolSetting(OperateByInstruction)
|
||||
&& QFileInfo::exists(fullName)
|
||||
&& !isQFatalBreakpoint(rid))
|
||||
&& !isQFatalBreakpoint(rid)
|
||||
&& function != "qt_v4TriggeredBreakpointHook")
|
||||
gotoLocation(Location(fullName, lineNumber));
|
||||
|
||||
if (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
|
||||
@@ -1453,7 +1456,6 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
||||
|
||||
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
|
||||
|
||||
|
||||
if (gotoHandleStop1)
|
||||
handleStop1(data);
|
||||
}
|
||||
@@ -2060,6 +2062,11 @@ void GdbEngine::executeStep()
|
||||
setTokenBarrier();
|
||||
notifyInferiorRunRequested();
|
||||
showStatusMessage(tr("Step requested..."), 5000);
|
||||
if (isNativeMixedActive()) {
|
||||
postCommand("prepareQmlStep 0");
|
||||
postCommand("-exec-continue", RunRequest, CB(handleExecuteContinue));
|
||||
return;
|
||||
}
|
||||
if (isReverseDebugging())
|
||||
postCommand("reverse-step", RunRequest, CB(handleExecuteStep));
|
||||
else
|
||||
@@ -2132,6 +2139,11 @@ void GdbEngine::executeNext()
|
||||
setTokenBarrier();
|
||||
notifyInferiorRunRequested();
|
||||
showStatusMessage(tr("Step next requested..."), 5000);
|
||||
if (isNativeMixedActive()) {
|
||||
postCommand("prepareQmlStep 1");
|
||||
postCommand("-exec-continue", RunRequest, CB(handleExecuteContinue));
|
||||
return;
|
||||
}
|
||||
if (isReverseDebugging()) {
|
||||
postCommand("reverse-next", RunRequest, CB(handleExecuteNext));
|
||||
} else {
|
||||
@@ -2887,6 +2899,15 @@ void GdbEngine::removeBreakpoint(Breakpoint bp)
|
||||
{
|
||||
QTC_CHECK(bp.state() == BreakpointRemoveRequested);
|
||||
BreakpointResponse br = bp.response();
|
||||
|
||||
const BreakpointParameters &data = bp.parameters();
|
||||
if (!data.isCppBreakpoint()) {
|
||||
postCommand("removeQmlBreakpoint " + data.fileName.toUtf8() + ' '
|
||||
+ QByteArray::number(data.lineNumber));
|
||||
bp.notifyBreakpointRemoveOk();
|
||||
return;
|
||||
}
|
||||
|
||||
if (br.id.isValid()) {
|
||||
// We already have a fully inserted breakpoint.
|
||||
bp.notifyBreakpointRemoveProceeding();
|
||||
@@ -3291,7 +3312,7 @@ QByteArray GdbEngine::stackCommand(int depth)
|
||||
if (isNativeMixedEnabled()) {
|
||||
cmd = "stackListFrames " + QByteArray::number(depth) + ' ';
|
||||
if (isNativeMixedActive())
|
||||
cmd += "mixed";
|
||||
cmd += "nativemixed";
|
||||
else
|
||||
cmd += "noopt";
|
||||
} else {
|
||||
@@ -3325,8 +3346,15 @@ StackFrame GdbEngine::parseStackFrame(const GdbMi &frameMi, int level)
|
||||
frame.from = _(frameMi["from"].data());
|
||||
frame.line = frameMi["line"].toInt();
|
||||
frame.address = frameMi["addr"].toAddress();
|
||||
frame.usable = QFileInfo(frame.file).isReadable();
|
||||
if (frameMi["language"].data() == "js") {
|
||||
GdbMi usable = frameMi["usable"];
|
||||
if (usable.isValid())
|
||||
frame.usable = usable.data().toInt();
|
||||
else
|
||||
frame.usable = QFileInfo(frame.file).isReadable();
|
||||
if (frameMi["language"].data() == "js"
|
||||
|| frame.file.endsWith(QLatin1String(".js"))
|
||||
|| frame.file.endsWith(QLatin1String(".qml"))) {
|
||||
frame.file = QFile::decodeName(frameMi["file"].data());
|
||||
frame.language = QmlLanguage;
|
||||
frame.fixQmlFrame(startParameters());
|
||||
}
|
||||
@@ -4847,6 +4875,8 @@ void GdbEngine::updateLocalsPython(const UpdateParameters ¶ms)
|
||||
options += "autoderef,";
|
||||
if (boolSetting(UseDynamicType))
|
||||
options += "dyntype,";
|
||||
if (isNativeMixedActive())
|
||||
options += "nativemixed,";
|
||||
if (options.isEmpty())
|
||||
options += "defaults,";
|
||||
if (params.tryPartial)
|
||||
@@ -4855,16 +4885,23 @@ void GdbEngine::updateLocalsPython(const UpdateParameters ¶ms)
|
||||
options += "tooltiponly,";
|
||||
options.chop(1);
|
||||
|
||||
QByteArray context;
|
||||
if (isNativeMixedActive()) {
|
||||
StackFrame frame = stackHandler()->currentFrame();
|
||||
if (frame.language == QmlLanguage)
|
||||
context += " qmlcontext:0x" + QByteArray::number(frame.address, 16);
|
||||
}
|
||||
|
||||
QByteArray resultVar;
|
||||
if (!m_resultVarName.isEmpty())
|
||||
resultVar = "resultvarname:" + m_resultVarName + ' ';
|
||||
|
||||
m_lastDebuggableCommand =
|
||||
"bb options:pe," + options + " vars:" + params.varList + ' '
|
||||
+ expanded + " watchers:" + watchers.toHex() + cutOff;
|
||||
+ expanded + " watchers:" + watchers.toHex() + cutOff + context;
|
||||
|
||||
postCommand("bb options:" + options + " vars:" + params.varList + ' '
|
||||
+ resultVar + expanded + " watchers:" + watchers.toHex() + cutOff,
|
||||
+ resultVar + expanded + " watchers:" + watchers.toHex() + cutOff + context,
|
||||
Discardable, CB(handleStackFramePython), QVariant(params.tryPartial));
|
||||
}
|
||||
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "gdbprocess.h"
|
||||
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <debugger/debuggercore.h>
|
||||
#include <debugger/procinterrupt.h>
|
||||
|
||||
namespace Debugger {
|
||||
@@ -115,8 +116,11 @@ void GdbProcess::setProcessEnvironment(const QProcessEnvironment &env)
|
||||
m_gdbProc.setProcessEnvironment(env);
|
||||
}
|
||||
|
||||
void GdbProcess::setEnvironment(const QStringList &env)
|
||||
void GdbProcess::setEnvironment(const QStringList &env_)
|
||||
{
|
||||
QStringList env = env_;
|
||||
if (isNativeMixedActive())
|
||||
env.append(QLatin1String("QV4_FORCE_INTERPRETER=1")); // FIXME: REMOVE!
|
||||
m_gdbProc.setEnvironment(Utils::Environment(env));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user