OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / libs / qtcreatorcdbext / symbolgroup.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
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.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "symbolgroup.h"
35 #include "stringutils.h"
36 #include "gdbmihelpers.h"
37
38 #include <set>
39 #include <algorithm>
40 #include <iterator>
41 #include <memory>
42
43 typedef std::vector<int>::size_type VectorIndexType;
44 typedef std::vector<std::string> StringVector;
45
46 enum { debug = 0 };
47 const char rootNameC[] = "local";
48
49 // ------------- SymbolGroup
50 SymbolGroup::SymbolGroup(IDebugSymbolGroup2 *sg,
51                          const SymbolParameterVector &vec,
52                          ULONG threadId,
53                          unsigned frame,
54                          const std::string &function) :
55     m_symbolGroup(sg),
56     m_threadId(threadId),
57     m_frame(frame),
58     m_root(0),
59     m_function(function)
60 {
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);
67     }
68 }
69
70 SymbolGroup::~SymbolGroup()
71 {
72     m_symbolGroup->Release();
73     delete m_root;
74 }
75
76 static inline bool getSymbolCount(CIDebugSymbolGroup *symbolGroup,
77                                   ULONG *count,
78                                   std::string *errorMessage)
79 {
80     const HRESULT hr = symbolGroup->GetNumberSymbols(count);
81     if (FAILED(hr)) {
82         *errorMessage = msgDebugEngineComFailed("GetNumberSymbols", hr);
83         return false;
84     }
85     return true;
86 }
87
88 bool SymbolGroup::getSymbolParameters(CIDebugSymbolGroup *symbolGroup,
89                                       SymbolParameterVector *vec,
90                                       std::string *errorMessage)
91 {
92     ULONG count;
93     return getSymbolCount(symbolGroup, &count, errorMessage)
94             && getSymbolParameters(symbolGroup, 0, count, vec, errorMessage);
95 }
96
97 bool SymbolGroup::getSymbolParameters(CIDebugSymbolGroup *symbolGroup,
98                                       unsigned long start,
99                                       unsigned long count,
100                                       SymbolParameterVector *vec,
101                                       std::string *errorMessage)
102 {
103     if (!count) {
104         vec->clear();
105         return true;
106     }
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.
110     ULONG totalCount;
111     if (!getSymbolCount(symbolGroup, &totalCount, errorMessage))
112         return false;
113     if (start >= totalCount) {
114         std::ostringstream str;
115         str << "SymbolGroup::getSymbolParameters: Start parameter "
116             << start << " beyond total " << totalCount << '.';
117         *errorMessage = str.str();
118         return  false;
119     }
120     if (start + count > totalCount)
121         count = totalCount - start;
122     // Get parameters.
123     vec->resize(count);
124     const HRESULT hr = symbolGroup->GetSymbolParameters(start, count, &(*vec->begin()));
125     if (FAILED(hr)) {
126         std::ostringstream str;
127         str << "SymbolGroup::getSymbolParameters failed for index=" << start << ", count=" << count
128             << ": " << msgDebugEngineComFailed("GetSymbolParameters", hr);
129         *errorMessage = str.str();
130         return false;
131     }
132     return true;
133 }
134
135 SymbolGroup *SymbolGroup::create(CIDebugControl *control, CIDebugSymbols *debugSymbols,
136                                  ULONG threadId, unsigned frame,
137                                  std::string *errorMessage)
138 {
139     errorMessage->clear();
140
141     ULONG obtainedFrameCount = 0;
142     const ULONG frameCount = frame + 1;
143
144     DEBUG_STACK_FRAME *frames = new DEBUG_STACK_FRAME[frameCount];
145     IDebugSymbolGroup2 *idebugSymbols = 0;
146     bool success = false;
147     SymbolParameterVector parameters;
148     std::string func;
149
150     // Obtain symbol group at stack frame.
151     do {
152         HRESULT hr = control->GetStackTrace(0, 0, 0, frames, frameCount, &obtainedFrameCount);
153         if (FAILED(hr)) {
154             *errorMessage = msgDebugEngineComFailed("GetStackTrace", hr);
155             break;
156         }
157         if (obtainedFrameCount < frameCount ) {
158             std::ostringstream str;
159             str << "Unable to obtain frame " << frame << " (" << obtainedFrameCount << ").";
160             *errorMessage = str.str();
161             break;
162         }
163         StackFrame frameData;
164         if (!getFrame(frame, &frameData, errorMessage))
165             break;
166         func = wStringToString(frameData.function);
167
168         hr = debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &idebugSymbols);
169         if (FAILED(hr)) {
170             *errorMessage = msgDebugEngineComFailed("GetScopeSymbolGroup2", hr);
171             break;
172         }
173         hr = debugSymbols->SetScope(0, frames + frame, NULL, 0);
174         if (FAILED(hr)) {
175             *errorMessage = msgDebugEngineComFailed("SetScope", hr);
176             break;
177         }
178         // refresh with current frame
179         hr = debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, idebugSymbols, &idebugSymbols);
180         if (FAILED(hr)) {
181             *errorMessage = msgDebugEngineComFailed("GetScopeSymbolGroup2", hr);
182             break;
183         }
184         if (!SymbolGroup::getSymbolParameters(idebugSymbols, &parameters, errorMessage))
185             break;
186
187         success = true;
188     } while (false);
189     delete [] frames;
190     if (!success) {
191         if (idebugSymbols)
192             idebugSymbols->Release();
193         return 0;
194     }
195     return new SymbolGroup(idebugSymbols, parameters, threadId, frame, func);
196 }
197
198 static inline std::string msgNotFound(const std::string &nodeName)
199 {
200     std::ostringstream str;
201     str << "Node '" << nodeName << "' not found.";
202     return str.str();
203 }
204
205 std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx,
206                               const DumpParameters &p) const
207 {
208     QTC_TRACE_IN
209     if (symbolGroupDebug)
210         DebugPrint() << "<SymbolGroup::dump()";
211     std::ostringstream str;
212     DumpSymbolGroupNodeVisitor visitor(str, ctx, p);
213     if (p.humanReadable())
214         str << '\n';
215     str << '[';
216     accept(visitor);
217     str << ']';
218     QTC_TRACE_OUT
219     if (symbolGroupDebug)
220         DebugPrint() << "<SymbolGroup::dump()";
221     return str.str();
222 }
223
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)
229 {
230     if (symbolGroupDebug)
231         DebugPrint() << ">SymbolGroup::dump(" << iname << ")";
232     QTC_TRACE_IN
233     AbstractSymbolGroupNode *const aNode = find(iname);
234     if (!aNode) {
235         *errorMessage = msgNotFound(iname);
236         return std::string();
237     }
238
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);
247         } else {
248             if (node->canExpand() && !node->expand(errorMessage))
249                 return false;
250         }
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();
256     }
257
258     std::ostringstream str;
259     if (p.humanReadable())
260         str << '\n';
261     DumpSymbolGroupNodeVisitor visitor(str, ctx, p);
262     str << '[';
263     aNode->accept(visitor, SymbolGroupNodeVisitor::parentIname(iname), 0, 0);
264     str << ']';
265     QTC_TRACE_OUT
266     if (symbolGroupDebug)
267             DebugPrint() << "<SymbolGroup::dump(" << iname << ')';
268     return str.str();
269 }
270
271 std::string SymbolGroup::debug(const std::string &iname,
272                                const std::string &filter,
273                                unsigned verbosity) const
274 {
275     std::ostringstream str;
276     str << '\n';
277     std::auto_ptr<DebugSymbolGroupNodeVisitor>
278             visitor(filter.empty() ?
279             new DebugSymbolGroupNodeVisitor(str, verbosity) :
280             new DebugFilterSymbolGroupNodeVisitor(str, filter, verbosity));
281     if (iname.empty()) {
282         accept(*visitor);
283     } else {
284         if (AbstractSymbolGroupNode *const node = find(iname)) {
285             node->accept(*visitor, SymbolGroupNodeVisitor::parentIname(iname), 0, 0);
286         } else {
287             str << msgNotFound(iname);
288         }
289     }
290     return str.str();
291 }
292
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). */
299
300 typedef std::pair<unsigned, std::string> InamePathEntry;
301
302 struct InamePathEntryLessThan : public std::binary_function<InamePathEntry, InamePathEntry, bool> {
303     bool operator()(const InamePathEntry &i1, const InamePathEntry& i2) const
304     {
305         if (i1.first < i2.first)
306             return true;
307         if (i1.first != i2.first)
308             return false;
309         return i1.second < i2.second;
310     }
311 };
312
313 typedef std::set<InamePathEntry, InamePathEntryLessThan> InamePathEntrySet;
314
315 static inline InamePathEntrySet expandEntrySet(const std::vector<std::string> &nodes)
316 {
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)));
328             pos = dotPos + 1;
329         }
330     }
331     return pathEntries;
332 }
333
334 // Expand a node list "locals.i1,locals.i2"
335 unsigned SymbolGroup::expandList(const std::vector<std::string> &nodes, std::string *errorMessage)
336 {
337     if (symbolGroupDebug)
338         DebugPrint() << ">SymbolGroup::expandList" << nodes.size();
339     if (nodes.empty())
340         return 0;
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)) {
349             succeeded++;
350         } else {
351             if (!errorMessage->empty())
352                 errorMessage->append(", ");
353             errorMessage->append(nodeError);
354         }
355     if (symbolGroupDebug)
356         DebugPrint() << "<SymbolGroup::expandList returns " << succeeded;
357     return succeeded;
358 }
359
360 unsigned SymbolGroup::expandListRunComplexDumpers(const std::vector<std::string> &nodes,
361                                      const SymbolGroupValueContext &ctx,
362                                      std::string *errorMessage)
363 {
364     if (symbolGroupDebug)
365         DebugPrint() << ">SymbolGroup::expandListRunComplexDumpers" << nodes.size();
366     QTC_TRACE_IN
367     if (nodes.empty())
368         return 0;
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)) {
377             succeeded++;
378         } else {
379             if (!errorMessage->empty())
380                 errorMessage->append(", ");
381             errorMessage->append(nodeError);
382         }
383     QTC_TRACE_OUT
384     if (symbolGroupDebug)
385             DebugPrint() << "<SymbolGroup::expandListRunComplexDumpers returns " << succeeded;
386     return succeeded;
387 }
388
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)
394 {
395     AbstractSymbolGroupNode *aNode = sg->find(nodeName);
396     if (!aNode) {
397         *errorMessage = msgNotFound(nodeName);
398         return 0;
399     }
400
401     SymbolGroupNode *node = aNode->resolveReference()->asSymbolGroupNode();
402     if (!node) {
403         *errorMessage = "Node type error in expand: " + nodeName;
404         return 0;
405     }
406     return node;
407 }
408
409 bool SymbolGroup::expand(const std::string &nodeName, std::string *errorMessage)
410 {
411     if (SymbolGroupNode *node = findNodeForExpansion(this, nodeName, errorMessage))
412         return node == m_root ? true : node->expand(errorMessage);
413     return false;
414 }
415
416 bool SymbolGroup::expandRunComplexDumpers(const std::string &nodeName, const SymbolGroupValueContext &ctx, std::string *errorMessage)
417 {
418     if (SymbolGroupNode *node = findNodeForExpansion(this, nodeName, errorMessage))
419         return node == m_root ? true : node->expandRunComplexDumpers(ctx, errorMessage);
420     return false;
421 }
422
423 // Cast an (unexpanded) node
424 bool SymbolGroup::typeCast(const std::string &iname, const std::string &desiredType, std::string *errorMessage)
425 {
426     AbstractSymbolGroupNode *aNode = find(iname);
427     if (!aNode) {
428         *errorMessage = msgNotFound(iname);
429         return false;
430     }
431     if (aNode == m_root) {
432         *errorMessage = "Cannot cast root node";
433         return false;
434     }
435     SymbolGroupNode *node = aNode->asSymbolGroupNode();
436     if (!node) {
437         *errorMessage = "Node type error in typeCast: " + iname;
438         return false;
439     }
440     return node->typeCast(desiredType, errorMessage);
441 }
442
443 SymbolGroupNode *SymbolGroup::addSymbol(const std::string &name, const std::string &iname, std::string *errorMessage)
444 {
445     return m_root->addSymbolByName(name, iname, errorMessage);
446 }
447
448 // Mark uninitialized (top level only)
449 void SymbolGroup::markUninitialized(const std::vector<std::string> &uniniNodes)
450 {
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();
454
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);
459         }
460     }
461 }
462
463 static inline std::string msgAssignError(const std::string &nodeName,
464                                          const std::string &value,
465                                          const std::string &why)
466 {
467     std::ostringstream str;
468     str << "Unable to assign '" << value << "' to '" << nodeName << "': " << why;
469     return str.str();
470 }
471
472 bool SymbolGroup::assign(const std::string &nodeName, const std::string &value,
473                          std::string *errorMessage)
474 {
475     AbstractSymbolGroupNode *aNode = find(nodeName);
476     if (aNode == 0) {
477         *errorMessage = msgAssignError(nodeName, value, "No such node");
478         return false;
479     }
480     SymbolGroupNode *node = aNode->asSymbolGroupNode();
481     if (node == 0) {
482         *errorMessage = msgAssignError(nodeName, value, "Invalid node type");
483         return false;
484     }
485
486     const HRESULT hr = m_symbolGroup->WriteSymbol(node->index(), const_cast<char *>(value.c_str()));
487     if (FAILED(hr)) {
488         *errorMessage = msgAssignError(nodeName, value, msgDebugEngineComFailed("WriteSymbol", hr));
489         return false;
490     }
491     return true;
492 }
493
494 bool SymbolGroup::accept(SymbolGroupNodeVisitor &visitor) const
495 {
496     if (!m_root || m_root->children().empty())
497         return false;
498     return m_root->accept(visitor, std::string(), 0, 0);
499 }
500
501 // Find  "locals.this.i1" and move index recursively
502 static AbstractSymbolGroupNode *findNodeRecursion(const std::vector<std::string> &iname,
503                                                   unsigned depth,
504                                                   std::vector<AbstractSymbolGroupNode *> nodes)
505 {
506     typedef std::vector<AbstractSymbolGroupNode *>::const_iterator ConstIt;
507
508     if (debug > 1) {
509         DebugPrint() <<"findNodeRecursion: Looking for " << iname.back() << " (" << iname.size()
510            << "),depth="  << depth << ",matching=" << iname.at(depth) << " in " << nodes.size();
511     }
512
513     if (nodes.empty())
514         return 0;
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.
521                 return c;
522             } else {
523                 // Sub-part of iname matched. Forward index and check children.
524                 return findNodeRecursion(iname, depth + 1, c->children());
525             }
526         }
527     }
528     return 0;
529 }
530
531 AbstractSymbolGroupNode *SymbolGroup::findI(const std::string &iname) const
532 {
533     if (iname.empty())
534         return 0;
535     // Match the root element only: Shouldn't happen, still, all happy
536     if (iname == m_root->name())
537         return m_root;
538
539     std::vector<std::string> inameTokens;
540     split(iname, SymbolGroupNodeVisitor::iNamePathSeparator, std::back_inserter(inameTokens));
541
542     // Must begin with root
543     if (inameTokens.front() != m_root->name())
544         return 0;
545
546     // Start with index = 0 at root's children
547     return findNodeRecursion(inameTokens, 1, m_root->children());
548 }
549
550 AbstractSymbolGroupNode *SymbolGroup::find(const std::string &iname) const
551 {
552     AbstractSymbolGroupNode *rc = findI(iname);
553     if (::debug > 1)
554         DebugPrint() << "SymbolGroup::find " << iname << ' ' << rc;
555     return rc;
556 }