Commit a20a7d09 authored by hjk's avatar hjk

Debugger: Move QML stack access to DumperBase

... and make it work with LLDB.

Change-Id: Idaec029942dbcc726931781caff830173f7b126a
Reviewed-by: default avatarhjk <hjk@theqtcompany.com>
parent 18c83a61
......@@ -1784,6 +1784,53 @@ class DumperBase:
def isReportableQmlFrame(self, functionName):
return functionName and functionName.find("QV4::Moth::VME::exec") >= 0
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]
# typeof runtimeStrings = QV4.StringValue **
runtimeStrings = compilationUnitPtr.dereference()["runtimeStrings"]
entry = runtimeStrings[index]
text = self.extractPointer(entry.dereference(), self.ptrSize())
(elided, fn) = self.encodeStringHelper(text, 100)
return self.encodedUtf16ToUtf8(fn)
def extractQmlLocation(self, engine):
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"]
functionName = "Unknown 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"]
# QV4.CompiledData.Function
compiledFunction = function["compiledFunction"].dereference()
index = int(compiledFunction["nameIndex"])
functionName = "JS: " + self.extractQmlRuntimeString(compilationUnit, index)
string = self.parseAndEvaluate("((%s)0x%x)->fileName()"
% (compilationUnit.type, compilationUnit))
fileName = self.encodeStringUtf8(string)
return {'functionName': functionName,
'lineNumber': int(context["lineNumber"]),
'fileName': fileName,
'context': context }
# Some "Enums"
......
......@@ -1706,52 +1706,6 @@ 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 stackListFrames(self, n, options):
self.prepare("options:" + options + ",pe")
self.output = []
......@@ -1779,7 +1733,13 @@ class Dumper(DumperBase):
if self.nativeMixed:
if self.isReportableQmlFrame(functionName):
self.putQmlLocation(i, frame, sal)
engine = frame.read_var("engine")
h = self.extractQmlLocation(engine)
self.put(('frame={level="%s",func="%s",file="%s",'
'fullname="%s",line="%s",language="js",addr="0x%x"}')
% (i, h['functionName'], h['fileName'], h['fileName'],
h['lineNumber'], h['context']))
i += 1
frame = frame.older()
continue
......
......@@ -90,7 +90,7 @@ Value = lldb.SBValue
def impl_SBValue__add__(self, offset):
if self.GetType().IsPointerType():
if isinstance(offset, int) or isinstance(offset, long):
if isinstance(offset, int):
pass
else:
offset = offset.GetValueAsSigned()
......@@ -138,7 +138,7 @@ def impl_SBValue__long__(self):
return int(self.GetValue(), 0)
def impl_SBValue__getitem__(value, index):
if isinstance(index, int):
if isinstance(index, int) or isinstance(index, long):
type = value.GetType()
if type.IsPointerType():
innertype = value.Dereference().GetType()
......@@ -846,6 +846,7 @@ class Dumper(DumperBase):
(n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
self.currentCallContext = None
result = 'stack={current-thread="%s"' % thread.GetThreadID()
result += ',frames=['
for i in xrange(n):
......@@ -867,9 +868,15 @@ class Dumper(DumperBase):
if self.nativeMixed:
if self.isReportableQmlFrame(functionName):
#self.putQmlLocation(i, frame, sal)
functionName = "### JS ###";
language = "js"
engine = frame.FindVariable("engine")
self.context = engine
h = self.extractQmlLocation(engine)
pc = 0
functionName = h['functionName']
fullname = h['fileName']
lineNumber = h['lineNumber']
addr = h['context']
language = 'js'
elif not functionName is None:
if functionName.startswith("qt_v4"):
......@@ -1669,6 +1676,9 @@ class Dumper(DumperBase):
instructions = function.GetInstructions(self.target)
else:
base = args.get('address', 0)
if int(base) == 0xffffffffffffffff:
warn("INVALID DISASSEMBLER BASE")
return
addr = lldb.SBAddress(base, self.target)
instructions = self.target.ReadInstructions(addr, 100)
......
......@@ -1000,6 +1000,12 @@ void LldbEngine::refreshStack(const GdbMi &stack)
frame.usable = usable.data().toInt();
else
frame.usable = QFileInfo(frame.file).isReadable();
if (item["language"].data() == "js"
|| frame.file.endsWith(QLatin1String(".js"))
|| frame.file.endsWith(QLatin1String(".qml"))) {
frame.language = QmlLanguage;
frame.fixQmlFrame(startParameters());
}
frames.append(frame);
}
bool canExpand = stack["hasmore"].toInt();
......
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