1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "symbolgroup.h"
35 #include "stringutils.h"
36 #include "gdbmihelpers.h"
43 typedef std::vector<int>::size_type VectorIndexType;
44 typedef std::vector<std::string> StringVector;
47 const char rootNameC[] = "local";
49 // ------------- SymbolGroup
50 SymbolGroup::SymbolGroup(IDebugSymbolGroup2 *sg,
51 const SymbolParameterVector &vec,
54 const std::string &function) :
61 m_root = SymbolGroupNode::create(this, rootNameC, vec);
62 // Split function 'Mod!foo'
63 const std::string::size_type exclPos = m_function.find('!');
64 if (exclPos != std::string::npos) {
65 m_module = m_function.substr(0, exclPos);
66 m_function.erase(0, exclPos + 1);
70 SymbolGroup::~SymbolGroup()
72 m_symbolGroup->Release();
76 static inline bool getSymbolCount(CIDebugSymbolGroup *symbolGroup,
78 std::string *errorMessage)
80 const HRESULT hr = symbolGroup->GetNumberSymbols(count);
82 *errorMessage = msgDebugEngineComFailed("GetNumberSymbols", hr);
88 bool SymbolGroup::getSymbolParameters(CIDebugSymbolGroup *symbolGroup,
89 SymbolParameterVector *vec,
90 std::string *errorMessage)
93 return getSymbolCount(symbolGroup, &count, errorMessage)
94 && getSymbolParameters(symbolGroup, 0, count, vec, errorMessage);
97 bool SymbolGroup::getSymbolParameters(CIDebugSymbolGroup *symbolGroup,
100 SymbolParameterVector *vec,
101 std::string *errorMessage)
107 // Trim the count to the maximum count available. When expanding elements
108 // and passing SubElements as count, SubElements might be an estimate that
109 // is too large and triggers errors.
111 if (!getSymbolCount(symbolGroup, &totalCount, errorMessage))
113 if (start >= totalCount) {
114 std::ostringstream str;
115 str << "SymbolGroup::getSymbolParameters: Start parameter "
116 << start << " beyond total " << totalCount << '.';
117 *errorMessage = str.str();
120 if (start + count > totalCount)
121 count = totalCount - start;
124 const HRESULT hr = symbolGroup->GetSymbolParameters(start, count, &(*vec->begin()));
126 std::ostringstream str;
127 str << "SymbolGroup::getSymbolParameters failed for index=" << start << ", count=" << count
128 << ": " << msgDebugEngineComFailed("GetSymbolParameters", hr);
129 *errorMessage = str.str();
135 SymbolGroup *SymbolGroup::create(CIDebugControl *control, CIDebugSymbols *debugSymbols,
136 ULONG threadId, unsigned frame,
137 std::string *errorMessage)
139 errorMessage->clear();
141 ULONG obtainedFrameCount = 0;
142 const ULONG frameCount = frame + 1;
144 DEBUG_STACK_FRAME *frames = new DEBUG_STACK_FRAME[frameCount];
145 IDebugSymbolGroup2 *idebugSymbols = 0;
146 bool success = false;
147 SymbolParameterVector parameters;
150 // Obtain symbol group at stack frame.
152 HRESULT hr = control->GetStackTrace(0, 0, 0, frames, frameCount, &obtainedFrameCount);
154 *errorMessage = msgDebugEngineComFailed("GetStackTrace", hr);
157 if (obtainedFrameCount < frameCount ) {
158 std::ostringstream str;
159 str << "Unable to obtain frame " << frame << " (" << obtainedFrameCount << ").";
160 *errorMessage = str.str();
163 StackFrame frameData;
164 if (!getFrame(frame, &frameData, errorMessage))
166 func = wStringToString(frameData.function);
168 hr = debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &idebugSymbols);
170 *errorMessage = msgDebugEngineComFailed("GetScopeSymbolGroup2", hr);
173 hr = debugSymbols->SetScope(0, frames + frame, NULL, 0);
175 *errorMessage = msgDebugEngineComFailed("SetScope", hr);
178 // refresh with current frame
179 hr = debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, idebugSymbols, &idebugSymbols);
181 *errorMessage = msgDebugEngineComFailed("GetScopeSymbolGroup2", hr);
184 if (!SymbolGroup::getSymbolParameters(idebugSymbols, ¶meters, errorMessage))
192 idebugSymbols->Release();
195 return new SymbolGroup(idebugSymbols, parameters, threadId, frame, func);
198 static inline std::string msgNotFound(const std::string &nodeName)
200 std::ostringstream str;
201 str << "Node '" << nodeName << "' not found.";
205 std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx,
206 const DumpParameters &p) const
209 if (symbolGroupDebug)
210 DebugPrint() << "<SymbolGroup::dump()";
211 std::ostringstream str;
212 DumpSymbolGroupNodeVisitor visitor(str, ctx, p);
213 if (p.humanReadable())
219 if (symbolGroupDebug)
220 DebugPrint() << "<SymbolGroup::dump()";
224 // Dump a node, potentially expand
225 std::string SymbolGroup::dump(const std::string &iname,
226 const SymbolGroupValueContext &ctx,
227 const DumpParameters &p,
228 std::string *errorMessage)
230 if (symbolGroupDebug)
231 DebugPrint() << ">SymbolGroup::dump(" << iname << ")";
233 AbstractSymbolGroupNode *const aNode = find(iname);
235 *errorMessage = msgNotFound(iname);
236 return std::string();
239 // Real nodes: Expand and complex dumpers
240 if (SymbolGroupNode *node = aNode->resolveReference()->asSymbolGroupNode()) {
241 if (symbolGroupDebug)
242 DebugPrint() << "SymbolGroup::dump(" << iname << '/'
243 << aNode->absoluteFullIName() <<" resolves to " << node->absoluteFullIName()
244 << " expanded=" << node->isExpanded();
245 if (node->isExpanded()) { // Mark expand request by watch model
246 node->clearFlags(SymbolGroupNode::ExpandedByDumper);
248 if (node->canExpand() && !node->expand(errorMessage))
251 // After expansion, run the complex dumpers
252 if (p.dumpFlags & DumpParameters::DumpComplexDumpers)
253 node->runComplexDumpers(ctx);
254 if (symbolGroupDebug)
255 DebugPrint() << "SymbolGroup::dump(" << iname << ") ran complex dumpers 0x" << std::hex << node->flags();
258 std::ostringstream str;
259 if (p.humanReadable())
261 DumpSymbolGroupNodeVisitor visitor(str, ctx, p);
263 aNode->accept(visitor, SymbolGroupNodeVisitor::parentIname(iname), 0, 0);
266 if (symbolGroupDebug)
267 DebugPrint() << "<SymbolGroup::dump(" << iname << ')';
271 std::string SymbolGroup::debug(const std::string &iname,
272 const std::string &filter,
273 unsigned verbosity) const
275 std::ostringstream str;
277 std::auto_ptr<DebugSymbolGroupNodeVisitor>
278 visitor(filter.empty() ?
279 new DebugSymbolGroupNodeVisitor(str, verbosity) :
280 new DebugFilterSymbolGroupNodeVisitor(str, filter, verbosity));
284 if (AbstractSymbolGroupNode *const node = find(iname)) {
285 node->accept(*visitor, SymbolGroupNodeVisitor::parentIname(iname), 0, 0);
287 str << msgNotFound(iname);
293 /* expandList: Expand a list of inames with a 'mkdir -p'-like behaviour, that is,
294 * expand all sub-paths. The list of inames has thus to be reordered to expand the
295 * parent items first, for example "locals.this.i1.data,locals.this.i2" --->:
296 * "locals, locals.this, locals.this.i1, locals.this.i2, locals.this.i1.data".
297 * This is done here by creating a set of name parts keyed by level and name
298 * (thus purging duplicates). */
300 typedef std::pair<unsigned, std::string> InamePathEntry;
302 struct InamePathEntryLessThan : public std::binary_function<InamePathEntry, InamePathEntry, bool> {
303 bool operator()(const InamePathEntry &i1, const InamePathEntry& i2) const
305 if (i1.first < i2.first)
307 if (i1.first != i2.first)
309 return i1.second < i2.second;
313 typedef std::set<InamePathEntry, InamePathEntryLessThan> InamePathEntrySet;
315 static inline InamePathEntrySet expandEntrySet(const std::vector<std::string> &nodes)
317 InamePathEntrySet pathEntries;
318 const VectorIndexType nodeCount = nodes.size();
319 for (VectorIndexType i= 0; i < nodeCount; i++) {
320 const std::string &iname = nodes.at(i);
321 std::string::size_type pos = 0;
322 // Split a path 'local.foo' and insert (0,'local'), (1,'local.foo') (see above)
323 for (unsigned level = 0; pos < iname.size(); level++) {
324 std::string::size_type dotPos = iname.find(SymbolGroupNodeVisitor::iNamePathSeparator, pos);
325 if (dotPos == std::string::npos)
326 dotPos = iname.size();
327 pathEntries.insert(InamePathEntry(level, iname.substr(0, dotPos)));
334 // Expand a node list "locals.i1,locals.i2"
335 unsigned SymbolGroup::expandList(const std::vector<std::string> &nodes, std::string *errorMessage)
337 if (symbolGroupDebug)
338 DebugPrint() << ">SymbolGroup::expandList" << nodes.size();
341 // Create a set with a key <level, name>. Also required for 1 node (see above).
342 const InamePathEntrySet pathEntries = expandEntrySet(nodes);
343 // Now expand going by level.
344 unsigned succeeded = 0;
345 std::string nodeError;
346 InamePathEntrySet::const_iterator cend = pathEntries.end();
347 for (InamePathEntrySet::const_iterator it = pathEntries.begin(); it != cend; ++it)
348 if (expand(it->second, &nodeError)) {
351 if (!errorMessage->empty())
352 errorMessage->append(", ");
353 errorMessage->append(nodeError);
355 if (symbolGroupDebug)
356 DebugPrint() << "<SymbolGroup::expandList returns " << succeeded;
360 unsigned SymbolGroup::expandListRunComplexDumpers(const std::vector<std::string> &nodes,
361 const SymbolGroupValueContext &ctx,
362 std::string *errorMessage)
364 if (symbolGroupDebug)
365 DebugPrint() << ">SymbolGroup::expandListRunComplexDumpers" << nodes.size();
369 // Create a set with a key <level, name>. Also required for 1 node (see above).
370 const InamePathEntrySet pathEntries = expandEntrySet(nodes);
371 // Now expand going by level.
372 unsigned succeeded = 0;
373 std::string nodeError;
374 InamePathEntrySet::const_iterator cend = pathEntries.end();
375 for (InamePathEntrySet::const_iterator it = pathEntries.begin(); it != cend; ++it)
376 if (expandRunComplexDumpers(it->second, ctx, &nodeError)) {
379 if (!errorMessage->empty())
380 errorMessage->append(", ");
381 errorMessage->append(nodeError);
384 if (symbolGroupDebug)
385 DebugPrint() << "<SymbolGroup::expandListRunComplexDumpers returns " << succeeded;
389 // Find a node for expansion, skipping reference nodes.
390 static inline SymbolGroupNode *
391 findNodeForExpansion(const SymbolGroup *sg,
392 const std::string &nodeName,
393 std::string *errorMessage)
395 AbstractSymbolGroupNode *aNode = sg->find(nodeName);
397 *errorMessage = msgNotFound(nodeName);
401 SymbolGroupNode *node = aNode->resolveReference()->asSymbolGroupNode();
403 *errorMessage = "Node type error in expand: " + nodeName;
409 bool SymbolGroup::expand(const std::string &nodeName, std::string *errorMessage)
411 if (SymbolGroupNode *node = findNodeForExpansion(this, nodeName, errorMessage))
412 return node == m_root ? true : node->expand(errorMessage);
416 bool SymbolGroup::expandRunComplexDumpers(const std::string &nodeName, const SymbolGroupValueContext &ctx, std::string *errorMessage)
418 if (SymbolGroupNode *node = findNodeForExpansion(this, nodeName, errorMessage))
419 return node == m_root ? true : node->expandRunComplexDumpers(ctx, errorMessage);
423 // Cast an (unexpanded) node
424 bool SymbolGroup::typeCast(const std::string &iname, const std::string &desiredType, std::string *errorMessage)
426 AbstractSymbolGroupNode *aNode = find(iname);
428 *errorMessage = msgNotFound(iname);
431 if (aNode == m_root) {
432 *errorMessage = "Cannot cast root node";
435 SymbolGroupNode *node = aNode->asSymbolGroupNode();
437 *errorMessage = "Node type error in typeCast: " + iname;
440 return node->typeCast(desiredType, errorMessage);
443 SymbolGroupNode *SymbolGroup::addSymbol(const std::string &name, const std::string &iname, std::string *errorMessage)
445 return m_root->addSymbolByName(name, iname, errorMessage);
448 // Mark uninitialized (top level only)
449 void SymbolGroup::markUninitialized(const std::vector<std::string> &uniniNodes)
451 if (m_root && !m_root->children().empty() && !uniniNodes.empty()) {
452 const std::vector<std::string>::const_iterator unIniNodesBegin = uniniNodes.begin();
453 const std::vector<std::string>::const_iterator unIniNodesEnd = uniniNodes.end();
455 const AbstractSymbolGroupNodePtrVector::const_iterator childrenEnd = m_root->children().end();
456 for (AbstractSymbolGroupNodePtrVector::const_iterator it = m_root->children().begin(); it != childrenEnd; ++it) {
457 if (std::find(unIniNodesBegin, unIniNodesEnd, (*it)->absoluteFullIName()) != unIniNodesEnd)
458 (*it)->addFlags(SymbolGroupNode::Uninitialized);
463 static inline std::string msgAssignError(const std::string &nodeName,
464 const std::string &value,
465 const std::string &why)
467 std::ostringstream str;
468 str << "Unable to assign '" << value << "' to '" << nodeName << "': " << why;
472 bool SymbolGroup::assign(const std::string &nodeName, const std::string &value,
473 std::string *errorMessage)
475 AbstractSymbolGroupNode *aNode = find(nodeName);
477 *errorMessage = msgAssignError(nodeName, value, "No such node");
480 SymbolGroupNode *node = aNode->asSymbolGroupNode();
482 *errorMessage = msgAssignError(nodeName, value, "Invalid node type");
486 const HRESULT hr = m_symbolGroup->WriteSymbol(node->index(), const_cast<char *>(value.c_str()));
488 *errorMessage = msgAssignError(nodeName, value, msgDebugEngineComFailed("WriteSymbol", hr));
494 bool SymbolGroup::accept(SymbolGroupNodeVisitor &visitor) const
496 if (!m_root || m_root->children().empty())
498 return m_root->accept(visitor, std::string(), 0, 0);
501 // Find "locals.this.i1" and move index recursively
502 static AbstractSymbolGroupNode *findNodeRecursion(const std::vector<std::string> &iname,
504 std::vector<AbstractSymbolGroupNode *> nodes)
506 typedef std::vector<AbstractSymbolGroupNode *>::const_iterator ConstIt;
509 DebugPrint() <<"findNodeRecursion: Looking for " << iname.back() << " (" << iname.size()
510 << "),depth=" << depth << ",matching=" << iname.at(depth) << " in " << nodes.size();
515 // Find the child that matches the iname part at depth
516 const ConstIt cend = nodes.end();
517 for (ConstIt it = nodes.begin(); it != cend; ++it) {
518 AbstractSymbolGroupNode *c = *it;
519 if (c->iName() == iname.at(depth)) {
520 if (depth == iname.size() - 1) { // Complete iname matched->happy.
523 // Sub-part of iname matched. Forward index and check children.
524 return findNodeRecursion(iname, depth + 1, c->children());
531 AbstractSymbolGroupNode *SymbolGroup::findI(const std::string &iname) const
535 // Match the root element only: Shouldn't happen, still, all happy
536 if (iname == m_root->name())
539 std::vector<std::string> inameTokens;
540 split(iname, SymbolGroupNodeVisitor::iNamePathSeparator, std::back_inserter(inameTokens));
542 // Must begin with root
543 if (inameTokens.front() != m_root->name())
546 // Start with index = 0 at root's children
547 return findNodeRecursion(inameTokens, 1, m_root->children());
550 AbstractSymbolGroupNode *SymbolGroup::find(const std::string &iname) const
552 AbstractSymbolGroupNode *rc = findI(iname);
554 DebugPrint() << "SymbolGroup::find " << iname << ' ' << rc;