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 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):
|
||||||
|
qstrdupSymbolName = '*qstrdup'
|
||||||
|
coreModuleName = self.qtCoreModuleName()
|
||||||
|
if coreModuleName is not None:
|
||||||
|
qstrdupSymbolName = '%s!%s' % (coreModuleName, qstrdupSymbolName)
|
||||||
|
resolved = cdbext.resolveSymbol(qstrdupSymbolName)
|
||||||
|
if not resolved:
|
||||||
return ''
|
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())
|
||||||
|
@@ -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,
|
||||||
|
Reference in New Issue
Block a user