Debugger: Fix QML extra stack loading for GDB

Change-Id: I702bb8f183e93fe25857115225fa55607ffb1674
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2016-10-11 14:58:55 +02:00
parent 4ae49fb856
commit cb7fb51313
6 changed files with 56 additions and 57 deletions

View File

@@ -998,9 +998,10 @@ class Dumper(DumperBase):
gdb.execute('continue')
def fetchStack(self, args):
def fromNativePath(str):
return str.replace('\\', '/')
def fromNativePath(string):
return string.replace('\\', '/')
extraQml = int(args.get('extraqml', '0'))
limit = int(args['limit'])
if limit <= 0:
limit = 10000
@@ -1008,8 +1009,42 @@ class Dumper(DumperBase):
self.prepare(args)
self.output = []
frame = gdb.newest_frame()
i = 0
if extraQml:
frame = gdb.newest_frame()
ns = self.qtNamespace()
needle = self.qtNamespace() + 'QV4::ExecutionEngine'
pat = "%sqt_v4StackTrace(((%sQV4::ExecutionEngine *)0x%x)->currentContext)"
done = False
while i < limit and frame and not done:
block = None
try:
block = frame.block()
except:
pass
if block is not None:
for symbol in block:
if symbol.is_variable or symbol.is_argument:
value = symbol.value(frame)
typeobj = value.type
if typeobj.code == gdb.TYPE_CODE_PTR:
dereftype = typeobj.target().unqualified()
if dereftype.name == needle:
addr = toInteger(value)
expr = pat % (ns, ns, addr)
res = str(gdb.parse_and_eval(expr))
pos = res.find('"stack=[')
if pos != -1:
res = res[pos + 8:-2]
res = res.replace('\\\"', '\"')
res = res.replace('func=', 'function=')
self.put(res)
done = True
break
frame = frame.older()
i += 1
frame = gdb.newest_frame()
self.currentCallContext = None
while i < limit and frame:
with OutputSafer(self):

View File

@@ -249,9 +249,12 @@ void GdbMi::parseList(const QChar *&from, const QChar *to)
}
GdbMi child;
child.parseResultOrValue(from, to);
if (child.isValid())
if (child.isValid()) {
m_children.push_back(child);
skipCommas(from, to);
skipCommas(from, to);
} else {
++from;
}
}
}

View File

@@ -3232,58 +3232,13 @@ static quint64 findJsExecutionContextAddress(const GdbMi &stackArgsResponse, con
void GdbEngine::loadAdditionalQmlStack()
{
// Scan for QV4::ExecutionContext parameter in the parameter list of a V4 call.
DebuggerCommand cmd("-stack-list-arguments --simple-values", NeedsStop);
cmd.callback = [this](const DebuggerResponse &response) {
if (!response.data.isValid()) {
showMessage(msgCannotLoadQmlStack("No stack obtained."), LogError);
return;
}
const quint64 contextAddress = findJsExecutionContextAddress(response.data, qtNamespace());
if (!contextAddress) {
showMessage(msgCannotLoadQmlStack("The address of the JS execution context could not be found."), LogError);
return;
}
// Call the debug function of QML with the context address to obtain the QML stack trace.
DebuggerCommand cmd;
cmd.function = "-data-evaluate-expression \"qt_v4StackTrace((QV4::ExecutionContext *)0x"
+ QString::number(contextAddress, 16) + ")\"";
cmd.callback = CB(handleQmlStackTrace);
runCommand(cmd);
};
DebuggerCommand cmd = stackCommand(-1);
cmd.arg("extraqml", "1");
cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, true); };
cmd.flags = Discardable | PythonCommand;
runCommand(cmd);
}
// Scan the arguments of a stack list for the address of a QV4::ExecutionContext.
void GdbEngine::handleQmlStackTrace(const DebuggerResponse &response)
{
if (!response.data.isValid()) {
showMessage(msgCannotLoadQmlStack("No result obtained."), LogError);
return;
}
// Prepend QML stack frames to existing C++ stack frames.
QString stackData = response.data["value"].data();
const int index = stackData.indexOf("stack=");
if (index == -1) {
showMessage(msgCannotLoadQmlStack("Malformed result."), LogError);
return;
}
stackData.remove(0, index);
stackData.replace("\\\"", "\"");
GdbMi stackMi;
stackMi.fromString(stackData);
const int qmlFrameCount = stackMi.childCount();
if (!qmlFrameCount) {
showMessage(msgCannotLoadQmlStack("No stack frames obtained."), LogError);
return;
}
QList<StackFrame> qmlFrames;
qmlFrames.reserve(qmlFrameCount);
for (int i = 0; i < qmlFrameCount; ++i)
qmlFrames.append(StackFrame::parseFrame(stackMi.childAt(i), runParameters()));
stackHandler()->prependFrames(qmlFrames);
}
DebuggerCommand GdbEngine::stackCommand(int depth)
{
DebuggerCommand cmd("fetchStack");

View File

@@ -360,9 +360,8 @@ protected:
void handleThreadNames(const DebuggerResponse &response);
DebuggerCommand stackCommand(int depth);
void reloadStack();
virtual void reloadFullStack() override;
virtual void loadAdditionalQmlStack() override;
void handleQmlStackTrace(const DebuggerResponse &response);
void reloadFullStack() override;
void loadAdditionalQmlStack() override;
int currentFrame() const;
//

View File

@@ -779,5 +779,11 @@ void QmlCppEngine::setActiveEngine(DebuggerEngine *engine)
updateViews();
}
void QmlCppEngine::loadAdditionalQmlStack()
{
if (m_cppEngine)
m_cppEngine->loadAdditionalQmlStack();
}
} // namespace Internal
} // namespace Debugger

View File

@@ -123,6 +123,7 @@ protected:
void notifyInferiorSetupOk() override;
void notifyEngineRemoteServerRunning(const QString &, int pid) override;
void loadAdditionalQmlStack() override;
private:
void engineStateChanged(DebuggerState newState);