1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "pyvalue.h"
27 
28 #include "extensioncontext.h"
29 #include "symbolgroupvalue.h"
30 
31 #include <list>
32 
33 constexpr bool debugPyValue = false;
debuggingValueEnabled()34 constexpr bool debuggingValueEnabled() { return debugPyValue || debugPyCdbextModule; }
35 
36 static std::map<CIDebugSymbolGroup *, std::list<PyValue *>> valuesForSymbolGroup;
37 
indicesMoved(CIDebugSymbolGroup * symbolGroup,ULONG start,ULONG delta)38 void PyValue::indicesMoved(CIDebugSymbolGroup *symbolGroup, ULONG start, ULONG delta)
39 {
40     if (delta == 0)
41         return;
42     ULONG count;
43     if (FAILED(symbolGroup->GetNumberSymbols(&count)))
44         return;
45     if (count <= start)
46         return;
47     for (PyValue *val : valuesForSymbolGroup[symbolGroup]) {
48         if (val->m_index >= start && val->m_index + delta < count)
49             val->m_index += delta;
50     }
51 }
52 
PyValue(unsigned long index,CIDebugSymbolGroup * symbolGroup)53 PyValue::PyValue(unsigned long index, CIDebugSymbolGroup *symbolGroup)
54     : m_index(index)
55     , m_symbolGroup(symbolGroup)
56 {
57     if (m_symbolGroup)
58         valuesForSymbolGroup[symbolGroup].push_back(this);
59 }
60 
PyValue(const PyValue & other)61 PyValue::PyValue(const PyValue &other)
62     : m_index(other.m_index)
63     , m_symbolGroup(other.m_symbolGroup)
64 {
65     if (m_symbolGroup)
66         valuesForSymbolGroup[m_symbolGroup].push_back(this);
67 }
68 
~PyValue()69 PyValue::~PyValue()
70 {
71     if (m_symbolGroup)
72         valuesForSymbolGroup[m_symbolGroup].remove(this);
73 }
74 
name() const75 std::string PyValue::name() const
76 {
77     if (!m_symbolGroup)
78         return std::string();
79     ULONG size = 0;
80     m_symbolGroup->GetSymbolName(m_index, NULL, 0, &size);
81     if (size == 0)
82         return std::string();
83     std::string name(size - 1, '\0');
84     if (FAILED(m_symbolGroup->GetSymbolName(m_index, &name[0], size, &size)))
85         name.clear();
86     return name;
87 }
88 
type()89 PyType PyValue::type()
90 {
91     if (!m_symbolGroup)
92         return PyType();
93     DEBUG_SYMBOL_PARAMETERS params;
94     if (FAILED(m_symbolGroup->GetSymbolParameters(m_index, 1, &params)))
95         return PyType();
96     ULONG size = 0;
97     m_symbolGroup->GetSymbolTypeName(m_index, NULL, 0, &size);
98     std::string typeName;
99     if (size != 0) {
100         typeName = std::string(size - 1, '\0');
101         if (FAILED(m_symbolGroup->GetSymbolTypeName(m_index, &typeName[0], size, NULL)))
102             typeName.clear();
103     }
104     return PyType(params.Module, params.TypeId, typeName, tag());
105 }
106 
bitsize()107 ULONG64 PyValue::bitsize()
108 {
109     if (!m_symbolGroup)
110         return 0;
111     ULONG size;
112     if (FAILED(m_symbolGroup->GetSymbolSize(m_index, &size)))
113         return 0;
114     return size * 8;
115 }
116 
asBytes()117 Bytes PyValue::asBytes()
118 {
119     if (!m_symbolGroup)
120         return Bytes();
121     ULONG64 address = 0;
122     if (FAILED(m_symbolGroup->GetSymbolOffset(m_index, &address)))
123         return Bytes();
124     ULONG size;
125     if (FAILED(m_symbolGroup->GetSymbolSize(m_index, &size)))
126         return Bytes();
127 
128     Bytes bytes(size);
129     unsigned long received;
130     auto data = ExtensionCommandContext::instance()->dataSpaces();
131     if (FAILED(data->ReadVirtual(address, bytes.data(), size, &received)))
132         return Bytes();
133 
134     bytes.resize(received);
135     return bytes;
136 }
137 
address()138 ULONG64 PyValue::address()
139 {
140     ULONG64 address = 0;
141     if (!m_symbolGroup || FAILED(m_symbolGroup->GetSymbolOffset(m_index, &address)))
142         return 0;
143     if (debuggingValueEnabled())
144         DebugPrint() << "Address of " << name() << ": " << std::hex << std::showbase << address;
145     return address;
146 }
147 
childCount()148 int PyValue::childCount()
149 {
150     if (!m_symbolGroup || !expand())
151         return 0;
152     DEBUG_SYMBOL_PARAMETERS params;
153     HRESULT hr = m_symbolGroup->GetSymbolParameters(m_index, 1, &params);
154     return SUCCEEDED(hr) ? params.SubElements : 0;
155 }
156 
hasChildren()157 bool PyValue::hasChildren()
158 {
159     return childCount() != 0;
160 }
161 
expand()162 bool PyValue::expand()
163 {
164     if (!m_symbolGroup)
165         return false;
166     DEBUG_SYMBOL_PARAMETERS params;
167     if (FAILED(m_symbolGroup->GetSymbolParameters(m_index, 1, &params)))
168         return false;
169     if (params.Flags & DEBUG_SYMBOL_EXPANDED)
170         return true;
171     if (FAILED(m_symbolGroup->ExpandSymbol(m_index, TRUE)))
172         return false;
173     if (FAILED(m_symbolGroup->GetSymbolParameters(m_index, 1, &params)))
174         return false;
175     if (params.Flags & DEBUG_SYMBOL_EXPANDED) {
176         if (debuggingValueEnabled())
177             DebugPrint() << "Expanded " << name();
178         indicesMoved(m_symbolGroup, m_index + 1, params.SubElements);
179         return true;
180     }
181     return false;
182 }
183 
nativeDebuggerValue()184 std::string PyValue::nativeDebuggerValue()
185 {
186     if (!m_symbolGroup)
187         std::string();
188     ULONG size = 0;
189 
190     m_symbolGroup->GetSymbolValueText(m_index, NULL, 0, &size);
191     std::string text(size - 1, '\0');
192     if (FAILED(m_symbolGroup->GetSymbolValueText(m_index, &text[0], size, &size)))
193         return std::string();
194     return text;
195 }
196 
isValid()197 int PyValue::isValid()
198 {
199     return m_symbolGroup != nullptr;
200 }
201 
tag()202 int PyValue::tag()
203 {
204     if (!m_symbolGroup)
205         return -1;
206     DEBUG_SYMBOL_ENTRY info;
207     if (FAILED(m_symbolGroup->GetSymbolEntryInformation(m_index, &info)))
208         return -1;
209     return info.Tag;
210 }
211 
childFromName(const std::string & name)212 PyValue PyValue::childFromName(const std::string &name)
213 {
214     const ULONG endIndex = m_index + childCount();
215     for (ULONG childIndex = m_index + 1; childIndex <= endIndex; ++childIndex) {
216         PyValue child(childIndex, m_symbolGroup);
217         if (child.name() == name)
218             return child;
219     }
220     return PyValue();
221 }
222 
pointedToSymbolName(ULONG64 address,const std::string & type)223 std::string pointedToSymbolName(ULONG64 address, const std::string &type)
224 {
225     std::ostringstream str;
226     str << "*(" << type;
227     if (!type.empty() && type.at(type.size() - 1) == '*')
228         str << ' ';
229     str << "*)" << std::showbase << std::hex << address;
230     return str.str();
231 }
232 
childFromField(const PyField & field)233 PyValue PyValue::childFromField(const PyField &field)
234 {
235     if (!m_symbolGroup)
236         return PyValue();
237     ULONG64 childAddress = address();
238     if (!childAddress)
239         return PyValue();
240     childAddress += field.bitpos();
241     const std::string childTypeName = field.type().name();
242     if (childTypeName.empty())
243         return PyValue();
244     const std::string name = pointedToSymbolName(childAddress, childTypeName);
245     ULONG index = DEBUG_ANY_ID;
246     if (FAILED(m_symbolGroup->AddSymbol(name.c_str(), &index)))
247         return PyValue();
248 
249     return PyValue(index, m_symbolGroup);
250 
251 }
252 
currentNumberOfChildren(ULONG index,IDebugSymbolGroup2 * sg)253 ULONG currentNumberOfChildren(ULONG index, IDebugSymbolGroup2 *sg)
254 {
255     DEBUG_SYMBOL_PARAMETERS params;
256     if (SUCCEEDED(sg->GetSymbolParameters(index, 1, &params))) {
257         if (params.Flags & DEBUG_SYMBOL_EXPANDED)
258             return params.SubElements;
259     }
260     return 0;
261 }
262 
currentNumberOfDescendants(ULONG index,IDebugSymbolGroup2 * sg)263 ULONG currentNumberOfDescendants(ULONG index, IDebugSymbolGroup2 *sg)
264 {
265     ULONG descendantCount = currentNumberOfChildren(index, sg);
266     for (ULONG childIndex = index + 1; childIndex <= descendantCount + index; ) {
267         const ULONG childDescendantCount = currentNumberOfDescendants(childIndex, sg);
268         childIndex += childDescendantCount + 1;
269         descendantCount += childDescendantCount;
270     }
271     return descendantCount;
272 }
273 
childFromIndex(int index)274 PyValue PyValue::childFromIndex(int index)
275 {
276     if (childCount() <= index)
277         return PyValue();
278 
279     int offset = index + 1;
280     for (ULONG childIndex = m_index + 1; childIndex < m_index + offset; ) {
281         const ULONG childDescendantCount = ::currentNumberOfDescendants(childIndex, m_symbolGroup);
282         childIndex += childDescendantCount + 1;
283         offset += childDescendantCount;
284     }
285     return PyValue(m_index + offset, m_symbolGroup);
286 }
287 
currentNumberOfDescendants()288 ULONG PyValue::currentNumberOfDescendants()
289 {
290     return ::currentNumberOfDescendants(m_index, m_symbolGroup);
291 }
292 
createValue(ULONG64 address,const PyType & type)293 PyValue PyValue::createValue(ULONG64 address, const PyType &type)
294 {
295     if (debuggingValueEnabled()) {
296         DebugPrint() << "Create Value address: 0x" << std::hex << address
297                      << " type name: " << type.name();
298     }
299 
300     IDebugSymbolGroup2 *symbolGroup = CurrentSymbolGroup::get();
301     if (symbolGroup == nullptr)
302         return PyValue();
303 
304     ULONG numberOfSymbols = 0;
305     symbolGroup->GetNumberSymbols(&numberOfSymbols);
306     ULONG index = 0;
307     for (;index < numberOfSymbols; ++index) {
308         ULONG64 offset;
309         symbolGroup->GetSymbolOffset(index, &offset);
310         if (offset == address) {
311             DEBUG_SYMBOL_PARAMETERS params;
312             if (SUCCEEDED(symbolGroup->GetSymbolParameters(index, 1, &params))) {
313                 if (params.TypeId == type.getTypeId() && params.Module == type.moduleId())
314                     return PyValue(index, symbolGroup);
315             }
316         }
317     }
318 
319     const std::string name = SymbolGroupValue::pointedToSymbolName(address, type.name(true));
320     if (debuggingValueEnabled())
321         DebugPrint() << "Create Value expression: " << name;
322 
323     index = DEBUG_ANY_ID;
324     if (FAILED(symbolGroup->AddSymbol(name.c_str(), &index)))
325         return PyValue();
326 
327     return PyValue(index, symbolGroup);
328 }
329 
tag(const std::string & typeName)330 int PyValue::tag(const std::string &typeName)
331 {
332     CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
333     IDebugSymbolGroup2 *sg = 0;
334     if (FAILED(symbols->CreateSymbolGroup2(&sg)))
335         return -1;
336 
337     int tag = -1;
338     const std::string name = SymbolGroupValue::pointedToSymbolName(0, typeName);
339     ULONG index = DEBUG_ANY_ID;
340     if (SUCCEEDED(sg->AddSymbol(name.c_str(), &index)))
341         tag = PyValue(index, sg).tag();
342 
343     sg->Release();
344     return tag;
345 }
346 
347 // Python interface implementation
348 
349 namespace PyValueInterface {
350 #define PY_OBJ_NAME ValuePythonObject
351 PY_NEW_FUNC(PY_OBJ_NAME)
PY_DEALLOC_FUNC(PY_OBJ_NAME)352 PY_DEALLOC_FUNC(PY_OBJ_NAME)
353 PY_FUNC_RET_STD_STRING(name, PY_OBJ_NAME)
354 PY_FUNC_RET_OBJECT(type, PY_OBJ_NAME)
355 PY_FUNC(bitsize, PY_OBJ_NAME, "K")
356 PY_FUNC_RET_BYTES(asBytes, PY_OBJ_NAME)
357 PY_FUNC(address, PY_OBJ_NAME, "K")
358 PY_FUNC_RET_BOOL(hasChildren, PY_OBJ_NAME)
359 PY_FUNC_RET_BOOL(expand, PY_OBJ_NAME)
360 PY_FUNC_RET_STD_STRING(nativeDebuggerValue, PY_OBJ_NAME)
361 PY_FUNC_DECL_WITH_ARGS(childFromName, PY_OBJ_NAME)
362 {
363     PY_IMPL_GUARD;
364     char *name;
365     if (!PyArg_ParseTuple(args, "s", &name))
366         Py_RETURN_NONE;
367     return createPythonObject(self->impl->childFromName(name));
368 }
PY_FUNC_DECL_WITH_ARGS(childFromField,PY_OBJ_NAME)369 PY_FUNC_DECL_WITH_ARGS(childFromField, PY_OBJ_NAME)
370 {
371     PY_IMPL_GUARD;
372     FieldPythonObject *field;
373     if (!PyArg_ParseTuple(args, "O", &field))
374         Py_RETURN_NONE;
375     return createPythonObject(self->impl->childFromField(*(field->impl)));
376 }
PY_FUNC_DECL_WITH_ARGS(childFromIndex,PY_OBJ_NAME)377 PY_FUNC_DECL_WITH_ARGS(childFromIndex, PY_OBJ_NAME)
378 {
379     PY_IMPL_GUARD;
380     unsigned int index;
381     if (!PyArg_ParseTuple(args, "I", &index))
382         Py_RETURN_NONE;
383     return createPythonObject(self->impl->childFromIndex(index));
384 }
385 static PyMethodDef valueMethods[] = {
386     {"name",                PyCFunction(name),                  METH_NOARGS,
387      "Name of this thing or None"},
388     {"type",                PyCFunction(type),                  METH_NOARGS,
389      "Type of this value"},
390     {"bitsize",             PyCFunction(bitsize),               METH_NOARGS,
391      "Return the size of the value in bits"},
392     {"asBytes",             PyCFunction(asBytes),               METH_NOARGS,
393      "Memory contents of this object, or None"},
394     {"address",             PyCFunction(address),               METH_NOARGS,
395      "Address of this object, or None"},
396     {"hasChildren",         PyCFunction(hasChildren),           METH_NOARGS,
397      "Whether this object has subobjects"},
398     {"expand",              PyCFunction(expand),                METH_NOARGS,
399      "Make sure that children are accessible."},
400     {"nativeDebuggerValue", PyCFunction(nativeDebuggerValue),   METH_NOARGS,
401      "Value string returned by the debugger"},
402 
403     {"childFromName",   PyCFunction(childFromName),             METH_VARARGS,
404      "Return the name of this value"},
405     {"childFromField",  PyCFunction(childFromField),            METH_VARARGS,
406      "Return the name of this value"},
407     {"childFromIndex",  PyCFunction(childFromIndex),            METH_VARARGS,
408      "Return the name of this value"},
409 
410     {NULL}  /* Sentinel */
411 };
412 } // namespace PyValueInterface
413 
414 
value_pytype()415 PyTypeObject *value_pytype()
416 {
417     static PyTypeObject cdbext_ValueType =
418     {
419         PyVarObject_HEAD_INIT(NULL, 0)
420         "cdbext.Value",                             /* tp_name */
421         sizeof(ValuePythonObject),                  /* tp_basicsize */
422         0,
423         (destructor)PyValueInterface::dealloc,      /* tp_dealloc */
424         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
425         Py_TPFLAGS_DEFAULT,                         /* tp_flags */
426         "Value objects",                            /* tp_doc */
427         0, 0, 0, 0, 0, 0,
428         PyValueInterface::valueMethods,             /* tp_methods */
429         0, 0, 0, 0, 0, 0, 0, 0, 0,
430         PyValueInterface::newObject,                /* tp_new */
431     };
432 
433     return &cdbext_ValueType;
434 }
435 
createPythonObject(PyValue implClass)436 PyObject *createPythonObject(PyValue implClass)
437 {
438     if (!implClass.isValid())
439         Py_RETURN_NONE;
440     ValuePythonObject *newPyValue = PyObject_New(ValuePythonObject, value_pytype());
441     newPyValue->impl = new PyValue(implClass);
442     return reinterpret_cast<PyObject *>(newPyValue);
443 }
444