1 | //===-- FormatEntity.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 | #ifndef LLDB_CORE_FORMATENTITY_H |
10 | #define LLDB_CORE_FORMATENTITY_H |
11 | |
12 | #include "lldb/lldb-enumerations.h" |
13 | #include "lldb/lldb-types.h" |
14 | #include <algorithm> |
15 | #include <stddef.h> |
16 | #include <stdint.h> |
17 | |
18 | #include <string> |
19 | #include <vector> |
20 | |
21 | namespace lldb_private { |
22 | class Address; |
23 | class CompletionRequest; |
24 | class ExecutionContext; |
25 | class FileSpec; |
26 | class Status; |
27 | class Stream; |
28 | class StringList; |
29 | class SymbolContext; |
30 | class ValueObject; |
31 | } |
32 | |
33 | namespace llvm { |
34 | class StringRef; |
35 | } |
36 | |
37 | namespace lldb_private { |
38 | class FormatEntity { |
39 | public: |
40 | struct Entry { |
41 | enum class Type { |
42 | Invalid, |
43 | ParentNumber, |
44 | ParentString, |
45 | EscapeCode, |
46 | Root, |
47 | String, |
48 | Scope, |
49 | Variable, |
50 | VariableSynthetic, |
51 | ScriptVariable, |
52 | ScriptVariableSynthetic, |
53 | AddressLoad, |
54 | AddressFile, |
55 | AddressLoadOrFile, |
56 | ProcessID, |
57 | ProcessFile, |
58 | ScriptProcess, |
59 | ThreadID, |
60 | ThreadProtocolID, |
61 | ThreadIndexID, |
62 | ThreadName, |
63 | ThreadQueue, |
64 | ThreadStopReason, |
65 | ThreadStopReasonRaw, |
66 | ThreadReturnValue, |
67 | ThreadCompletedExpression, |
68 | ScriptThread, |
69 | ThreadInfo, |
70 | TargetArch, |
71 | ScriptTarget, |
72 | ModuleFile, |
73 | File, |
74 | Lang, |
75 | FrameIndex, |
76 | FrameNoDebug, |
77 | FrameRegisterPC, |
78 | FrameRegisterSP, |
79 | FrameRegisterFP, |
80 | FrameRegisterFlags, |
81 | FrameRegisterByName, |
82 | FrameIsArtificial, |
83 | ScriptFrame, |
84 | FunctionID, |
85 | FunctionDidChange, |
86 | FunctionInitialFunction, |
87 | FunctionName, |
88 | FunctionNameWithArgs, |
89 | FunctionNameNoArgs, |
90 | FunctionMangledName, |
91 | FunctionAddrOffset, |
92 | FunctionAddrOffsetConcrete, |
93 | FunctionLineOffset, |
94 | FunctionPCOffset, |
95 | FunctionInitial, |
96 | FunctionChanged, |
97 | FunctionIsOptimized, |
98 | LineEntryFile, |
99 | LineEntryLineNumber, |
100 | LineEntryColumn, |
101 | LineEntryStartAddress, |
102 | LineEntryEndAddress, |
103 | CurrentPCArrow |
104 | }; |
105 | |
106 | struct Definition { |
107 | /// The name/string placeholder that corresponds to this definition. |
108 | const char *name; |
109 | /// Insert this exact string into the output |
110 | const char *string = nullptr; |
111 | /// Entry::Type corresponding to this definition. |
112 | const Entry::Type type; |
113 | /// Data that is returned as the value of the format string. |
114 | const uint64_t data = 0; |
115 | /// The number of children of this node in the tree of format strings. |
116 | const uint32_t num_children = 0; |
117 | /// An array of "num_children" Definition entries. |
118 | const Definition *children = nullptr; |
119 | /// Whether the separator is kept during parsing or not. It's used |
120 | /// for entries with parameters. |
121 | const bool keep_separator = false; |
122 | |
123 | constexpr Definition(const char *name, const FormatEntity::Entry::Type t) |
124 | : name(name), type(t) {} |
125 | |
126 | constexpr Definition(const char *name, const char *string) |
127 | : name(name), string(string), type(Entry::Type::EscapeCode) {} |
128 | |
129 | constexpr Definition(const char *name, const FormatEntity::Entry::Type t, |
130 | const uint64_t data) |
131 | : name(name), string(nullptr), type(t), data(data) {} |
132 | |
133 | constexpr Definition(const char *name, const FormatEntity::Entry::Type t, |
134 | const uint64_t num_children, |
135 | const Definition *children, |
136 | const bool keep_separator = false) |
137 | : name(name), type(t), num_children(num_children), children(children), |
138 | keep_separator(keep_separator) {} |
139 | }; |
140 | |
141 | template <size_t N> |
142 | static constexpr Definition |
143 | DefinitionWithChildren(const char *name, const FormatEntity::Entry::Type t, |
144 | const Definition (&children)[N], |
145 | bool keep_separator = false) { |
146 | return Definition(name, t, N, children, keep_separator); |
147 | } |
148 | |
149 | Entry(Type t = Type::Invalid, const char *s = nullptr, |
150 | const char *f = nullptr) |
151 | : string(s ? s : "" ), printf_format(f ? f : "" ), children(), type(t), |
152 | fmt(lldb::eFormatDefault), number(0), deref(false) {} |
153 | |
154 | Entry(llvm::StringRef s); |
155 | Entry(char ch); |
156 | |
157 | void AppendChar(char ch); |
158 | |
159 | void AppendText(const llvm::StringRef &s); |
160 | |
161 | void AppendText(const char *cstr); |
162 | |
163 | void AppendEntry(const Entry &&entry) { children.push_back(entry); } |
164 | |
165 | void Clear() { |
166 | string.clear(); |
167 | printf_format.clear(); |
168 | children.clear(); |
169 | type = Type::Invalid; |
170 | fmt = lldb::eFormatDefault; |
171 | number = 0; |
172 | deref = false; |
173 | } |
174 | |
175 | static const char *TypeToCString(Type t); |
176 | |
177 | void Dump(Stream &s, int depth = 0) const; |
178 | |
179 | bool operator==(const Entry &rhs) const { |
180 | if (string != rhs.string) |
181 | return false; |
182 | if (printf_format != rhs.printf_format) |
183 | return false; |
184 | const size_t n = children.size(); |
185 | const size_t m = rhs.children.size(); |
186 | for (size_t i = 0; i < std::min<size_t>(n, m); ++i) { |
187 | if (!(children[i] == rhs.children[i])) |
188 | return false; |
189 | } |
190 | if (children != rhs.children) |
191 | return false; |
192 | if (type != rhs.type) |
193 | return false; |
194 | if (fmt != rhs.fmt) |
195 | return false; |
196 | if (deref != rhs.deref) |
197 | return false; |
198 | return true; |
199 | } |
200 | |
201 | std::string string; |
202 | std::string printf_format; |
203 | std::vector<Entry> children; |
204 | Type type; |
205 | lldb::Format fmt; |
206 | lldb::addr_t number; |
207 | bool deref; |
208 | }; |
209 | |
210 | static bool Format(const Entry &entry, Stream &s, const SymbolContext *sc, |
211 | const ExecutionContext *exe_ctx, const Address *addr, |
212 | ValueObject *valobj, bool function_changed, |
213 | bool initial_function); |
214 | |
215 | static bool FormatStringRef(const llvm::StringRef &format, Stream &s, |
216 | const SymbolContext *sc, |
217 | const ExecutionContext *exe_ctx, |
218 | const Address *addr, ValueObject *valobj, |
219 | bool function_changed, bool initial_function); |
220 | |
221 | static bool FormatCString(const char *format, Stream &s, |
222 | const SymbolContext *sc, |
223 | const ExecutionContext *exe_ctx, |
224 | const Address *addr, ValueObject *valobj, |
225 | bool function_changed, bool initial_function); |
226 | |
227 | static Status Parse(const llvm::StringRef &format, Entry &entry); |
228 | |
229 | static Status (llvm::StringRef &format_str, |
230 | llvm::StringRef &variable_name, |
231 | llvm::StringRef &variable_format); |
232 | |
233 | static void AutoComplete(lldb_private::CompletionRequest &request); |
234 | |
235 | // Format the current elements into the stream \a s. |
236 | // |
237 | // The root element will be stripped off and the format str passed in will be |
238 | // either an empty string (print a description of this object), or contain a |
239 | // `.`-separated series like a domain name that identifies further |
240 | // sub-elements to display. |
241 | static bool FormatFileSpec(const FileSpec &file, Stream &s, |
242 | llvm::StringRef elements, |
243 | llvm::StringRef element_format); |
244 | |
245 | protected: |
246 | static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry, |
247 | uint32_t depth); |
248 | }; |
249 | } // namespace lldb_private |
250 | |
251 | #endif // LLDB_CORE_FORMATENTITY_H |
252 | |