forked from qt-creator/qt-creator
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:
@@ -27,6 +27,7 @@ import inspect
|
||||
import os
|
||||
import sys
|
||||
import cdbext
|
||||
import re
|
||||
|
||||
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
|
||||
|
||||
@@ -229,10 +230,18 @@ class Dumper(DumperBase):
|
||||
|
||||
def qtCoreModuleName(self):
|
||||
modules = cdbext.listOfModules()
|
||||
# first check for an exact module name match
|
||||
for coreName in ['Qt5Cored', 'Qt5Core', 'QtCored4', 'QtCore4']:
|
||||
if coreName in modules:
|
||||
self.qtCoreModuleName = lambda: 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
|
||||
|
||||
def qtDeclarativeModuleName(self):
|
||||
@@ -241,13 +250,24 @@ class Dumper(DumperBase):
|
||||
if declarativeModuleName in modules:
|
||||
self.qtDeclarativeModuleName = lambda: 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
|
||||
|
||||
def qtHookDataSymbolName(self):
|
||||
hookSymbolName = 'qtHookData'
|
||||
coreModuleName = self.qtCoreModuleName()
|
||||
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
|
||||
return hookSymbolName
|
||||
|
||||
@@ -255,12 +275,29 @@ class Dumper(DumperBase):
|
||||
hookSymbolName = 'qtDeclarativeHookData'
|
||||
declarativeModuleName = self.qtDeclarativeModuleName()
|
||||
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
|
||||
return hookSymbolName
|
||||
|
||||
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):
|
||||
qtVersion = self.findValueByExpression('((void**)&%s)[2]' % self.qtHookDataSymbolName())
|
||||
|
@@ -97,6 +97,39 @@ static PyObject *cdbext_parseAndEvaluate(PyObject *, PyObject *args) // -> Value
|
||||
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
|
||||
{
|
||||
char *type;
|
||||
@@ -290,6 +323,8 @@ static PyObject *cdbext_call(PyObject *, PyObject *args)
|
||||
static PyMethodDef cdbextMethods[] = {
|
||||
{"parseAndEvaluate", cdbext_parseAndEvaluate, METH_VARARGS,
|
||||
"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,
|
||||
"Returns type object or None if the type can not be resolved"},
|
||||
{"listOfLocals", cdbext_listOfLocals, METH_VARARGS,
|
||||
|
Reference in New Issue
Block a user