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