Debugger: Add support for none standard Qt builds

... to the python based cdb dumper.
Now supporting static, namespace and qt builds with a libinfix.

Change-Id: Ib6bcd00dba876adc7a56c23ec4f4280cd3208143
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2017-01-13 09:08:17 +01:00
parent cb2021d630
commit 046e6309d3
2 changed files with 75 additions and 3 deletions

View File

@@ -27,6 +27,7 @@ import inspect
import os import os
import sys import sys
import cdbext import cdbext
import re
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
@@ -229,10 +230,18 @@ class Dumper(DumperBase):
def qtCoreModuleName(self): def qtCoreModuleName(self):
modules = cdbext.listOfModules() modules = cdbext.listOfModules()
# first check for an exact module name match
for coreName in ['Qt5Cored', 'Qt5Core', 'QtCored4', 'QtCore4']: for coreName in ['Qt5Cored', 'Qt5Core', 'QtCored4', 'QtCore4']:
if coreName in modules: if coreName in modules:
self.qtCoreModuleName = lambda: coreName self.qtCoreModuleName = lambda: coreName
return coreName return coreName
# maybe we have a libinfix build.
for pattern in ['Qt5Core.*', 'QtCore.*']:
matches = [module for module in modules if re.match(pattern, module)]
if matches:
coreName = matches[0]
self.qtCoreModuleName = lambda: coreName
return coreName
return None return None
def qtDeclarativeModuleName(self): def qtDeclarativeModuleName(self):
@@ -241,13 +250,24 @@ class Dumper(DumperBase):
if declarativeModuleName in modules: if declarativeModuleName in modules:
self.qtDeclarativeModuleName = lambda: declarativeModuleName self.qtDeclarativeModuleName = lambda: declarativeModuleName
return declarativeModuleName return declarativeModuleName
matches = [module for module in modules if re.match('Qt5Qml.*', module)]
if matches:
declarativeModuleName = matches[0]
self.qtDeclarativeModuleName = lambda: declarativeModuleName
return declarativeModuleName
return None return None
def qtHookDataSymbolName(self): def qtHookDataSymbolName(self):
hookSymbolName = 'qtHookData' hookSymbolName = 'qtHookData'
coreModuleName = self.qtCoreModuleName() coreModuleName = self.qtCoreModuleName()
if coreModuleName is not None: if coreModuleName is not None:
hookSymbolName = '%s!%s' % (coreModuleName, hookSymbolName) hookSymbolName = '%s!%s%s' % (coreModuleName, self.qtNamespace(), hookSymbolName)
else:
resolved = cdbext.resolveSymbol('*' + hookSymbolName)
if resolved:
hookSymbolName = resolved[0]
else:
hookSymbolName = '*%s' % hookSymbolName
self.qtHookDataSymbolName = lambda: hookSymbolName self.qtHookDataSymbolName = lambda: hookSymbolName
return hookSymbolName return hookSymbolName
@@ -255,12 +275,29 @@ class Dumper(DumperBase):
hookSymbolName = 'qtDeclarativeHookData' hookSymbolName = 'qtDeclarativeHookData'
declarativeModuleName = self.qtDeclarativeModuleName() declarativeModuleName = self.qtDeclarativeModuleName()
if declarativeModuleName is not None: if declarativeModuleName is not None:
hookSymbolName = '%s!%s' % (declarativeModuleName, hookSymbolName) hookSymbolName = '%s!%s%s' % (declarativeModuleName, self.qtNamespace(), hookSymbolName)
else:
resolved = cdbext.resolveSymbol('*' + hookSymbolName)
if resolved:
hookSymbolName = resolved[0]
else:
hookSymbolName = '*%s' % hookSymbolName
self.qtDeclarativeHookDataSymbolName = lambda: hookSymbolName self.qtDeclarativeHookDataSymbolName = lambda: hookSymbolName
return hookSymbolName return hookSymbolName
def qtNamespace(self): def qtNamespace(self):
return '' qstrdupSymbolName = '*qstrdup'
coreModuleName = self.qtCoreModuleName()
if coreModuleName is not None:
qstrdupSymbolName = '%s!%s' % (coreModuleName, qstrdupSymbolName)
resolved = cdbext.resolveSymbol(qstrdupSymbolName)
if not resolved:
return ''
name = resolved[0].split('!')[1]
namespace = name[:name.find(':') + 2] if '::' in name else ''
self.qtNamespace = lambda: namespace
return namespace
def qtVersion(self): def qtVersion(self):
qtVersion = self.findValueByExpression('((void**)&%s)[2]' % self.qtHookDataSymbolName()) qtVersion = self.findValueByExpression('((void**)&%s)[2]' % self.qtHookDataSymbolName())

View File

@@ -97,6 +97,39 @@ static PyObject *cdbext_parseAndEvaluate(PyObject *, PyObject *args) // -> Value
return Py_BuildValue("K", value.I64); return Py_BuildValue("K", value.I64);
} }
static PyObject *cdbext_resolveSymbol(PyObject *, PyObject *args) // -> Value
{
enum { bufSize = 2048 };
char *pattern;
if (!PyArg_ParseTuple(args, "s", &pattern))
Py_RETURN_NONE;
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
auto rc = PyList_New(0);
ULONG64 handle = 0;
// E_NOINTERFACE means "no match". Apparently, it does not always
// set handle.
HRESULT hr = symbols->StartSymbolMatch(pattern, &handle);
if (hr == E_NOINTERFACE || FAILED(hr)) {
if (handle)
symbols->EndSymbolMatch(handle);
return rc;
}
char buf[bufSize];
ULONG64 offset;
while (true) {
hr = symbols->GetNextSymbolMatch(handle, buf, bufSize - 1, 0, &offset);
if (hr == E_NOINTERFACE)
break;
if (hr == S_OK)
PyList_Append(rc, Py_BuildValue("s", buf));
}
symbols->EndSymbolMatch(handle);
return rc;
}
static PyObject *cdbext_lookupType(PyObject *, PyObject *args) // -> Type static PyObject *cdbext_lookupType(PyObject *, PyObject *args) // -> Type
{ {
char *type; char *type;
@@ -290,6 +323,8 @@ static PyObject *cdbext_call(PyObject *, PyObject *args)
static PyMethodDef cdbextMethods[] = { static PyMethodDef cdbextMethods[] = {
{"parseAndEvaluate", cdbext_parseAndEvaluate, METH_VARARGS, {"parseAndEvaluate", cdbext_parseAndEvaluate, METH_VARARGS,
"Returns value of expression or None if the expression can not be resolved"}, "Returns value of expression or None if the expression can not be resolved"},
{"resolveSymbol", cdbext_resolveSymbol, METH_VARARGS,
"Returns a list of symbol names matching the given pattern"},
{"lookupType", cdbext_lookupType, METH_VARARGS, {"lookupType", cdbext_lookupType, METH_VARARGS,
"Returns type object or None if the type can not be resolved"}, "Returns type object or None if the type can not be resolved"},
{"listOfLocals", cdbext_listOfLocals, METH_VARARGS, {"listOfLocals", cdbext_listOfLocals, METH_VARARGS,