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, ¶ms)))
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, ¶ms);
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, ¶ms)))
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, ¶ms)))
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, ¶ms))) {
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, ¶ms))) {
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