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 #pragma once
27 
28 #include "common.h"
29 
30 #include <vector>
31 #include <string>
32 #include <map>
33 #include <iosfwd>
34 
35 enum { symbolGroupDebug = 0 };
36 
37 std::ostream &operator<<(std::ostream &, const DEBUG_SYMBOL_PARAMETERS&p);
38 
39 class SymbolGroupNodeVisitor;
40 class SymbolGroup;
41 struct SymbolGroupValueContext;
42 class SymbolGroupNode;
43 class MemoryHandle;
44 
45 // Helper struct used for check results when recoding CDB char pointer output.
46 struct DumpParameterRecodeResult
47 {
48     unsigned char *buffer = 0;
49     size_t size = 0;
50     std::string recommendedFormat;
51     bool isWide = false;
52 };
53 
54 struct DumpParameters
55 {
56     typedef std::map<std::string, std::string> FormatMap; // type or iname to format
57     enum DumpFlags
58     {
59         DumpHumanReadable = 0x1,
60         DumpComplexDumpers = 0x2,
61         DumpAlphabeticallySorted = 0x4
62     };
63 
humanReadableDumpParameters64     bool humanReadable() const {  return dumpFlags & DumpHumanReadable; }
isAlphabeticallySortedDumpParameters65     bool isAlphabeticallySorted() const {  return (dumpFlags & DumpAlphabeticallySorted) != 0; }
66     // Helper to decode format option arguments.
67     static FormatMap decodeFormatArgument(const std::string &f, bool isHex);
68 
69     static DumpParameterRecodeResult
70         checkRecode(const std::string &type, const std::string &iname,
71                     const std::wstring &value,
72                     const SymbolGroupValueContext &ctx,
73                     ULONG64 address,
74                     const DumpParameters *dp =0);
75 
76     bool recode(const std::string &type, const std::string &iname,
77                 const SymbolGroupValueContext &ctx,
78                 ULONG64 address,
79                 std::wstring *value, std::string *encoding) const;
80     std::string format(const std::string &type, const std::string &iname) const;
81 
82     unsigned dumpFlags = 0;
83     FormatMap typeFormats;
84     FormatMap individualFormats;
85 };
86 
87 std::ostream &operator<<(std::ostream &os, const DumpParameters &);
88 
89 class AbstractSymbolGroupNode
90 {
91     AbstractSymbolGroupNode(const AbstractSymbolGroupNode&);
92     AbstractSymbolGroupNode& operator=(const AbstractSymbolGroupNode&);
93 
94 public:
95     typedef std::vector<AbstractSymbolGroupNode *> AbstractSymbolGroupNodePtrVector;
96     typedef AbstractSymbolGroupNodePtrVector::iterator AbstractSymbolGroupNodePtrVectorIterator;
97     typedef AbstractSymbolGroupNodePtrVector::const_iterator AbstractSymbolGroupNodePtrVectorConstIterator;
98 
99     virtual ~AbstractSymbolGroupNode();
100 
101     // Name to appear in watchwindow
name()102     const std::string &name() const { return m_name; }
103     // 'iname' used as an internal id.
iName()104     const std::string &iName() const { return m_iname; }
105     // Full iname 'local.x.foo': WARNING: this returns the absolute path not
106     // taking reference nodes into account by recursing up the parents.
107     std::string absoluteFullIName() const;
108 
109     virtual const AbstractSymbolGroupNodePtrVector &children() const = 0;
110     AbstractSymbolGroupNode *childAt(unsigned) const;
111 
112     unsigned indexByIName(const char *) const; // (unsigned(-1) on failure
113     AbstractSymbolGroupNode *childByIName(const char *) const;
114     unsigned indexOf(const AbstractSymbolGroupNode *) const;
115 
parent()116     const AbstractSymbolGroupNode *parent() const { return m_parent; }
parent()117     AbstractSymbolGroupNode *parent() { return m_parent; }
118 
flags()119     unsigned flags() const           { return m_flags; }
testFlags(unsigned f)120     bool testFlags(unsigned f) const { return (m_flags & f) != 0; }
addFlags(unsigned f)121     void addFlags(unsigned f)        { m_flags |= f; }
clearFlags(unsigned f)122     void clearFlags(unsigned f)      { m_flags &= ~f; }
123 
asSymbolGroupNode()124     virtual SymbolGroupNode *asSymbolGroupNode() { return 0; }
asSymbolGroupNode()125     virtual const SymbolGroupNode *asSymbolGroupNode() const { return 0; }
resolveReference()126     virtual const AbstractSymbolGroupNode *resolveReference() const { return this; }
resolveReference()127     virtual AbstractSymbolGroupNode *resolveReference() { return this; }
128 
129     bool accept(SymbolGroupNodeVisitor &visitor,
130                 const std::string &visitingParentIname,
131                 unsigned child, unsigned depth);
132 
133     // I/O: GDBMI dump for Visitors, return child count
134     virtual int dump(std::ostream &str, const std::string &visitingFullIname,
135                      const DumpParameters &p, const SymbolGroupValueContext &ctx) = 0;
136     // I/O: debug output for Visitors
137     virtual void debug(std::ostream &os, const std::string &visitingFullIname,
138                        unsigned verbosity, unsigned depth) const;
139 
140     // For BaseSymbolGroupNode only.
141     void setParent(AbstractSymbolGroupNode *n);
142 
143 protected:
144     explicit AbstractSymbolGroupNode(const std::string &name, const std::string &iname);
145 
146     // Basic GDBMI dumping
147     static inline void dumpBasicData(std::ostream &str, const std::string &aName,
148                                   const std::string &aFullIname,
149                                   const std::string &type = std::string(),
150                                   const std::string &expression = std::string());
151 
152 private:
153     const std::string m_name;
154     const std::string m_iname;
155     AbstractSymbolGroupNode *m_parent = nullptr;
156     unsigned m_flags = 0;
157 };
158 
159 class BaseSymbolGroupNode : public AbstractSymbolGroupNode
160 {
161 public:
children()162     virtual const AbstractSymbolGroupNodePtrVector &children() const { return m_children; }
163     void addChild(AbstractSymbolGroupNode *c); // for watches
164     void removeChildAt(unsigned);
165 
166 protected:
167     explicit BaseSymbolGroupNode(const std::string &name, const std::string &iname);
168     virtual ~BaseSymbolGroupNode();
169 
reserveChildren(AbstractSymbolGroupNodePtrVector::size_type s)170     void reserveChildren(AbstractSymbolGroupNodePtrVector::size_type s) { m_children.reserve(s); }
171 
172 protected:
173     AbstractSymbolGroupNodePtrVector m_children;
174     void removeChildren();
175 };
176 
177 // Dummy fake node to satisfy the watch model for failed additions. Reports error.
178 class ErrorSymbolGroupNode : public BaseSymbolGroupNode
179 {
180 public:
181     explicit ErrorSymbolGroupNode(const std::string &name, const std::string &iname);
182 
183     virtual int dump(std::ostream &str, const std::string &fullIname,
184                      const DumpParameters &p, const SymbolGroupValueContext &ctx);
185     virtual void debug(std::ostream &os, const std::string &visitingFullIname,
186                        unsigned verbosity, unsigned depth) const;
187 };
188 
189 class SymbolGroupNode : public BaseSymbolGroupNode
190 {
191     explicit SymbolGroupNode(SymbolGroup *symbolGroup,
192                              ULONG index,
193                              const std::string &module,
194                              const std::string &name,
195                              const std::string &iname);
196 
197 public:
198     enum Flags
199     {
200         Uninitialized = 0x1,
201         SimpleDumperNotApplicable = 0x2, // No dumper available for type
202         SimpleDumperOk = 0x4,     // Internal dumper ran, value set
203         SimpleDumperFailed = 0x8, // Internal dumper failed
204         SimpleDumperMask = SimpleDumperNotApplicable|SimpleDumperOk|SimpleDumperFailed,
205         ExpandedByRequest = 0x10,
206         AdditionalSymbol = 0x20, // Introduced by addSymbol, should not be visible
207         Obscured = 0x40,    // Symbol is obscured by (for example) fake container children
208         ComplexDumperOk = 0x80,
209         WatchNode = 0x100,
210         PreSortedChildren = 0x200
211     };
212 
213     ~SymbolGroupNode();
214 
215     typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
216 
217     void parseParameters(SymbolParameterVector::size_type index,
218                          SymbolParameterVector::size_type parameterOffset,
219                          const SymbolParameterVector &vec);
220 
221     static SymbolGroupNode *create(SymbolGroup *sg, const std::string &module, const std::string &name, const SymbolParameterVector &vec);
222     // For root nodes, only: Add a new symbol by name
223     SymbolGroupNode *addSymbolByName(const std::string &module,
224                                      const std::string &name,  // Expression like 'myarray[1]'
225                                      const std::string &displayName,  // Name to be displayed, defaults to name
226                                      const std::string &iname, // Desired iname, defaults to name
227                                      std::string *errorMessage);
228 
symbolGroup()229     SymbolGroup *symbolGroup() const { return m_symbolGroup; }
230 
231     // I/O: Gdbmi dump for Visitors
232     virtual int dump(std::ostream &str, const std::string &fullIname,
233                       const DumpParameters &p, const SymbolGroupValueContext &ctx);
234     // Dumper functionality for reference nodes, returns child count guess
235     int dumpNode(std::ostream &str, const std::string &aName, const std::string &aFullIName,
236                   const DumpParameters &p, const SymbolGroupValueContext &ctx);
237 
238     // I/O: debug for Visitors
239     virtual void debug(std::ostream &os, const std::string &visitingFullIname,
240                        unsigned verbosity, unsigned depth) const;
241 
242     std::wstring symbolGroupRawValue() const;
243     std::wstring symbolGroupFixedValue() const;
244 
245     bool assign(const std::string &value, std::string *errorMessage = 0);
246     std::wstring simpleDumpValue(const SymbolGroupValueContext &ctx, std::string *encoding);
247 
248     // A quick check if symbol is valid by checking for inaccessible value
249     bool isMemoryAccessible() const;
250 
251     std::string type() const;
dumperType()252     int dumperType() const { return m_dumperType; } // Valid after dumper run
dumperContainerSize()253     int dumperContainerSize() { return m_dumperContainerSize; } // Valid after dumper run
254     unsigned size() const; // Size of value
255     ULONG64 address() const;
module()256     std::string module() const { return m_module; }
257 
258     bool expand(std::string *errorMessage);
259     bool expandRunComplexDumpers(const SymbolGroupValueContext &ctx, std::string *errorMessage);
isExpanded()260     bool isExpanded() const { return !children().empty(); }
canExpand()261     bool canExpand() const { return m_parameters.SubElements > 0; }
262     bool collapse(std::string *errorMessage);
263     void runComplexDumpers(const SymbolGroupValueContext &ctx);
264     // Cast to a different type. Works only on unexpanded nodes
265     bool typeCast(const std::string &desiredType, std::string *errorMessage);
266 
subElements()267     ULONG subElements() const { return m_parameters.SubElements; }
index()268     ULONG index() const { return m_index; }
269 
memory()270     MemoryHandle *memory() const { return m_memory; }
271 
asSymbolGroupNode()272     virtual SymbolGroupNode *asSymbolGroupNode() { return this; }
asSymbolGroupNode()273     virtual const SymbolGroupNode *asSymbolGroupNode() const { return this; }
274 
275     // Remove self off parent and return the indexes to be shifted or unsigned(-1).
276     bool removeSelf(SymbolGroupNode *root, std::string *errorMessage);
277 
278     static std::string msgAssignError(const std::string &nodeName,
279                                       const std::string &value,
280                                       const std::string &why);
281 
282 private:
283     const SymbolGroupNode *symbolGroupNodeParent() const;
284     SymbolGroupNode *symbolGroupNodeParent();
285     bool isArrayElement() const;
286     // Notify about expansion/collapsing of a node, shift indexes
287     bool notifyIndexesMoved(ULONG index, bool inserted, ULONG offset);
288     bool runSimpleDumpers(const SymbolGroupValueContext &ctx);
289     ULONG nextSymbolIndex() const;
290 
291     SymbolGroup *const m_symbolGroup = nullptr;
292     const std::string m_module;
293     ULONG m_index = 0;
294     DEBUG_SYMBOL_PARAMETERS m_parameters; // Careful when using ParentSymbol. It might not be correct.
295     std::wstring m_dumperValue;
296     std::string m_dumperValueEncoding;
297     int m_dumperType = -1;
298     int m_dumperContainerSize = -1;
299     void *m_dumperSpecialInfo = nullptr; // Opaque information passed from simple to complex dumpers
300     MemoryHandle *m_memory = nullptr; // Memory shared between simple dumper and edit value.
301 };
302 
303 class ReferenceSymbolGroupNode : public AbstractSymbolGroupNode
304 {
305 public:
306     explicit ReferenceSymbolGroupNode(const std::string &name,
307                                       const std::string &iname,
308                                       SymbolGroupNode *referencedNode);
309     // Convenience to create a node name name='[1]', iname='1' for arrays
310     static ReferenceSymbolGroupNode *createArrayNode(int index,
311                                                      SymbolGroupNode *referencedNode);
312 
313     virtual int dump(std::ostream &str, const std::string &visitingFullIname,
314                       const DumpParameters &p, const SymbolGroupValueContext &ctx);
315     virtual void debug(std::ostream &os, const std::string &visitingFullIname,
316                        unsigned verbosity, unsigned depth) const;
317 
children()318     virtual const AbstractSymbolGroupNodePtrVector &children() const { return m_referencedNode->children(); }
319 
resolveReference()320     virtual const AbstractSymbolGroupNode *resolveReference() const { return m_referencedNode; }
resolveReference()321     virtual AbstractSymbolGroupNode *resolveReference() { return m_referencedNode; }
322 
323 private:
324     SymbolGroupNode * const m_referencedNode;
325 };
326 
327 class MapNodeSymbolGroupNode : public BaseSymbolGroupNode
328 {
329 private:
330     explicit MapNodeSymbolGroupNode(const std::string &name,
331                                     const std::string &iname,
332                                     ULONG64 address /* = 0 */,
333                                     const std::string &type,
334                                     AbstractSymbolGroupNode *key,
335                                     AbstractSymbolGroupNode *value);
336 
337 public:
338     static MapNodeSymbolGroupNode *
339         create(int i, ULONG64 address /* = 0 */, const std::string &type,
340                SymbolGroupNode *key, SymbolGroupNode *value);
341 
342     virtual int dump(std::ostream &str, const std::string &visitingFullIname,
343                       const DumpParameters &p, const SymbolGroupValueContext &ctx);
344     virtual void debug(std::ostream &os, const std::string &visitingFullIname,
345                        unsigned verbosity, unsigned depth) const;
346 
347 private:
348     const ULONG64 m_address;
349     const std::string m_type;
350 };
351 
352 class SymbolGroupNodeVisitor {
353     SymbolGroupNodeVisitor(const SymbolGroupNodeVisitor&);
354     SymbolGroupNodeVisitor& operator=(const SymbolGroupNodeVisitor&);
355 
356     friend class AbstractSymbolGroupNode;
357 protected:
358     SymbolGroupNodeVisitor() = default;
359 public:
360     virtual ~SymbolGroupNodeVisitor() = default;
361 
362     // "local.vi" -> "local"
363     static std::string parentIname(const std::string &iname);
364     static const char iNamePathSeparator = '.';
365 
366 protected:
367     enum VisitResult
368     {
369         VisitContinue,
370         VisitSkipChildren,
371         VisitStop
372     };
373 
374 protected:
375     virtual VisitResult visit(AbstractSymbolGroupNode *node,
376                               const std::string &fullIname,
377                               unsigned child, unsigned depth) = 0;
378     // Helper for formatting output.
childrenVisited(const AbstractSymbolGroupNode *,unsigned)379     virtual void childrenVisited(const AbstractSymbolGroupNode * /* node */, unsigned /* depth */) {}
sortChildrenAlphabetically()380     virtual bool sortChildrenAlphabetically() const { return false; }
381 };
382 
383 class DebugSymbolGroupNodeVisitor : public SymbolGroupNodeVisitor {
384 public:
385     explicit DebugSymbolGroupNodeVisitor(std::ostream &os, unsigned verbosity = 0);
386 
387 protected:
388     virtual VisitResult visit(AbstractSymbolGroupNode *node,
389                               const std::string &fullIname,
390                               unsigned child, unsigned depth);
391 
392 private:
393     std::ostream &m_os;
394     const unsigned m_verbosity;
395 };
396 
397 class DebugFilterSymbolGroupNodeVisitor : public DebugSymbolGroupNodeVisitor {
398 public:
399     explicit DebugFilterSymbolGroupNodeVisitor(std::ostream &os,
400                                                const std::string &filter,
401                                                const unsigned verbosity = 0);
402 
403 protected:
404     virtual VisitResult visit(AbstractSymbolGroupNode *node,
405                               const std::string &fullIname,
406                               unsigned child, unsigned depth);
407 
408 private:
409     const std::string m_filter;
410 };
411 
412 class DumpSymbolGroupNodeVisitor : public SymbolGroupNodeVisitor {
413 public:
414     explicit DumpSymbolGroupNodeVisitor(std::ostream &os,
415                                         const SymbolGroupValueContext &context,
416                                         const DumpParameters &parameters = DumpParameters());
417 
418 protected:
419     virtual VisitResult visit(AbstractSymbolGroupNode *node,
420                               const std::string &fullIname,
421                               unsigned child, unsigned depth);
422     virtual void childrenVisited(const AbstractSymbolGroupNode *  node, unsigned depth);
sortChildrenAlphabetically()423     bool sortChildrenAlphabetically() const override { return m_parameters.isAlphabeticallySorted(); }
424 
425 private:
426     std::ostream &m_os;
427     const SymbolGroupValueContext &m_context;
428     const DumpParameters &m_parameters;
429     unsigned m_lastDepth = unsigned(-1);
430 };
431