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 ¶meters = 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