1 //===- MarkupFilter.h -------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file declares a filter that replaces symbolizer markup with
11 /// human-readable expressions.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_DEBUGINFO_SYMBOLIZE_MARKUPFILTER_H
16 #define LLVM_DEBUGINFO_SYMBOLIZE_MARKUPFILTER_H
17 
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/DebugInfo/Symbolize/Markup.h"
20 #include "llvm/Object/BuildID.h"
21 #include "llvm/Support/WithColor.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <map>
24 
25 namespace llvm {
26 namespace symbolize {
27 
28 class LLVMSymbolizer;
29 
30 /// Filter to convert parsed log symbolizer markup elements into human-readable
31 /// text.
32 class MarkupFilter {
33 public:
34   MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer,
35                std::optional<bool> ColorsEnabled = std::nullopt);
36 
37   /// Filters a line containing symbolizer markup and writes the human-readable
38   /// results to the output stream.
39   ///
40   /// Invalid or unimplemented markup elements are removed. Some output may be
41   /// deferred until future filter() or finish() call.
42   void filter(StringRef Line);
43 
44   /// Records that the input stream has ended and writes any deferred output.
45   void finish();
46 
47 private:
48   struct Module {
49     uint64_t ID;
50     std::string Name;
51     SmallVector<uint8_t> BuildID;
52   };
53 
54   struct MMap {
55     uint64_t Addr;
56     uint64_t Size;
57     const Module *Mod;
58     std::string Mode; // Lowercase
59     uint64_t ModuleRelativeAddr;
60 
61     bool contains(uint64_t Addr) const;
62     uint64_t getModuleRelativeAddr(uint64_t Addr) const;
63   };
64 
65   // An informational module line currently being constructed. As many mmap
66   // elements as possible are folded into one ModuleInfo line.
67   struct ModuleInfoLine {
68     const Module *Mod;
69 
70     SmallVector<const MMap *> MMaps = {};
71   };
72 
73   // The semantics of a possible program counter value.
74   enum class PCType {
75     // The address is a return address and must be adjusted to point to the call
76     // itself.
77     ReturnAddress,
78     // The address is the precise location in the code and needs no adjustment.
79     PreciseCode,
80   };
81 
82   bool tryContextualElement(const MarkupNode &Node,
83                             const SmallVector<MarkupNode> &DeferredNodes);
84   bool tryMMap(const MarkupNode &Element,
85                const SmallVector<MarkupNode> &DeferredNodes);
86   bool tryReset(const MarkupNode &Element,
87                 const SmallVector<MarkupNode> &DeferredNodes);
88   bool tryModule(const MarkupNode &Element,
89                  const SmallVector<MarkupNode> &DeferredNodes);
90 
91   void beginModuleInfoLine(const Module *M);
92   void endAnyModuleInfoLine();
93 
94   void filterNode(const MarkupNode &Node);
95 
96   bool tryPresentation(const MarkupNode &Node);
97   bool trySymbol(const MarkupNode &Node);
98   bool tryPC(const MarkupNode &Node);
99   bool tryBackTrace(const MarkupNode &Node);
100   bool tryData(const MarkupNode &Node);
101 
102   bool trySGR(const MarkupNode &Node);
103 
104   void highlight();
105   void highlightValue();
106   void restoreColor();
107   void resetColor();
108 
109   void printRawElement(const MarkupNode &Element);
110   void printValue(Twine Value);
111 
112   std::optional<Module> parseModule(const MarkupNode &Element) const;
113   std::optional<MMap> parseMMap(const MarkupNode &Element) const;
114 
115   std::optional<uint64_t> parseAddr(StringRef Str) const;
116   std::optional<uint64_t> parseModuleID(StringRef Str) const;
117   std::optional<uint64_t> parseSize(StringRef Str) const;
118   object::BuildID parseBuildID(StringRef Str) const;
119   std::optional<std::string> parseMode(StringRef Str) const;
120   std::optional<PCType> parsePCType(StringRef Str) const;
121   std::optional<uint64_t> parseFrameNumber(StringRef Str) const;
122 
123   bool checkTag(const MarkupNode &Node) const;
124   bool checkNumFields(const MarkupNode &Element, size_t Size) const;
125   bool checkNumFieldsAtLeast(const MarkupNode &Element, size_t Size) const;
126   void warnNumFieldsAtMost(const MarkupNode &Element, size_t Size) const;
127 
128   void reportTypeError(StringRef Str, StringRef TypeName) const;
129   void reportLocation(StringRef::iterator Loc) const;
130 
131   const MMap *getOverlappingMMap(const MMap &Map) const;
132   const MMap *getContainingMMap(uint64_t Addr) const;
133 
134   uint64_t adjustAddr(uint64_t Addr, PCType Type) const;
135 
136   StringRef lineEnding() const;
137 
138   raw_ostream &OS;
139   LLVMSymbolizer &Symbolizer;
140   const bool ColorsEnabled;
141 
142   MarkupParser Parser;
143 
144   // Current line being filtered.
145   StringRef Line;
146 
147   // A module info line currently being built. This incorporates as much mmap
148   // information as possible before being emitted.
149   std::optional<ModuleInfoLine> MIL;
150 
151   // SGR state.
152   std::optional<raw_ostream::Colors> Color;
153   bool Bold = false;
154 
155   // Map from Module ID to Module.
156   DenseMap<uint64_t, std::unique_ptr<Module>> Modules;
157 
158   // Ordered map from starting address to mmap.
159   std::map<uint64_t, MMap> MMaps;
160 };
161 
162 } // end namespace symbolize
163 } // end namespace llvm
164 
165 #endif // LLVM_DEBUGINFO_SYMBOLIZE_MARKUPFILTER_H
166