1 //===-- FormatEntity.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Core/FormatEntity.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringRef.h"
17 
18 // Project includes
19 #include "lldb/Core/Address.h"
20 #include "lldb/Core/Debugger.h"
21 #include "lldb/Core/Module.h"
22 #include "lldb/Core/Stream.h"
23 #include "lldb/Core/StreamString.h"
24 #include "lldb/Core/ValueObject.h"
25 #include "lldb/Core/ValueObjectVariable.h"
26 #include "lldb/DataFormatters/DataVisualization.h"
27 #include "lldb/DataFormatters/FormatManager.h"
28 #include "lldb/DataFormatters/ValueObjectPrinter.h"
29 #include "lldb/Expression/ExpressionVariable.h"
30 #include "lldb/Host/FileSpec.h"
31 #include "lldb/Interpreter/CommandInterpreter.h"
32 #include "lldb/Symbol/Block.h"
33 #include "lldb/Symbol/CompileUnit.h"
34 #include "lldb/Symbol/Function.h"
35 #include "lldb/Symbol/LineEntry.h"
36 #include "lldb/Symbol/Symbol.h"
37 #include "lldb/Symbol/VariableList.h"
38 #include "lldb/Target/ExecutionContext.h"
39 #include "lldb/Target/Language.h"
40 #include "lldb/Target/Process.h"
41 #include "lldb/Target/RegisterContext.h"
42 #include "lldb/Target/SectionLoadList.h"
43 #include "lldb/Target/StackFrame.h"
44 #include "lldb/Target/StopInfo.h"
45 #include "lldb/Target/Target.h"
46 #include "lldb/Target/Thread.h"
47 #include "lldb/Utility/AnsiTerminal.h"
48 
49 using namespace lldb;
50 using namespace lldb_private;
51 
52 enum FileKind { FileError = 0, Basename, Dirname, Fullpath };
53 
54 #define ENTRY(n, t, f)                                                         \
55   {                                                                            \
56     n, nullptr, FormatEntity::Entry::Type::t,                                  \
57         FormatEntity::Entry::FormatType::f, 0, 0, nullptr, false               \
58   }
59 #define ENTRY_VALUE(n, t, f, v)                                                \
60   {                                                                            \
61     n, nullptr, FormatEntity::Entry::Type::t,                                  \
62         FormatEntity::Entry::FormatType::f, v, 0, nullptr, false               \
63   }
64 #define ENTRY_CHILDREN(n, t, f, c)                                             \
65   {                                                                            \
66     n, nullptr, FormatEntity::Entry::Type::t,                                  \
67         FormatEntity::Entry::FormatType::f, 0, llvm::array_lengthof(c), c,     \
68         false                                                                  \
69   }
70 #define ENTRY_CHILDREN_KEEP_SEP(n, t, f, c)                                    \
71   {                                                                            \
72     n, nullptr, FormatEntity::Entry::Type::t,                                  \
73         FormatEntity::Entry::FormatType::f, 0, llvm::array_lengthof(c), c,     \
74         true                                                                   \
75   }
76 #define ENTRY_STRING(n, s)                                                     \
77   {                                                                            \
78     n, s, FormatEntity::Entry::Type::InsertString,                             \
79         FormatEntity::Entry::FormatType::None, 0, 0, nullptr, false            \
80   }
81 static FormatEntity::Entry::Definition g_string_entry[] = {
82     ENTRY("*", ParentString, None)};
83 
84 static FormatEntity::Entry::Definition g_addr_entries[] = {
85     ENTRY("load", AddressLoad, UInt64), ENTRY("file", AddressFile, UInt64),
86     ENTRY("load", AddressLoadOrFile, UInt64),
87 };
88 
89 static FormatEntity::Entry::Definition g_file_child_entries[] = {
90     ENTRY_VALUE("basename", ParentNumber, CString, FileKind::Basename),
91     ENTRY_VALUE("dirname", ParentNumber, CString, FileKind::Dirname),
92     ENTRY_VALUE("fullpath", ParentNumber, CString, FileKind::Fullpath)};
93 
94 static FormatEntity::Entry::Definition g_frame_child_entries[] = {
95     ENTRY("index", FrameIndex, UInt32),
96     ENTRY("pc", FrameRegisterPC, UInt64),
97     ENTRY("fp", FrameRegisterFP, UInt64),
98     ENTRY("sp", FrameRegisterSP, UInt64),
99     ENTRY("flags", FrameRegisterFlags, UInt64),
100     ENTRY("no-debug", FrameNoDebug, None),
101     ENTRY_CHILDREN("reg", FrameRegisterByName, UInt64, g_string_entry),
102 };
103 
104 static FormatEntity::Entry::Definition g_function_child_entries[] = {
105     ENTRY("id", FunctionID, UInt64), ENTRY("name", FunctionName, CString),
106     ENTRY("name-without-args", FunctionNameNoArgs, CString),
107     ENTRY("name-with-args", FunctionNameWithArgs, CString),
108     ENTRY("addr-offset", FunctionAddrOffset, UInt64),
109     ENTRY("concrete-only-addr-offset-no-padding", FunctionAddrOffsetConcrete,
110           UInt64),
111     ENTRY("line-offset", FunctionLineOffset, UInt64),
112     ENTRY("pc-offset", FunctionPCOffset, UInt64),
113     ENTRY("initial-function", FunctionInitial, None),
114     ENTRY("changed", FunctionChanged, None),
115     ENTRY("is-optimized", FunctionIsOptimized, None)};
116 
117 static FormatEntity::Entry::Definition g_line_child_entries[] = {
118     ENTRY_CHILDREN("file", LineEntryFile, None, g_file_child_entries),
119     ENTRY("number", LineEntryLineNumber, UInt32),
120     ENTRY("start-addr", LineEntryStartAddress, UInt64),
121     ENTRY("end-addr", LineEntryEndAddress, UInt64),
122 };
123 
124 static FormatEntity::Entry::Definition g_module_child_entries[] = {
125     ENTRY_CHILDREN("file", ModuleFile, None, g_file_child_entries),
126 };
127 
128 static FormatEntity::Entry::Definition g_process_child_entries[] = {
129     ENTRY("id", ProcessID, UInt64),
130     ENTRY_VALUE("name", ProcessFile, CString, FileKind::Basename),
131     ENTRY_CHILDREN("file", ProcessFile, None, g_file_child_entries),
132 };
133 
134 static FormatEntity::Entry::Definition g_svar_child_entries[] = {
135     ENTRY("*", ParentString, None)};
136 
137 static FormatEntity::Entry::Definition g_var_child_entries[] = {
138     ENTRY("*", ParentString, None)};
139 
140 static FormatEntity::Entry::Definition g_thread_child_entries[] = {
141     ENTRY("id", ThreadID, UInt64),
142     ENTRY("protocol_id", ThreadProtocolID, UInt64),
143     ENTRY("index", ThreadIndexID, UInt32),
144     ENTRY_CHILDREN("info", ThreadInfo, None, g_string_entry),
145     ENTRY("queue", ThreadQueue, CString),
146     ENTRY("name", ThreadName, CString),
147     ENTRY("stop-reason", ThreadStopReason, CString),
148     ENTRY("return-value", ThreadReturnValue, CString),
149     ENTRY("completed-expression", ThreadCompletedExpression, CString),
150 };
151 
152 static FormatEntity::Entry::Definition g_target_child_entries[] = {
153     ENTRY("arch", TargetArch, CString),
154 };
155 
156 #define _TO_STR2(_val) #_val
157 #define _TO_STR(_val) _TO_STR2(_val)
158 
159 static FormatEntity::Entry::Definition g_ansi_fg_entries[] = {
160     ENTRY_STRING("black",
161                  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLACK) ANSI_ESC_END),
162     ENTRY_STRING("red", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_RED) ANSI_ESC_END),
163     ENTRY_STRING("green",
164                  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_GREEN) ANSI_ESC_END),
165     ENTRY_STRING("yellow",
166                  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_YELLOW) ANSI_ESC_END),
167     ENTRY_STRING("blue",
168                  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLUE) ANSI_ESC_END),
169     ENTRY_STRING("purple",
170                  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_PURPLE) ANSI_ESC_END),
171     ENTRY_STRING("cyan",
172                  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_CYAN) ANSI_ESC_END),
173     ENTRY_STRING("white",
174                  ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_WHITE) ANSI_ESC_END),
175 };
176 
177 static FormatEntity::Entry::Definition g_ansi_bg_entries[] = {
178     ENTRY_STRING("black",
179                  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLACK) ANSI_ESC_END),
180     ENTRY_STRING("red", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_RED) ANSI_ESC_END),
181     ENTRY_STRING("green",
182                  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_GREEN) ANSI_ESC_END),
183     ENTRY_STRING("yellow",
184                  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_YELLOW) ANSI_ESC_END),
185     ENTRY_STRING("blue",
186                  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLUE) ANSI_ESC_END),
187     ENTRY_STRING("purple",
188                  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_PURPLE) ANSI_ESC_END),
189     ENTRY_STRING("cyan",
190                  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_CYAN) ANSI_ESC_END),
191     ENTRY_STRING("white",
192                  ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_WHITE) ANSI_ESC_END),
193 };
194 
195 static FormatEntity::Entry::Definition g_ansi_entries[] = {
196     ENTRY_CHILDREN("fg", Invalid, None, g_ansi_fg_entries),
197     ENTRY_CHILDREN("bg", Invalid, None, g_ansi_bg_entries),
198     ENTRY_STRING("normal",
199                  ANSI_ESC_START _TO_STR(ANSI_CTRL_NORMAL) ANSI_ESC_END),
200     ENTRY_STRING("bold", ANSI_ESC_START _TO_STR(ANSI_CTRL_BOLD) ANSI_ESC_END),
201     ENTRY_STRING("faint", ANSI_ESC_START _TO_STR(ANSI_CTRL_FAINT) ANSI_ESC_END),
202     ENTRY_STRING("italic",
203                  ANSI_ESC_START _TO_STR(ANSI_CTRL_ITALIC) ANSI_ESC_END),
204     ENTRY_STRING("underline",
205                  ANSI_ESC_START _TO_STR(ANSI_CTRL_UNDERLINE) ANSI_ESC_END),
206     ENTRY_STRING("slow-blink",
207                  ANSI_ESC_START _TO_STR(ANSI_CTRL_SLOW_BLINK) ANSI_ESC_END),
208     ENTRY_STRING("fast-blink",
209                  ANSI_ESC_START _TO_STR(ANSI_CTRL_FAST_BLINK) ANSI_ESC_END),
210     ENTRY_STRING("negative",
211                  ANSI_ESC_START _TO_STR(ANSI_CTRL_IMAGE_NEGATIVE) ANSI_ESC_END),
212     ENTRY_STRING("conceal",
213                  ANSI_ESC_START _TO_STR(ANSI_CTRL_CONCEAL) ANSI_ESC_END),
214     ENTRY_STRING("crossed-out",
215                  ANSI_ESC_START _TO_STR(ANSI_CTRL_CROSSED_OUT) ANSI_ESC_END),
216 };
217 
218 static FormatEntity::Entry::Definition g_script_child_entries[] = {
219     ENTRY("frame", ScriptFrame, None),
220     ENTRY("process", ScriptProcess, None),
221     ENTRY("target", ScriptTarget, None),
222     ENTRY("thread", ScriptThread, None),
223     ENTRY("var", ScriptVariable, None),
224     ENTRY("svar", ScriptVariableSynthetic, None),
225     ENTRY("thread", ScriptThread, None),
226 };
227 
228 static FormatEntity::Entry::Definition g_top_level_entries[] = {
229     ENTRY_CHILDREN("addr", AddressLoadOrFile, UInt64, g_addr_entries),
230     ENTRY("addr-file-or-load", AddressLoadOrFile, UInt64),
231     ENTRY_CHILDREN("ansi", Invalid, None, g_ansi_entries),
232     ENTRY("current-pc-arrow", CurrentPCArrow, CString),
233     ENTRY_CHILDREN("file", File, CString, g_file_child_entries),
234     ENTRY("language", Lang, CString),
235     ENTRY_CHILDREN("frame", Invalid, None, g_frame_child_entries),
236     ENTRY_CHILDREN("function", Invalid, None, g_function_child_entries),
237     ENTRY_CHILDREN("line", Invalid, None, g_line_child_entries),
238     ENTRY_CHILDREN("module", Invalid, None, g_module_child_entries),
239     ENTRY_CHILDREN("process", Invalid, None, g_process_child_entries),
240     ENTRY_CHILDREN("script", Invalid, None, g_script_child_entries),
241     ENTRY_CHILDREN_KEEP_SEP("svar", VariableSynthetic, None,
242                             g_svar_child_entries),
243     ENTRY_CHILDREN("thread", Invalid, None, g_thread_child_entries),
244     ENTRY_CHILDREN("target", Invalid, None, g_target_child_entries),
245     ENTRY_CHILDREN_KEEP_SEP("var", Variable, None, g_var_child_entries),
246 };
247 
248 static FormatEntity::Entry::Definition g_root =
249     ENTRY_CHILDREN("<root>", Root, None, g_top_level_entries);
250 
251 FormatEntity::Entry::Entry(llvm::StringRef s)
252     : string(s.data(), s.size()), printf_format(), children(),
253       definition(nullptr), type(Type::String), fmt(lldb::eFormatDefault),
254       number(0), deref(false) {}
255 
256 FormatEntity::Entry::Entry(char ch)
257     : string(1, ch), printf_format(), children(), definition(nullptr),
258       type(Type::String), fmt(lldb::eFormatDefault), number(0), deref(false) {}
259 
260 void FormatEntity::Entry::AppendChar(char ch) {
261   if (children.empty() || children.back().type != Entry::Type::String)
262     children.push_back(Entry(ch));
263   else
264     children.back().string.append(1, ch);
265 }
266 
267 void FormatEntity::Entry::AppendText(const llvm::StringRef &s) {
268   if (children.empty() || children.back().type != Entry::Type::String)
269     children.push_back(Entry(s));
270   else
271     children.back().string.append(s.data(), s.size());
272 }
273 
274 void FormatEntity::Entry::AppendText(const char *cstr) {
275   return AppendText(llvm::StringRef(cstr));
276 }
277 
278 Error FormatEntity::Parse(const llvm::StringRef &format_str, Entry &entry) {
279   entry.Clear();
280   entry.type = Entry::Type::Root;
281   llvm::StringRef modifiable_format(format_str);
282   return ParseInternal(modifiable_format, entry, 0);
283 }
284 
285 #define ENUM_TO_CSTR(eee)                                                      \
286   case FormatEntity::Entry::Type::eee:                                         \
287     return #eee
288 
289 const char *FormatEntity::Entry::TypeToCString(Type t) {
290   switch (t) {
291     ENUM_TO_CSTR(Invalid);
292     ENUM_TO_CSTR(ParentNumber);
293     ENUM_TO_CSTR(ParentString);
294     ENUM_TO_CSTR(InsertString);
295     ENUM_TO_CSTR(Root);
296     ENUM_TO_CSTR(String);
297     ENUM_TO_CSTR(Scope);
298     ENUM_TO_CSTR(Variable);
299     ENUM_TO_CSTR(VariableSynthetic);
300     ENUM_TO_CSTR(ScriptVariable);
301     ENUM_TO_CSTR(ScriptVariableSynthetic);
302     ENUM_TO_CSTR(AddressLoad);
303     ENUM_TO_CSTR(AddressFile);
304     ENUM_TO_CSTR(AddressLoadOrFile);
305     ENUM_TO_CSTR(ProcessID);
306     ENUM_TO_CSTR(ProcessFile);
307     ENUM_TO_CSTR(ScriptProcess);
308     ENUM_TO_CSTR(ThreadID);
309     ENUM_TO_CSTR(ThreadProtocolID);
310     ENUM_TO_CSTR(ThreadIndexID);
311     ENUM_TO_CSTR(ThreadName);
312     ENUM_TO_CSTR(ThreadQueue);
313     ENUM_TO_CSTR(ThreadStopReason);
314     ENUM_TO_CSTR(ThreadReturnValue);
315     ENUM_TO_CSTR(ThreadCompletedExpression);
316     ENUM_TO_CSTR(ScriptThread);
317     ENUM_TO_CSTR(ThreadInfo);
318     ENUM_TO_CSTR(TargetArch);
319     ENUM_TO_CSTR(ScriptTarget);
320     ENUM_TO_CSTR(ModuleFile);
321     ENUM_TO_CSTR(File);
322     ENUM_TO_CSTR(Lang);
323     ENUM_TO_CSTR(FrameIndex);
324     ENUM_TO_CSTR(FrameNoDebug);
325     ENUM_TO_CSTR(FrameRegisterPC);
326     ENUM_TO_CSTR(FrameRegisterSP);
327     ENUM_TO_CSTR(FrameRegisterFP);
328     ENUM_TO_CSTR(FrameRegisterFlags);
329     ENUM_TO_CSTR(FrameRegisterByName);
330     ENUM_TO_CSTR(ScriptFrame);
331     ENUM_TO_CSTR(FunctionID);
332     ENUM_TO_CSTR(FunctionDidChange);
333     ENUM_TO_CSTR(FunctionInitialFunction);
334     ENUM_TO_CSTR(FunctionName);
335     ENUM_TO_CSTR(FunctionNameWithArgs);
336     ENUM_TO_CSTR(FunctionNameNoArgs);
337     ENUM_TO_CSTR(FunctionAddrOffset);
338     ENUM_TO_CSTR(FunctionAddrOffsetConcrete);
339     ENUM_TO_CSTR(FunctionLineOffset);
340     ENUM_TO_CSTR(FunctionPCOffset);
341     ENUM_TO_CSTR(FunctionInitial);
342     ENUM_TO_CSTR(FunctionChanged);
343     ENUM_TO_CSTR(FunctionIsOptimized);
344     ENUM_TO_CSTR(LineEntryFile);
345     ENUM_TO_CSTR(LineEntryLineNumber);
346     ENUM_TO_CSTR(LineEntryStartAddress);
347     ENUM_TO_CSTR(LineEntryEndAddress);
348     ENUM_TO_CSTR(CurrentPCArrow);
349   }
350   return "???";
351 }
352 
353 #undef ENUM_TO_CSTR
354 
355 void FormatEntity::Entry::Dump(Stream &s, int depth) const {
356   s.Printf("%*.*s%-20s: ", depth * 2, depth * 2, "", TypeToCString(type));
357   if (fmt != eFormatDefault)
358     s.Printf("lldb-format = %s, ", FormatManager::GetFormatAsCString(fmt));
359   if (!string.empty())
360     s.Printf("string = \"%s\"", string.c_str());
361   if (!printf_format.empty())
362     s.Printf("printf_format = \"%s\"", printf_format.c_str());
363   if (number != 0)
364     s.Printf("number = %" PRIu64 " (0x%" PRIx64 "), ", number, number);
365   if (deref)
366     s.Printf("deref = true, ");
367   s.EOL();
368   for (const auto &child : children) {
369     child.Dump(s, depth + 1);
370   }
371 }
372 
373 template <typename T>
374 static bool RunScriptFormatKeyword(Stream &s, const SymbolContext *sc,
375                                    const ExecutionContext *exe_ctx, T t,
376                                    const char *script_function_name) {
377   Target *target = Target::GetTargetFromContexts(exe_ctx, sc);
378 
379   if (target) {
380     ScriptInterpreter *script_interpreter =
381         target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
382     if (script_interpreter) {
383       Error error;
384       std::string script_output;
385 
386       if (script_interpreter->RunScriptFormatKeyword(script_function_name, t,
387                                                      script_output, error) &&
388           error.Success()) {
389         s.Printf("%s", script_output.c_str());
390         return true;
391       } else {
392         s.Printf("<error: %s>", error.AsCString());
393       }
394     }
395   }
396   return false;
397 }
398 
399 static bool DumpAddress(Stream &s, const SymbolContext *sc,
400                         const ExecutionContext *exe_ctx, const Address &addr,
401                         bool print_file_addr_or_load_addr) {
402   Target *target = Target::GetTargetFromContexts(exe_ctx, sc);
403   addr_t vaddr = LLDB_INVALID_ADDRESS;
404   if (exe_ctx && !target->GetSectionLoadList().IsEmpty())
405     vaddr = addr.GetLoadAddress(target);
406   if (vaddr == LLDB_INVALID_ADDRESS)
407     vaddr = addr.GetFileAddress();
408 
409   if (vaddr != LLDB_INVALID_ADDRESS) {
410     int addr_width = 0;
411     if (exe_ctx && target) {
412       addr_width = target->GetArchitecture().GetAddressByteSize() * 2;
413     }
414     if (addr_width == 0)
415       addr_width = 16;
416     if (print_file_addr_or_load_addr) {
417       ExecutionContextScope *exe_scope = nullptr;
418       if (exe_ctx)
419         exe_scope = exe_ctx->GetBestExecutionContextScope();
420       addr.Dump(&s, exe_scope, Address::DumpStyleLoadAddress,
421                 Address::DumpStyleModuleWithFileAddress, 0);
422     } else {
423       s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr);
424     }
425     return true;
426   }
427   return false;
428 }
429 
430 static bool DumpAddressOffsetFromFunction(Stream &s, const SymbolContext *sc,
431                                           const ExecutionContext *exe_ctx,
432                                           const Address &format_addr,
433                                           bool concrete_only, bool no_padding,
434                                           bool print_zero_offsets) {
435   if (format_addr.IsValid()) {
436     Address func_addr;
437 
438     if (sc) {
439       if (sc->function) {
440         func_addr = sc->function->GetAddressRange().GetBaseAddress();
441         if (sc->block && !concrete_only) {
442           // Check to make sure we aren't in an inline
443           // function. If we are, use the inline block
444           // range that contains "format_addr" since
445           // blocks can be discontiguous.
446           Block *inline_block = sc->block->GetContainingInlinedBlock();
447           AddressRange inline_range;
448           if (inline_block &&
449               inline_block->GetRangeContainingAddress(format_addr,
450                                                       inline_range))
451             func_addr = inline_range.GetBaseAddress();
452         }
453       } else if (sc->symbol && sc->symbol->ValueIsAddress())
454         func_addr = sc->symbol->GetAddressRef();
455     }
456 
457     if (func_addr.IsValid()) {
458       const char *addr_offset_padding = no_padding ? "" : " ";
459 
460       if (func_addr.GetSection() == format_addr.GetSection()) {
461         addr_t func_file_addr = func_addr.GetFileAddress();
462         addr_t addr_file_addr = format_addr.GetFileAddress();
463         if (addr_file_addr > func_file_addr ||
464             (addr_file_addr == func_file_addr && print_zero_offsets)) {
465           s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding,
466                    addr_file_addr - func_file_addr);
467         } else if (addr_file_addr < func_file_addr) {
468           s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding,
469                    func_file_addr - addr_file_addr);
470         }
471         return true;
472       } else {
473         Target *target = Target::GetTargetFromContexts(exe_ctx, sc);
474         if (target) {
475           addr_t func_load_addr = func_addr.GetLoadAddress(target);
476           addr_t addr_load_addr = format_addr.GetLoadAddress(target);
477           if (addr_load_addr > func_load_addr ||
478               (addr_load_addr == func_load_addr && print_zero_offsets)) {
479             s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding,
480                      addr_load_addr - func_load_addr);
481           } else if (addr_load_addr < func_load_addr) {
482             s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding,
483                      func_load_addr - addr_load_addr);
484           }
485           return true;
486         }
487       }
488     }
489   }
490   return false;
491 }
492 
493 static bool ScanBracketedRange(llvm::StringRef subpath,
494                                size_t &close_bracket_index,
495                                const char *&var_name_final_if_array_range,
496                                int64_t &index_lower, int64_t &index_higher) {
497   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
498   close_bracket_index = llvm::StringRef::npos;
499   const size_t open_bracket_index = subpath.find('[');
500   if (open_bracket_index == llvm::StringRef::npos) {
501     if (log)
502       log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely");
503     return false;
504   }
505 
506   close_bracket_index = subpath.find(']', open_bracket_index + 1);
507 
508   if (close_bracket_index == llvm::StringRef::npos) {
509     if (log)
510       log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely");
511     return false;
512   } else {
513     var_name_final_if_array_range = subpath.data() + open_bracket_index;
514 
515     if (close_bracket_index - open_bracket_index == 1) {
516       if (log)
517         log->Printf(
518             "[ScanBracketedRange] '[]' detected.. going from 0 to end of data");
519       index_lower = 0;
520     } else {
521       const size_t separator_index = subpath.find('-', open_bracket_index + 1);
522 
523       if (separator_index == llvm::StringRef::npos) {
524         const char *index_lower_cstr = subpath.data() + open_bracket_index + 1;
525         index_lower = ::strtoul(index_lower_cstr, nullptr, 0);
526         index_higher = index_lower;
527         if (log)
528           log->Printf("[ScanBracketedRange] [%" PRId64
529                       "] detected, high index is same",
530                       index_lower);
531       } else {
532         const char *index_lower_cstr = subpath.data() + open_bracket_index + 1;
533         const char *index_higher_cstr = subpath.data() + separator_index + 1;
534         index_lower = ::strtoul(index_lower_cstr, nullptr, 0);
535         index_higher = ::strtoul(index_higher_cstr, nullptr, 0);
536         if (log)
537           log->Printf("[ScanBracketedRange] [%" PRId64 "-%" PRId64 "] detected",
538                       index_lower, index_higher);
539       }
540       if (index_lower > index_higher && index_higher > 0) {
541         if (log)
542           log->Printf("[ScanBracketedRange] swapping indices");
543         const int64_t temp = index_lower;
544         index_lower = index_higher;
545         index_higher = temp;
546       }
547     }
548   }
549   return true;
550 }
551 
552 static bool DumpFile(Stream &s, const FileSpec &file, FileKind file_kind) {
553   switch (file_kind) {
554   case FileKind::FileError:
555     break;
556 
557   case FileKind::Basename:
558     if (file.GetFilename()) {
559       s << file.GetFilename();
560       return true;
561     }
562     break;
563 
564   case FileKind::Dirname:
565     if (file.GetDirectory()) {
566       s << file.GetDirectory();
567       return true;
568     }
569     break;
570 
571   case FileKind::Fullpath:
572     if (file) {
573       s << file;
574       return true;
575     }
576     break;
577   }
578   return false;
579 }
580 
581 static bool DumpRegister(Stream &s, StackFrame *frame, RegisterKind reg_kind,
582                          uint32_t reg_num, Format format)
583 
584 {
585   if (frame) {
586     RegisterContext *reg_ctx = frame->GetRegisterContext().get();
587 
588     if (reg_ctx) {
589       const uint32_t lldb_reg_num =
590           reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num);
591       if (lldb_reg_num != LLDB_INVALID_REGNUM) {
592         const RegisterInfo *reg_info =
593             reg_ctx->GetRegisterInfoAtIndex(lldb_reg_num);
594         if (reg_info) {
595           RegisterValue reg_value;
596           if (reg_ctx->ReadRegister(reg_info, reg_value)) {
597             reg_value.Dump(&s, reg_info, false, false, format);
598             return true;
599           }
600         }
601       }
602     }
603   }
604   return false;
605 }
606 
607 static ValueObjectSP ExpandIndexedExpression(ValueObject *valobj, size_t index,
608                                              StackFrame *frame,
609                                              bool deref_pointer) {
610   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
611   const char *ptr_deref_format = "[%d]";
612   std::string ptr_deref_buffer(10, 0);
613   ::sprintf(&ptr_deref_buffer[0], ptr_deref_format, index);
614   if (log)
615     log->Printf("[ExpandIndexedExpression] name to deref: %s",
616                 ptr_deref_buffer.c_str());
617   ValueObject::GetValueForExpressionPathOptions options;
618   ValueObject::ExpressionPathEndResultType final_value_type;
619   ValueObject::ExpressionPathScanEndReason reason_to_stop;
620   ValueObject::ExpressionPathAftermath what_next =
621       (deref_pointer ? ValueObject::eExpressionPathAftermathDereference
622                      : ValueObject::eExpressionPathAftermathNothing);
623   ValueObjectSP item = valobj->GetValueForExpressionPath(
624       ptr_deref_buffer.c_str(), &reason_to_stop, &final_value_type, options,
625       &what_next);
626   if (!item) {
627     if (log)
628       log->Printf("[ExpandIndexedExpression] ERROR: why stopping = %d,"
629                   " final_value_type %d",
630                   reason_to_stop, final_value_type);
631   } else {
632     if (log)
633       log->Printf("[ExpandIndexedExpression] ALL RIGHT: why stopping = %d,"
634                   " final_value_type %d",
635                   reason_to_stop, final_value_type);
636   }
637   return item;
638 }
639 
640 static char ConvertValueObjectStyleToChar(
641     ValueObject::ValueObjectRepresentationStyle style) {
642   switch (style) {
643   case ValueObject::eValueObjectRepresentationStyleLanguageSpecific:
644     return '@';
645   case ValueObject::eValueObjectRepresentationStyleValue:
646     return 'V';
647   case ValueObject::eValueObjectRepresentationStyleLocation:
648     return 'L';
649   case ValueObject::eValueObjectRepresentationStyleSummary:
650     return 'S';
651   case ValueObject::eValueObjectRepresentationStyleChildrenCount:
652     return '#';
653   case ValueObject::eValueObjectRepresentationStyleType:
654     return 'T';
655   case ValueObject::eValueObjectRepresentationStyleName:
656     return 'N';
657   case ValueObject::eValueObjectRepresentationStyleExpressionPath:
658     return '>';
659   }
660   return '\0';
661 }
662 
663 static bool DumpValue(Stream &s, const SymbolContext *sc,
664                       const ExecutionContext *exe_ctx,
665                       const FormatEntity::Entry &entry, ValueObject *valobj) {
666   if (valobj == nullptr)
667     return false;
668 
669   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
670   Format custom_format = eFormatInvalid;
671   ValueObject::ValueObjectRepresentationStyle val_obj_display =
672       entry.string.empty()
673           ? ValueObject::eValueObjectRepresentationStyleValue
674           : ValueObject::eValueObjectRepresentationStyleSummary;
675 
676   bool do_deref_pointer = entry.deref;
677   bool is_script = false;
678   switch (entry.type) {
679   case FormatEntity::Entry::Type::ScriptVariable:
680     is_script = true;
681     break;
682 
683   case FormatEntity::Entry::Type::Variable:
684     custom_format = entry.fmt;
685     val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number;
686     break;
687 
688   case FormatEntity::Entry::Type::ScriptVariableSynthetic:
689     is_script = true;
690     LLVM_FALLTHROUGH;
691   case FormatEntity::Entry::Type::VariableSynthetic:
692     custom_format = entry.fmt;
693     val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number;
694     if (!valobj->IsSynthetic()) {
695       valobj = valobj->GetSyntheticValue().get();
696       if (valobj == nullptr)
697         return false;
698     }
699     break;
700 
701   default:
702     return false;
703   }
704 
705   if (valobj == nullptr)
706     return false;
707 
708   ValueObject::ExpressionPathAftermath what_next =
709       (do_deref_pointer ? ValueObject::eExpressionPathAftermathDereference
710                         : ValueObject::eExpressionPathAftermathNothing);
711   ValueObject::GetValueForExpressionPathOptions options;
712   options.DontCheckDotVsArrowSyntax()
713       .DoAllowBitfieldSyntax()
714       .DoAllowFragileIVar()
715       .SetSyntheticChildrenTraversal(
716           ValueObject::GetValueForExpressionPathOptions::
717               SyntheticChildrenTraversal::Both);
718   ValueObject *target = nullptr;
719   const char *var_name_final_if_array_range = nullptr;
720   size_t close_bracket_index = llvm::StringRef::npos;
721   int64_t index_lower = -1;
722   int64_t index_higher = -1;
723   bool is_array_range = false;
724   bool was_plain_var = false;
725   bool was_var_format = false;
726   bool was_var_indexed = false;
727   ValueObject::ExpressionPathScanEndReason reason_to_stop =
728       ValueObject::eExpressionPathScanEndReasonEndOfString;
729   ValueObject::ExpressionPathEndResultType final_value_type =
730       ValueObject::eExpressionPathEndResultTypePlain;
731 
732   if (is_script) {
733     return RunScriptFormatKeyword(s, sc, exe_ctx, valobj, entry.string.c_str());
734   }
735 
736   llvm::StringRef subpath(entry.string);
737   // simplest case ${var}, just print valobj's value
738   if (entry.string.empty()) {
739     if (entry.printf_format.empty() && entry.fmt == eFormatDefault &&
740         entry.number == ValueObject::eValueObjectRepresentationStyleValue)
741       was_plain_var = true;
742     else
743       was_var_format = true;
744     target = valobj;
745   } else // this is ${var.something} or multiple .something nested
746   {
747     if (entry.string[0] == '[')
748       was_var_indexed = true;
749     ScanBracketedRange(subpath, close_bracket_index,
750                        var_name_final_if_array_range, index_lower,
751                        index_higher);
752 
753     Error error;
754 
755     const std::string &expr_path = entry.string;
756 
757     if (log)
758       log->Printf("[Debugger::FormatPrompt] symbol to expand: %s",
759                   expr_path.c_str());
760 
761     target =
762         valobj
763             ->GetValueForExpressionPath(expr_path.c_str(), &reason_to_stop,
764                                         &final_value_type, options, &what_next)
765             .get();
766 
767     if (!target) {
768       if (log)
769         log->Printf("[Debugger::FormatPrompt] ERROR: why stopping = %d,"
770                     " final_value_type %d",
771                     reason_to_stop, final_value_type);
772       return false;
773     } else {
774       if (log)
775         log->Printf("[Debugger::FormatPrompt] ALL RIGHT: why stopping = %d,"
776                     " final_value_type %d",
777                     reason_to_stop, final_value_type);
778       target = target
779                    ->GetQualifiedRepresentationIfAvailable(
780                        target->GetDynamicValueType(), true)
781                    .get();
782     }
783   }
784 
785   is_array_range =
786       (final_value_type ==
787            ValueObject::eExpressionPathEndResultTypeBoundedRange ||
788        final_value_type ==
789            ValueObject::eExpressionPathEndResultTypeUnboundedRange);
790 
791   do_deref_pointer =
792       (what_next == ValueObject::eExpressionPathAftermathDereference);
793 
794   if (do_deref_pointer && !is_array_range) {
795     // I have not deref-ed yet, let's do it
796     // this happens when we are not going through
797     // GetValueForVariableExpressionPath
798     // to get to the target ValueObject
799     Error error;
800     target = target->Dereference(error).get();
801     if (error.Fail()) {
802       if (log)
803         log->Printf("[Debugger::FormatPrompt] ERROR: %s\n",
804                     error.AsCString("unknown"));
805       return false;
806     }
807     do_deref_pointer = false;
808   }
809 
810   if (!target) {
811     if (log)
812       log->Printf("[Debugger::FormatPrompt] could not calculate target for "
813                   "prompt expression");
814     return false;
815   }
816 
817   // we do not want to use the summary for a bitfield of type T:n
818   // if we were originally dealing with just a T - that would get
819   // us into an endless recursion
820   if (target->IsBitfield() && was_var_indexed) {
821     // TODO: check for a (T:n)-specific summary - we should still obey that
822     StreamString bitfield_name;
823     bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(),
824                          target->GetBitfieldBitSize());
825     lldb::TypeNameSpecifierImplSP type_sp(
826         new TypeNameSpecifierImpl(bitfield_name.GetString(), false));
827     if (val_obj_display ==
828             ValueObject::eValueObjectRepresentationStyleSummary &&
829         !DataVisualization::GetSummaryForType(type_sp))
830       val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
831   }
832 
833   // TODO use flags for these
834   const uint32_t type_info_flags =
835       target->GetCompilerType().GetTypeInfo(nullptr);
836   bool is_array = (type_info_flags & eTypeIsArray) != 0;
837   bool is_pointer = (type_info_flags & eTypeIsPointer) != 0;
838   bool is_aggregate = target->GetCompilerType().IsAggregateType();
839 
840   if ((is_array || is_pointer) && (!is_array_range) &&
841       val_obj_display ==
842           ValueObject::eValueObjectRepresentationStyleValue) // this should be
843                                                              // wrong, but there
844                                                              // are some
845                                                              // exceptions
846   {
847     StreamString str_temp;
848     if (log)
849       log->Printf(
850           "[Debugger::FormatPrompt] I am into array || pointer && !range");
851 
852     if (target->HasSpecialPrintableRepresentation(val_obj_display,
853                                                   custom_format)) {
854       // try to use the special cases
855       bool success = target->DumpPrintableRepresentation(
856           str_temp, val_obj_display, custom_format);
857       if (log)
858         log->Printf("[Debugger::FormatPrompt] special cases did%s match",
859                     success ? "" : "n't");
860 
861       // should not happen
862       if (success)
863         s << str_temp.GetString();
864       return true;
865     } else {
866       if (was_plain_var) // if ${var}
867       {
868         s << target->GetTypeName() << " @ " << target->GetLocationAsCString();
869       } else if (is_pointer) // if pointer, value is the address stored
870       {
871         target->DumpPrintableRepresentation(
872             s, val_obj_display, custom_format,
873             ValueObject::PrintableRepresentationSpecialCases::eDisable);
874       }
875       return true;
876     }
877   }
878 
879   // if directly trying to print ${var}, and this is an aggregate, display a
880   // nice
881   // type @ location message
882   if (is_aggregate && was_plain_var) {
883     s << target->GetTypeName() << " @ " << target->GetLocationAsCString();
884     return true;
885   }
886 
887   // if directly trying to print ${var%V}, and this is an aggregate, do not let
888   // the user do it
889   if (is_aggregate &&
890       ((was_var_format &&
891         val_obj_display ==
892             ValueObject::eValueObjectRepresentationStyleValue))) {
893     s << "<invalid use of aggregate type>";
894     return true;
895   }
896 
897   if (!is_array_range) {
898     if (log)
899       log->Printf("[Debugger::FormatPrompt] dumping ordinary printable output");
900     return target->DumpPrintableRepresentation(s, val_obj_display,
901                                                custom_format);
902   } else {
903     if (log)
904       log->Printf("[Debugger::FormatPrompt] checking if I can handle as array");
905     if (!is_array && !is_pointer)
906       return false;
907     if (log)
908       log->Printf("[Debugger::FormatPrompt] handle as array");
909     StreamString special_directions_stream;
910     llvm::StringRef special_directions;
911     if (close_bracket_index != llvm::StringRef::npos &&
912         subpath.size() > close_bracket_index) {
913       ConstString additional_data(subpath.drop_front(close_bracket_index + 1));
914       special_directions_stream.Printf("${%svar%s", do_deref_pointer ? "*" : "",
915                                        additional_data.GetCString());
916 
917       if (entry.fmt != eFormatDefault) {
918         const char format_char =
919             FormatManager::GetFormatAsFormatChar(entry.fmt);
920         if (format_char != '\0')
921           special_directions_stream.Printf("%%%c", format_char);
922         else {
923           const char *format_cstr =
924               FormatManager::GetFormatAsCString(entry.fmt);
925           special_directions_stream.Printf("%%%s", format_cstr);
926         }
927       } else if (entry.number != 0) {
928         const char style_char = ConvertValueObjectStyleToChar(
929             (ValueObject::ValueObjectRepresentationStyle)entry.number);
930         if (style_char)
931           special_directions_stream.Printf("%%%c", style_char);
932       }
933       special_directions_stream.PutChar('}');
934       special_directions =
935           llvm::StringRef(special_directions_stream.GetString());
936     }
937 
938     // let us display items index_lower thru index_higher of this array
939     s.PutChar('[');
940 
941     if (index_higher < 0)
942       index_higher = valobj->GetNumChildren() - 1;
943 
944     uint32_t max_num_children =
945         target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
946 
947     bool success = true;
948     for (int64_t index = index_lower; index <= index_higher; ++index) {
949       ValueObject *item =
950           ExpandIndexedExpression(target, index, exe_ctx->GetFramePtr(), false)
951               .get();
952 
953       if (!item) {
954         if (log)
955           log->Printf("[Debugger::FormatPrompt] ERROR in getting child item at "
956                       "index %" PRId64,
957                       index);
958       } else {
959         if (log)
960           log->Printf(
961               "[Debugger::FormatPrompt] special_directions for child item: %s",
962               special_directions.data() ? special_directions.data() : "");
963       }
964 
965       if (special_directions.empty()) {
966         success &= item->DumpPrintableRepresentation(s, val_obj_display,
967                                                      custom_format);
968       } else {
969         success &= FormatEntity::FormatStringRef(
970             special_directions, s, sc, exe_ctx, nullptr, item, false, false);
971       }
972 
973       if (--max_num_children == 0) {
974         s.PutCString(", ...");
975         break;
976       }
977 
978       if (index < index_higher)
979         s.PutChar(',');
980     }
981     s.PutChar(']');
982     return success;
983   }
984 }
985 
986 static bool DumpRegister(Stream &s, StackFrame *frame, const char *reg_name,
987                          Format format) {
988   if (frame) {
989     RegisterContext *reg_ctx = frame->GetRegisterContext().get();
990 
991     if (reg_ctx) {
992       const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
993       if (reg_info) {
994         RegisterValue reg_value;
995         if (reg_ctx->ReadRegister(reg_info, reg_value)) {
996           reg_value.Dump(&s, reg_info, false, false, format);
997           return true;
998         }
999       }
1000     }
1001   }
1002   return false;
1003 }
1004 
1005 static bool FormatThreadExtendedInfoRecurse(
1006     const FormatEntity::Entry &entry,
1007     const StructuredData::ObjectSP &thread_info_dictionary,
1008     const SymbolContext *sc, const ExecutionContext *exe_ctx, Stream &s) {
1009   llvm::StringRef path(entry.string);
1010 
1011   StructuredData::ObjectSP value =
1012       thread_info_dictionary->GetObjectForDotSeparatedPath(path);
1013 
1014   if (value) {
1015     if (value->GetType() == StructuredData::Type::eTypeInteger) {
1016       const char *token_format = "0x%4.4" PRIx64;
1017       if (!entry.printf_format.empty())
1018         token_format = entry.printf_format.c_str();
1019       s.Printf(token_format, value->GetAsInteger()->GetValue());
1020       return true;
1021     } else if (value->GetType() == StructuredData::Type::eTypeFloat) {
1022       s.Printf("%f", value->GetAsFloat()->GetValue());
1023       return true;
1024     } else if (value->GetType() == StructuredData::Type::eTypeString) {
1025       s.Printf("%s", value->GetAsString()->GetValue().c_str());
1026       return true;
1027     } else if (value->GetType() == StructuredData::Type::eTypeArray) {
1028       if (value->GetAsArray()->GetSize() > 0) {
1029         s.Printf("%zu", value->GetAsArray()->GetSize());
1030         return true;
1031       }
1032     } else if (value->GetType() == StructuredData::Type::eTypeDictionary) {
1033       s.Printf("%zu",
1034                value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize());
1035       return true;
1036     }
1037   }
1038 
1039   return false;
1040 }
1041 
1042 static inline bool IsToken(const char *var_name_begin, const char *var) {
1043   return (::strncmp(var_name_begin, var, strlen(var)) == 0);
1044 }
1045 
1046 bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream &s,
1047                                    const SymbolContext *sc,
1048                                    const ExecutionContext *exe_ctx,
1049                                    const Address *addr, ValueObject *valobj,
1050                                    bool function_changed,
1051                                    bool initial_function) {
1052   if (!format_str.empty()) {
1053     FormatEntity::Entry root;
1054     Error error = FormatEntity::Parse(format_str, root);
1055     if (error.Success()) {
1056       return FormatEntity::Format(root, s, sc, exe_ctx, addr, valobj,
1057                                   function_changed, initial_function);
1058     }
1059   }
1060   return false;
1061 }
1062 
1063 bool FormatEntity::FormatCString(const char *format, Stream &s,
1064                                  const SymbolContext *sc,
1065                                  const ExecutionContext *exe_ctx,
1066                                  const Address *addr, ValueObject *valobj,
1067                                  bool function_changed, bool initial_function) {
1068   if (format && format[0]) {
1069     FormatEntity::Entry root;
1070     llvm::StringRef format_str(format);
1071     Error error = FormatEntity::Parse(format_str, root);
1072     if (error.Success()) {
1073       return FormatEntity::Format(root, s, sc, exe_ctx, addr, valobj,
1074                                   function_changed, initial_function);
1075     }
1076   }
1077   return false;
1078 }
1079 
1080 bool FormatEntity::Format(const Entry &entry, Stream &s,
1081                           const SymbolContext *sc,
1082                           const ExecutionContext *exe_ctx, const Address *addr,
1083                           ValueObject *valobj, bool function_changed,
1084                           bool initial_function) {
1085   switch (entry.type) {
1086   case Entry::Type::Invalid:
1087   case Entry::Type::ParentNumber: // Only used for
1088                                   // FormatEntity::Entry::Definition encoding
1089   case Entry::Type::ParentString: // Only used for
1090                                   // FormatEntity::Entry::Definition encoding
1091   case Entry::Type::InsertString: // Only used for
1092                                   // FormatEntity::Entry::Definition encoding
1093     return false;
1094 
1095   case Entry::Type::Root:
1096     for (const auto &child : entry.children) {
1097       if (!Format(child, s, sc, exe_ctx, addr, valobj, function_changed,
1098                   initial_function)) {
1099         return false; // If any item of root fails, then the formatting fails
1100       }
1101     }
1102     return true; // Only return true if all items succeeded
1103 
1104   case Entry::Type::String:
1105     s.PutCString(entry.string);
1106     return true;
1107 
1108   case Entry::Type::Scope: {
1109     StreamString scope_stream;
1110     bool success = false;
1111     for (const auto &child : entry.children) {
1112       success = Format(child, scope_stream, sc, exe_ctx, addr, valobj,
1113                        function_changed, initial_function);
1114       if (!success)
1115         break;
1116     }
1117     // Only if all items in a scope succeed, then do we
1118     // print the output into the main stream
1119     if (success)
1120       s.Write(scope_stream.GetString().data(), scope_stream.GetString().size());
1121   }
1122     return true; // Scopes always successfully print themselves
1123 
1124   case Entry::Type::Variable:
1125   case Entry::Type::VariableSynthetic:
1126   case Entry::Type::ScriptVariable:
1127   case Entry::Type::ScriptVariableSynthetic:
1128     return DumpValue(s, sc, exe_ctx, entry, valobj);
1129 
1130   case Entry::Type::AddressFile:
1131   case Entry::Type::AddressLoad:
1132   case Entry::Type::AddressLoadOrFile:
1133     return (addr != nullptr && addr->IsValid() &&
1134             DumpAddress(s, sc, exe_ctx, *addr,
1135                         entry.type == Entry::Type::AddressLoadOrFile));
1136 
1137   case Entry::Type::ProcessID:
1138     if (exe_ctx) {
1139       Process *process = exe_ctx->GetProcessPtr();
1140       if (process) {
1141         const char *format = "%" PRIu64;
1142         if (!entry.printf_format.empty())
1143           format = entry.printf_format.c_str();
1144         s.Printf(format, process->GetID());
1145         return true;
1146       }
1147     }
1148     return false;
1149 
1150   case Entry::Type::ProcessFile:
1151     if (exe_ctx) {
1152       Process *process = exe_ctx->GetProcessPtr();
1153       if (process) {
1154         Module *exe_module = process->GetTarget().GetExecutableModulePointer();
1155         if (exe_module) {
1156           if (DumpFile(s, exe_module->GetFileSpec(), (FileKind)entry.number))
1157             return true;
1158         }
1159       }
1160     }
1161     return false;
1162 
1163   case Entry::Type::ScriptProcess:
1164     if (exe_ctx) {
1165       Process *process = exe_ctx->GetProcessPtr();
1166       if (process)
1167         return RunScriptFormatKeyword(s, sc, exe_ctx, process,
1168                                       entry.string.c_str());
1169     }
1170     return false;
1171 
1172   case Entry::Type::ThreadID:
1173     if (exe_ctx) {
1174       Thread *thread = exe_ctx->GetThreadPtr();
1175       if (thread) {
1176         const char *format = "0x%4.4" PRIx64;
1177         if (!entry.printf_format.empty()) {
1178           // Watch for the special "tid" format...
1179           if (entry.printf_format == "tid") {
1180             // TODO(zturner): Rather than hardcoding this to be platform
1181             // specific, it should be controlled by a
1182             // setting and the default value of the setting can be different
1183             // depending on the platform.
1184             Target &target = thread->GetProcess()->GetTarget();
1185             ArchSpec arch(target.GetArchitecture());
1186             llvm::Triple::OSType ostype = arch.IsValid()
1187                                               ? arch.GetTriple().getOS()
1188                                               : llvm::Triple::UnknownOS;
1189             if ((ostype == llvm::Triple::FreeBSD) ||
1190                 (ostype == llvm::Triple::Linux)) {
1191               format = "%" PRIu64;
1192             }
1193           } else {
1194             format = entry.printf_format.c_str();
1195           }
1196         }
1197         s.Printf(format, thread->GetID());
1198         return true;
1199       }
1200     }
1201     return false;
1202 
1203   case Entry::Type::ThreadProtocolID:
1204     if (exe_ctx) {
1205       Thread *thread = exe_ctx->GetThreadPtr();
1206       if (thread) {
1207         const char *format = "0x%4.4" PRIx64;
1208         if (!entry.printf_format.empty())
1209           format = entry.printf_format.c_str();
1210         s.Printf(format, thread->GetProtocolID());
1211         return true;
1212       }
1213     }
1214     return false;
1215 
1216   case Entry::Type::ThreadIndexID:
1217     if (exe_ctx) {
1218       Thread *thread = exe_ctx->GetThreadPtr();
1219       if (thread) {
1220         const char *format = "%" PRIu32;
1221         if (!entry.printf_format.empty())
1222           format = entry.printf_format.c_str();
1223         s.Printf(format, thread->GetIndexID());
1224         return true;
1225       }
1226     }
1227     return false;
1228 
1229   case Entry::Type::ThreadName:
1230     if (exe_ctx) {
1231       Thread *thread = exe_ctx->GetThreadPtr();
1232       if (thread) {
1233         const char *cstr = thread->GetName();
1234         if (cstr && cstr[0]) {
1235           s.PutCString(cstr);
1236           return true;
1237         }
1238       }
1239     }
1240     return false;
1241 
1242   case Entry::Type::ThreadQueue:
1243     if (exe_ctx) {
1244       Thread *thread = exe_ctx->GetThreadPtr();
1245       if (thread) {
1246         const char *cstr = thread->GetQueueName();
1247         if (cstr && cstr[0]) {
1248           s.PutCString(cstr);
1249           return true;
1250         }
1251       }
1252     }
1253     return false;
1254 
1255   case Entry::Type::ThreadStopReason:
1256     if (exe_ctx) {
1257       Thread *thread = exe_ctx->GetThreadPtr();
1258       if (thread) {
1259         StopInfoSP stop_info_sp = thread->GetStopInfo();
1260         if (stop_info_sp && stop_info_sp->IsValid()) {
1261           const char *cstr = stop_info_sp->GetDescription();
1262           if (cstr && cstr[0]) {
1263             s.PutCString(cstr);
1264             return true;
1265           }
1266         }
1267       }
1268     }
1269     return false;
1270 
1271   case Entry::Type::ThreadReturnValue:
1272     if (exe_ctx) {
1273       Thread *thread = exe_ctx->GetThreadPtr();
1274       if (thread) {
1275         StopInfoSP stop_info_sp = thread->GetStopInfo();
1276         if (stop_info_sp && stop_info_sp->IsValid()) {
1277           ValueObjectSP return_valobj_sp =
1278               StopInfo::GetReturnValueObject(stop_info_sp);
1279           if (return_valobj_sp) {
1280             return_valobj_sp->Dump(s);
1281             return true;
1282           }
1283         }
1284       }
1285     }
1286     return false;
1287 
1288   case Entry::Type::ThreadCompletedExpression:
1289     if (exe_ctx) {
1290       Thread *thread = exe_ctx->GetThreadPtr();
1291       if (thread) {
1292         StopInfoSP stop_info_sp = thread->GetStopInfo();
1293         if (stop_info_sp && stop_info_sp->IsValid()) {
1294           ExpressionVariableSP expression_var_sp =
1295               StopInfo::GetExpressionVariable(stop_info_sp);
1296           if (expression_var_sp && expression_var_sp->GetValueObject()) {
1297             expression_var_sp->GetValueObject()->Dump(s);
1298             return true;
1299           }
1300         }
1301       }
1302     }
1303     return false;
1304 
1305   case Entry::Type::ScriptThread:
1306     if (exe_ctx) {
1307       Thread *thread = exe_ctx->GetThreadPtr();
1308       if (thread)
1309         return RunScriptFormatKeyword(s, sc, exe_ctx, thread,
1310                                       entry.string.c_str());
1311     }
1312     return false;
1313 
1314   case Entry::Type::ThreadInfo:
1315     if (exe_ctx) {
1316       Thread *thread = exe_ctx->GetThreadPtr();
1317       if (thread) {
1318         StructuredData::ObjectSP object_sp = thread->GetExtendedInfo();
1319         if (object_sp &&
1320             object_sp->GetType() == StructuredData::Type::eTypeDictionary) {
1321           if (FormatThreadExtendedInfoRecurse(entry, object_sp, sc, exe_ctx, s))
1322             return true;
1323         }
1324       }
1325     }
1326     return false;
1327 
1328   case Entry::Type::TargetArch:
1329     if (exe_ctx) {
1330       Target *target = exe_ctx->GetTargetPtr();
1331       if (target) {
1332         const ArchSpec &arch = target->GetArchitecture();
1333         if (arch.IsValid()) {
1334           s.PutCString(arch.GetArchitectureName());
1335           return true;
1336         }
1337       }
1338     }
1339     return false;
1340 
1341   case Entry::Type::ScriptTarget:
1342     if (exe_ctx) {
1343       Target *target = exe_ctx->GetTargetPtr();
1344       if (target)
1345         return RunScriptFormatKeyword(s, sc, exe_ctx, target,
1346                                       entry.string.c_str());
1347     }
1348     return false;
1349 
1350   case Entry::Type::ModuleFile:
1351     if (sc) {
1352       Module *module = sc->module_sp.get();
1353       if (module) {
1354         if (DumpFile(s, module->GetFileSpec(), (FileKind)entry.number))
1355           return true;
1356       }
1357     }
1358     return false;
1359 
1360   case Entry::Type::File:
1361     if (sc) {
1362       CompileUnit *cu = sc->comp_unit;
1363       if (cu) {
1364         // CompileUnit is a FileSpec
1365         if (DumpFile(s, *cu, (FileKind)entry.number))
1366           return true;
1367       }
1368     }
1369     return false;
1370 
1371   case Entry::Type::Lang:
1372     if (sc) {
1373       CompileUnit *cu = sc->comp_unit;
1374       if (cu) {
1375         const char *lang_name =
1376             Language::GetNameForLanguageType(cu->GetLanguage());
1377         if (lang_name) {
1378           s.PutCString(lang_name);
1379           return true;
1380         }
1381       }
1382     }
1383     return false;
1384 
1385   case Entry::Type::FrameIndex:
1386     if (exe_ctx) {
1387       StackFrame *frame = exe_ctx->GetFramePtr();
1388       if (frame) {
1389         const char *format = "%" PRIu32;
1390         if (!entry.printf_format.empty())
1391           format = entry.printf_format.c_str();
1392         s.Printf(format, frame->GetFrameIndex());
1393         return true;
1394       }
1395     }
1396     return false;
1397 
1398   case Entry::Type::FrameRegisterPC:
1399     if (exe_ctx) {
1400       StackFrame *frame = exe_ctx->GetFramePtr();
1401       if (frame) {
1402         const Address &pc_addr = frame->GetFrameCodeAddress();
1403         if (pc_addr.IsValid()) {
1404           if (DumpAddress(s, sc, exe_ctx, pc_addr, false))
1405             return true;
1406         }
1407       }
1408     }
1409     return false;
1410 
1411   case Entry::Type::FrameRegisterSP:
1412     if (exe_ctx) {
1413       StackFrame *frame = exe_ctx->GetFramePtr();
1414       if (frame) {
1415         if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP,
1416                          (lldb::Format)entry.number))
1417           return true;
1418       }
1419     }
1420     return false;
1421 
1422   case Entry::Type::FrameRegisterFP:
1423     if (exe_ctx) {
1424       StackFrame *frame = exe_ctx->GetFramePtr();
1425       if (frame) {
1426         if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP,
1427                          (lldb::Format)entry.number))
1428           return true;
1429       }
1430     }
1431     return false;
1432 
1433   case Entry::Type::FrameRegisterFlags:
1434     if (exe_ctx) {
1435       StackFrame *frame = exe_ctx->GetFramePtr();
1436       if (frame) {
1437         if (DumpRegister(s, frame, eRegisterKindGeneric,
1438                          LLDB_REGNUM_GENERIC_FLAGS, (lldb::Format)entry.number))
1439           return true;
1440       }
1441     }
1442     return false;
1443 
1444   case Entry::Type::FrameNoDebug:
1445     if (exe_ctx) {
1446       StackFrame *frame = exe_ctx->GetFramePtr();
1447       if (frame) {
1448         return !frame->HasDebugInformation();
1449       }
1450     }
1451     return true;
1452 
1453   case Entry::Type::FrameRegisterByName:
1454     if (exe_ctx) {
1455       StackFrame *frame = exe_ctx->GetFramePtr();
1456       if (frame) {
1457         if (DumpRegister(s, frame, entry.string.c_str(),
1458                          (lldb::Format)entry.number))
1459           return true;
1460       }
1461     }
1462     return false;
1463 
1464   case Entry::Type::ScriptFrame:
1465     if (exe_ctx) {
1466       StackFrame *frame = exe_ctx->GetFramePtr();
1467       if (frame)
1468         return RunScriptFormatKeyword(s, sc, exe_ctx, frame,
1469                                       entry.string.c_str());
1470     }
1471     return false;
1472 
1473   case Entry::Type::FunctionID:
1474     if (sc) {
1475       if (sc->function) {
1476         s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID());
1477         return true;
1478       } else if (sc->symbol) {
1479         s.Printf("symbol[%u]", sc->symbol->GetID());
1480         return true;
1481       }
1482     }
1483     return false;
1484 
1485   case Entry::Type::FunctionDidChange:
1486     return function_changed;
1487 
1488   case Entry::Type::FunctionInitialFunction:
1489     return initial_function;
1490 
1491   case Entry::Type::FunctionName: {
1492     Language *language_plugin = nullptr;
1493     bool language_plugin_handled = false;
1494     StreamString ss;
1495     if (sc->function)
1496       language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1497     else if (sc->symbol)
1498       language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1499     if (language_plugin) {
1500       language_plugin_handled = language_plugin->GetFunctionDisplayName(
1501           sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
1502     }
1503     if (language_plugin_handled) {
1504       s << ss.GetString();
1505       return true;
1506     } else {
1507       const char *name = nullptr;
1508       if (sc->function)
1509         name = sc->function->GetName().AsCString(nullptr);
1510       else if (sc->symbol)
1511         name = sc->symbol->GetName().AsCString(nullptr);
1512       if (name) {
1513         s.PutCString(name);
1514 
1515         if (sc->block) {
1516           Block *inline_block = sc->block->GetContainingInlinedBlock();
1517           if (inline_block) {
1518             const InlineFunctionInfo *inline_info =
1519                 sc->block->GetInlinedFunctionInfo();
1520             if (inline_info) {
1521               s.PutCString(" [inlined] ");
1522               inline_info->GetName(sc->function->GetLanguage()).Dump(&s);
1523             }
1524           }
1525         }
1526         return true;
1527       }
1528     }
1529   }
1530     return false;
1531 
1532   case Entry::Type::FunctionNameNoArgs: {
1533     Language *language_plugin = nullptr;
1534     bool language_plugin_handled = false;
1535     StreamString ss;
1536     if (sc->function)
1537       language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1538     else if (sc->symbol)
1539       language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1540     if (language_plugin) {
1541       language_plugin_handled = language_plugin->GetFunctionDisplayName(
1542           sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
1543           ss);
1544     }
1545     if (language_plugin_handled) {
1546       s << ss.GetString();
1547       return true;
1548     } else {
1549       ConstString name;
1550       if (sc->function)
1551         name = sc->function->GetNameNoArguments();
1552       else if (sc->symbol)
1553         name = sc->symbol->GetNameNoArguments();
1554       if (name) {
1555         s.PutCString(name.GetCString());
1556         return true;
1557       }
1558     }
1559   }
1560     return false;
1561 
1562   case Entry::Type::FunctionNameWithArgs: {
1563     Language *language_plugin = nullptr;
1564     bool language_plugin_handled = false;
1565     StreamString ss;
1566     if (sc->function)
1567       language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1568     else if (sc->symbol)
1569       language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1570     if (language_plugin) {
1571       language_plugin_handled = language_plugin->GetFunctionDisplayName(
1572           sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss);
1573     }
1574     if (language_plugin_handled) {
1575       s << ss.GetString();
1576       return true;
1577     } else {
1578       // Print the function name with arguments in it
1579       if (sc->function) {
1580         ExecutionContextScope *exe_scope =
1581             exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
1582         const char *cstr = sc->function->GetName().AsCString(nullptr);
1583         if (cstr) {
1584           const InlineFunctionInfo *inline_info = nullptr;
1585           VariableListSP variable_list_sp;
1586           bool get_function_vars = true;
1587           if (sc->block) {
1588             Block *inline_block = sc->block->GetContainingInlinedBlock();
1589 
1590             if (inline_block) {
1591               get_function_vars = false;
1592               inline_info = sc->block->GetInlinedFunctionInfo();
1593               if (inline_info)
1594                 variable_list_sp = inline_block->GetBlockVariableList(true);
1595             }
1596           }
1597 
1598           if (get_function_vars) {
1599             variable_list_sp =
1600                 sc->function->GetBlock(true).GetBlockVariableList(true);
1601           }
1602 
1603           if (inline_info) {
1604             s.PutCString(cstr);
1605             s.PutCString(" [inlined] ");
1606             cstr =
1607                 inline_info->GetName(sc->function->GetLanguage()).GetCString();
1608           }
1609 
1610           VariableList args;
1611           if (variable_list_sp)
1612             variable_list_sp->AppendVariablesWithScope(
1613                 eValueTypeVariableArgument, args);
1614           if (args.GetSize() > 0) {
1615             const char *open_paren = strchr(cstr, '(');
1616             const char *close_paren = nullptr;
1617             const char *generic = strchr(cstr, '<');
1618             // if before the arguments list begins there is a template sign
1619             // then scan to the end of the generic args before you try to find
1620             // the arguments list
1621             if (generic && open_paren && generic < open_paren) {
1622               int generic_depth = 1;
1623               ++generic;
1624               for (; *generic && generic_depth > 0; generic++) {
1625                 if (*generic == '<')
1626                   generic_depth++;
1627                 if (*generic == '>')
1628                   generic_depth--;
1629               }
1630               if (*generic)
1631                 open_paren = strchr(generic, '(');
1632               else
1633                 open_paren = nullptr;
1634             }
1635             if (open_paren) {
1636               if (IsToken(open_paren, "(anonymous namespace)")) {
1637                 open_paren =
1638                     strchr(open_paren + strlen("(anonymous namespace)"), '(');
1639                 if (open_paren)
1640                   close_paren = strchr(open_paren, ')');
1641               } else
1642                 close_paren = strchr(open_paren, ')');
1643             }
1644 
1645             if (open_paren)
1646               s.Write(cstr, open_paren - cstr + 1);
1647             else {
1648               s.PutCString(cstr);
1649               s.PutChar('(');
1650             }
1651             const size_t num_args = args.GetSize();
1652             for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) {
1653               std::string buffer;
1654 
1655               VariableSP var_sp(args.GetVariableAtIndex(arg_idx));
1656               ValueObjectSP var_value_sp(
1657                   ValueObjectVariable::Create(exe_scope, var_sp));
1658               StreamString ss;
1659               llvm::StringRef var_representation;
1660               const char *var_name = var_value_sp->GetName().GetCString();
1661               if (var_value_sp->GetCompilerType().IsValid()) {
1662                 if (var_value_sp && exe_scope->CalculateTarget())
1663                   var_value_sp =
1664                       var_value_sp->GetQualifiedRepresentationIfAvailable(
1665                           exe_scope->CalculateTarget()
1666                               ->TargetProperties::GetPreferDynamicValue(),
1667                           exe_scope->CalculateTarget()
1668                               ->TargetProperties::GetEnableSyntheticValue());
1669                 if (var_value_sp->GetCompilerType().IsAggregateType() &&
1670                     DataVisualization::ShouldPrintAsOneLiner(*var_value_sp)) {
1671                   static StringSummaryFormat format(
1672                       TypeSummaryImpl::Flags()
1673                           .SetHideItemNames(false)
1674                           .SetShowMembersOneLiner(true),
1675                       "");
1676                   format.FormatObject(var_value_sp.get(), buffer,
1677                                       TypeSummaryOptions());
1678                   var_representation = buffer;
1679                 } else
1680                   var_value_sp->DumpPrintableRepresentation(
1681                       ss, ValueObject::ValueObjectRepresentationStyle::
1682                               eValueObjectRepresentationStyleSummary,
1683                       eFormatDefault,
1684                       ValueObject::PrintableRepresentationSpecialCases::eAllow,
1685                       false);
1686               }
1687 
1688               if (!ss.GetString().empty())
1689                 var_representation = ss.GetString();
1690               if (arg_idx > 0)
1691                 s.PutCString(", ");
1692               if (var_value_sp->GetError().Success()) {
1693                 if (!var_representation.empty())
1694                   s.Printf("%s=%s", var_name, var_representation.str().c_str());
1695                 else
1696                   s.Printf("%s=%s at %s", var_name,
1697                            var_value_sp->GetTypeName().GetCString(),
1698                            var_value_sp->GetLocationAsCString());
1699               } else
1700                 s.Printf("%s=<unavailable>", var_name);
1701             }
1702 
1703             if (close_paren)
1704               s.PutCString(close_paren);
1705             else
1706               s.PutChar(')');
1707 
1708           } else {
1709             s.PutCString(cstr);
1710           }
1711           return true;
1712         }
1713       } else if (sc->symbol) {
1714         const char *cstr = sc->symbol->GetName().AsCString(nullptr);
1715         if (cstr) {
1716           s.PutCString(cstr);
1717           return true;
1718         }
1719       }
1720     }
1721   }
1722     return false;
1723 
1724   case Entry::Type::FunctionAddrOffset:
1725     if (addr) {
1726       if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, false, false,
1727                                         false))
1728         return true;
1729     }
1730     return false;
1731 
1732   case Entry::Type::FunctionAddrOffsetConcrete:
1733     if (addr) {
1734       if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, true, true,
1735                                         true))
1736         return true;
1737     }
1738     return false;
1739 
1740   case Entry::Type::FunctionLineOffset:
1741     return (DumpAddressOffsetFromFunction(s, sc, exe_ctx,
1742                                           sc->line_entry.range.GetBaseAddress(),
1743                                           false, false, false));
1744 
1745   case Entry::Type::FunctionPCOffset:
1746     if (exe_ctx) {
1747       StackFrame *frame = exe_ctx->GetFramePtr();
1748       if (frame) {
1749         if (DumpAddressOffsetFromFunction(s, sc, exe_ctx,
1750                                           frame->GetFrameCodeAddress(), false,
1751                                           false, false))
1752           return true;
1753       }
1754     }
1755     return false;
1756 
1757   case Entry::Type::FunctionChanged:
1758     return function_changed;
1759 
1760   case Entry::Type::FunctionIsOptimized: {
1761     bool is_optimized = false;
1762     if (sc->function && sc->function->GetIsOptimized()) {
1763       is_optimized = true;
1764     }
1765     return is_optimized;
1766   }
1767 
1768   case Entry::Type::FunctionInitial:
1769     return initial_function;
1770 
1771   case Entry::Type::LineEntryFile:
1772     if (sc && sc->line_entry.IsValid()) {
1773       Module *module = sc->module_sp.get();
1774       if (module) {
1775         if (DumpFile(s, sc->line_entry.file, (FileKind)entry.number))
1776           return true;
1777       }
1778     }
1779     return false;
1780 
1781   case Entry::Type::LineEntryLineNumber:
1782     if (sc && sc->line_entry.IsValid()) {
1783       const char *format = "%" PRIu32;
1784       if (!entry.printf_format.empty())
1785         format = entry.printf_format.c_str();
1786       s.Printf(format, sc->line_entry.line);
1787       return true;
1788     }
1789     return false;
1790 
1791   case Entry::Type::LineEntryStartAddress:
1792   case Entry::Type::LineEntryEndAddress:
1793     if (sc && sc->line_entry.range.GetBaseAddress().IsValid()) {
1794       Address addr = sc->line_entry.range.GetBaseAddress();
1795 
1796       if (entry.type == Entry::Type::LineEntryEndAddress)
1797         addr.Slide(sc->line_entry.range.GetByteSize());
1798       if (DumpAddress(s, sc, exe_ctx, addr, false))
1799         return true;
1800     }
1801     return false;
1802 
1803   case Entry::Type::CurrentPCArrow:
1804     if (addr && exe_ctx && exe_ctx->GetFramePtr()) {
1805       RegisterContextSP reg_ctx =
1806           exe_ctx->GetFramePtr()->GetRegisterContextSP();
1807       if (reg_ctx) {
1808         addr_t pc_loadaddr = reg_ctx->GetPC();
1809         if (pc_loadaddr != LLDB_INVALID_ADDRESS) {
1810           Address pc;
1811           pc.SetLoadAddress(pc_loadaddr, exe_ctx->GetTargetPtr());
1812           if (pc == *addr) {
1813             s.Printf("-> ");
1814             return true;
1815           }
1816         }
1817       }
1818       s.Printf("   ");
1819       return true;
1820     }
1821     return false;
1822   }
1823   return false;
1824 }
1825 
1826 static bool DumpCommaSeparatedChildEntryNames(
1827     Stream &s, const FormatEntity::Entry::Definition *parent) {
1828   if (parent->children) {
1829     const size_t n = parent->num_children;
1830     for (size_t i = 0; i < n; ++i) {
1831       if (i > 0)
1832         s.PutCString(", ");
1833       s.Printf("\"%s\"", parent->children[i].name);
1834     }
1835     return true;
1836   }
1837   return false;
1838 }
1839 
1840 static Error ParseEntry(const llvm::StringRef &format_str,
1841                         const FormatEntity::Entry::Definition *parent,
1842                         FormatEntity::Entry &entry) {
1843   Error error;
1844 
1845   const size_t sep_pos = format_str.find_first_of(".[:");
1846   const char sep_char =
1847       (sep_pos == llvm::StringRef::npos) ? '\0' : format_str[sep_pos];
1848   llvm::StringRef key = format_str.substr(0, sep_pos);
1849 
1850   const size_t n = parent->num_children;
1851   for (size_t i = 0; i < n; ++i) {
1852     const FormatEntity::Entry::Definition *entry_def = parent->children + i;
1853     if (key.equals(entry_def->name) || entry_def->name[0] == '*') {
1854       llvm::StringRef value;
1855       if (sep_char)
1856         value =
1857             format_str.substr(sep_pos + (entry_def->keep_separator ? 0 : 1));
1858       switch (entry_def->type) {
1859       case FormatEntity::Entry::Type::ParentString:
1860         entry.string = format_str.str();
1861         return error; // Success
1862 
1863       case FormatEntity::Entry::Type::ParentNumber:
1864         entry.number = entry_def->data;
1865         return error; // Success
1866 
1867       case FormatEntity::Entry::Type::InsertString:
1868         entry.type = entry_def->type;
1869         entry.string = entry_def->string;
1870         return error; // Success
1871 
1872       default:
1873         entry.type = entry_def->type;
1874         break;
1875       }
1876 
1877       if (value.empty()) {
1878         if (entry_def->type == FormatEntity::Entry::Type::Invalid) {
1879           if (entry_def->children) {
1880             StreamString error_strm;
1881             error_strm.Printf("'%s' can't be specified on its own, you must "
1882                               "access one of its children: ",
1883                               entry_def->name);
1884             DumpCommaSeparatedChildEntryNames(error_strm, entry_def);
1885             error.SetErrorStringWithFormat("%s", error_strm.GetData());
1886           } else if (sep_char == ':') {
1887             // Any value whose separator is a with a ':' means this value has a
1888             // string argument
1889             // that needs to be stored in the entry (like "${script.var:}").
1890             // In this case the string value is the empty string which is ok.
1891           } else {
1892             error.SetErrorStringWithFormat("%s", "invalid entry definitions");
1893           }
1894         }
1895       } else {
1896         if (entry_def->children) {
1897           error = ParseEntry(value, entry_def, entry);
1898         } else if (sep_char == ':') {
1899           // Any value whose separator is a with a ':' means this value has a
1900           // string argument
1901           // that needs to be stored in the entry (like
1902           // "${script.var:modulename.function}")
1903           entry.string = value.str();
1904         } else {
1905           error.SetErrorStringWithFormat(
1906               "'%s' followed by '%s' but it has no children", key.str().c_str(),
1907               value.str().c_str());
1908         }
1909       }
1910       return error;
1911     }
1912   }
1913   StreamString error_strm;
1914   if (parent->type == FormatEntity::Entry::Type::Root)
1915     error_strm.Printf(
1916         "invalid top level item '%s'. Valid top level items are: ",
1917         key.str().c_str());
1918   else
1919     error_strm.Printf("invalid member '%s' in '%s'. Valid members are: ",
1920                       key.str().c_str(), parent->name);
1921   DumpCommaSeparatedChildEntryNames(error_strm, parent);
1922   error.SetErrorStringWithFormat("%s", error_strm.GetData());
1923   return error;
1924 }
1925 
1926 static const FormatEntity::Entry::Definition *
1927 FindEntry(const llvm::StringRef &format_str,
1928           const FormatEntity::Entry::Definition *parent,
1929           llvm::StringRef &remainder) {
1930   Error error;
1931 
1932   std::pair<llvm::StringRef, llvm::StringRef> p = format_str.split('.');
1933   const size_t n = parent->num_children;
1934   for (size_t i = 0; i < n; ++i) {
1935     const FormatEntity::Entry::Definition *entry_def = parent->children + i;
1936     if (p.first.equals(entry_def->name) || entry_def->name[0] == '*') {
1937       if (p.second.empty()) {
1938         if (format_str.back() == '.')
1939           remainder = format_str.drop_front(format_str.size() - 1);
1940         else
1941           remainder = llvm::StringRef(); // Exact match
1942         return entry_def;
1943       } else {
1944         if (entry_def->children) {
1945           return FindEntry(p.second, entry_def, remainder);
1946         } else {
1947           remainder = p.second;
1948           return entry_def;
1949         }
1950       }
1951     }
1952   }
1953   remainder = format_str;
1954   return parent;
1955 }
1956 
1957 Error FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry,
1958                                   uint32_t depth) {
1959   Error error;
1960   while (!format.empty() && error.Success()) {
1961     const size_t non_special_chars = format.find_first_of("${}\\");
1962 
1963     if (non_special_chars == llvm::StringRef::npos) {
1964       // No special characters, just string bytes so add them and we are done
1965       parent_entry.AppendText(format);
1966       return error;
1967     }
1968 
1969     if (non_special_chars > 0) {
1970       // We have a special character, so add all characters before these as a
1971       // plain string
1972       parent_entry.AppendText(format.substr(0, non_special_chars));
1973       format = format.drop_front(non_special_chars);
1974     }
1975 
1976     switch (format[0]) {
1977     case '\0':
1978       return error;
1979 
1980     case '{': {
1981       format = format.drop_front(); // Skip the '{'
1982       Entry scope_entry(Entry::Type::Scope);
1983       error = FormatEntity::ParseInternal(format, scope_entry, depth + 1);
1984       if (error.Fail())
1985         return error;
1986       parent_entry.AppendEntry(std::move(scope_entry));
1987     } break;
1988 
1989     case '}':
1990       if (depth == 0)
1991         error.SetErrorString("unmatched '}' character");
1992       else
1993         format =
1994             format
1995                 .drop_front(); // Skip the '}' as we are at the end of the scope
1996       return error;
1997 
1998     case '\\': {
1999       format = format.drop_front(); // Skip the '\' character
2000       if (format.empty()) {
2001         error.SetErrorString(
2002             "'\\' character was not followed by another character");
2003         return error;
2004       }
2005 
2006       const char desens_char = format[0];
2007       format = format.drop_front(); // Skip the desensitized char character
2008       switch (desens_char) {
2009       case 'a':
2010         parent_entry.AppendChar('\a');
2011         break;
2012       case 'b':
2013         parent_entry.AppendChar('\b');
2014         break;
2015       case 'f':
2016         parent_entry.AppendChar('\f');
2017         break;
2018       case 'n':
2019         parent_entry.AppendChar('\n');
2020         break;
2021       case 'r':
2022         parent_entry.AppendChar('\r');
2023         break;
2024       case 't':
2025         parent_entry.AppendChar('\t');
2026         break;
2027       case 'v':
2028         parent_entry.AppendChar('\v');
2029         break;
2030       case '\'':
2031         parent_entry.AppendChar('\'');
2032         break;
2033       case '\\':
2034         parent_entry.AppendChar('\\');
2035         break;
2036       case '0':
2037         // 1 to 3 octal chars
2038         {
2039           // Make a string that can hold onto the initial zero char,
2040           // up to 3 octal digits, and a terminating NULL.
2041           char oct_str[5] = {0, 0, 0, 0, 0};
2042 
2043           int i;
2044           for (i = 0; (format[i] >= '0' && format[i] <= '7') && i < 4; ++i)
2045             oct_str[i] = format[i];
2046 
2047           // We don't want to consume the last octal character since
2048           // the main for loop will do this for us, so we advance p by
2049           // one less than i (even if i is zero)
2050           format = format.drop_front(i);
2051           unsigned long octal_value = ::strtoul(oct_str, nullptr, 8);
2052           if (octal_value <= UINT8_MAX) {
2053             parent_entry.AppendChar((char)octal_value);
2054           } else {
2055             error.SetErrorString("octal number is larger than a single byte");
2056             return error;
2057           }
2058         }
2059         break;
2060 
2061       case 'x':
2062         // hex number in the format
2063         if (isxdigit(format[0])) {
2064           // Make a string that can hold onto two hex chars plus a
2065           // NULL terminator
2066           char hex_str[3] = {0, 0, 0};
2067           hex_str[0] = format[0];
2068 
2069           format = format.drop_front();
2070 
2071           if (isxdigit(format[0])) {
2072             hex_str[1] = format[0];
2073             format = format.drop_front();
2074           }
2075 
2076           unsigned long hex_value = strtoul(hex_str, nullptr, 16);
2077           if (hex_value <= UINT8_MAX) {
2078             parent_entry.AppendChar((char)hex_value);
2079           } else {
2080             error.SetErrorString("hex number is larger than a single byte");
2081             return error;
2082           }
2083         } else {
2084           parent_entry.AppendChar(desens_char);
2085         }
2086         break;
2087 
2088       default:
2089         // Just desensitize any other character by just printing what
2090         // came after the '\'
2091         parent_entry.AppendChar(desens_char);
2092         break;
2093       }
2094     } break;
2095 
2096     case '$':
2097       if (format.size() == 1) {
2098         // '$' at the end of a format string, just print the '$'
2099         parent_entry.AppendText("$");
2100       } else {
2101         format = format.drop_front(); // Skip the '$'
2102 
2103         if (format[0] == '{') {
2104           format = format.drop_front(); // Skip the '{'
2105 
2106           llvm::StringRef variable, variable_format;
2107           error = FormatEntity::ExtractVariableInfo(format, variable,
2108                                                     variable_format);
2109           if (error.Fail())
2110             return error;
2111           bool verify_is_thread_id = false;
2112           Entry entry;
2113           if (!variable_format.empty()) {
2114             entry.printf_format = variable_format.str();
2115 
2116             // If the format contains a '%' we are going to assume this is
2117             // a printf style format. So if you want to format your thread ID
2118             // using "0x%llx" you can use:
2119             // ${thread.id%0x%llx}
2120             //
2121             // If there is no '%' in the format, then it is assumed to be a
2122             // LLDB format name, or one of the extended formats specified in
2123             // the switch statement below.
2124 
2125             if (entry.printf_format.find('%') == std::string::npos) {
2126               bool clear_printf = false;
2127 
2128               if (FormatManager::GetFormatFromCString(
2129                       entry.printf_format.c_str(), false, entry.fmt)) {
2130                 // We have an LLDB format, so clear the printf format
2131                 clear_printf = true;
2132               } else if (entry.printf_format.size() == 1) {
2133                 switch (entry.printf_format[0]) {
2134                 case '@': // if this is an @ sign, print ObjC description
2135                   entry.number = ValueObject::
2136                       eValueObjectRepresentationStyleLanguageSpecific;
2137                   clear_printf = true;
2138                   break;
2139                 case 'V': // if this is a V, print the value using the default
2140                           // format
2141                   entry.number =
2142                       ValueObject::eValueObjectRepresentationStyleValue;
2143                   clear_printf = true;
2144                   break;
2145                 case 'L': // if this is an L, print the location of the value
2146                   entry.number =
2147                       ValueObject::eValueObjectRepresentationStyleLocation;
2148                   clear_printf = true;
2149                   break;
2150                 case 'S': // if this is an S, print the summary after all
2151                   entry.number =
2152                       ValueObject::eValueObjectRepresentationStyleSummary;
2153                   clear_printf = true;
2154                   break;
2155                 case '#': // if this is a '#', print the number of children
2156                   entry.number =
2157                       ValueObject::eValueObjectRepresentationStyleChildrenCount;
2158                   clear_printf = true;
2159                   break;
2160                 case 'T': // if this is a 'T', print the type
2161                   entry.number =
2162                       ValueObject::eValueObjectRepresentationStyleType;
2163                   clear_printf = true;
2164                   break;
2165                 case 'N': // if this is a 'N', print the name
2166                   entry.number =
2167                       ValueObject::eValueObjectRepresentationStyleName;
2168                   clear_printf = true;
2169                   break;
2170                 case '>': // if this is a '>', print the expression path
2171                   entry.number = ValueObject::
2172                       eValueObjectRepresentationStyleExpressionPath;
2173                   clear_printf = true;
2174                   break;
2175                 default:
2176                   error.SetErrorStringWithFormat("invalid format: '%s'",
2177                                                  entry.printf_format.c_str());
2178                   return error;
2179                 }
2180               } else if (FormatManager::GetFormatFromCString(
2181                              entry.printf_format.c_str(), true, entry.fmt)) {
2182                 clear_printf = true;
2183               } else if (entry.printf_format == "tid") {
2184                 verify_is_thread_id = true;
2185               } else {
2186                 error.SetErrorStringWithFormat("invalid format: '%s'",
2187                                                entry.printf_format.c_str());
2188                 return error;
2189               }
2190 
2191               // Our format string turned out to not be a printf style format
2192               // so lets clear the string
2193               if (clear_printf)
2194                 entry.printf_format.clear();
2195             }
2196           }
2197 
2198           // Check for dereferences
2199           if (variable[0] == '*') {
2200             entry.deref = true;
2201             variable = variable.drop_front();
2202           }
2203 
2204           error = ParseEntry(variable, &g_root, entry);
2205           if (error.Fail())
2206             return error;
2207 
2208           if (verify_is_thread_id) {
2209             if (entry.type != Entry::Type::ThreadID &&
2210                 entry.type != Entry::Type::ThreadProtocolID) {
2211               error.SetErrorString("the 'tid' format can only be used on "
2212                                    "${thread.id} and ${thread.protocol_id}");
2213             }
2214           }
2215 
2216           switch (entry.type) {
2217           case Entry::Type::Variable:
2218           case Entry::Type::VariableSynthetic:
2219             if (entry.number == 0) {
2220               if (entry.string.empty())
2221                 entry.number =
2222                     ValueObject::eValueObjectRepresentationStyleValue;
2223               else
2224                 entry.number =
2225                     ValueObject::eValueObjectRepresentationStyleSummary;
2226             }
2227             break;
2228           default:
2229             // Make sure someone didn't try to dereference anything but ${var}
2230             // or ${svar}
2231             if (entry.deref) {
2232               error.SetErrorStringWithFormat(
2233                   "${%s} can't be dereferenced, only ${var} and ${svar} can.",
2234                   variable.str().c_str());
2235               return error;
2236             }
2237           }
2238           // Check if this entry just wants to insert a constant string
2239           // value into the parent_entry, if so, insert the string with
2240           // AppendText, else append the entry to the parent_entry.
2241           if (entry.type == Entry::Type::InsertString)
2242             parent_entry.AppendText(entry.string.c_str());
2243           else
2244             parent_entry.AppendEntry(std::move(entry));
2245         }
2246       }
2247       break;
2248     }
2249   }
2250   return error;
2251 }
2252 
2253 Error FormatEntity::ExtractVariableInfo(llvm::StringRef &format_str,
2254                                         llvm::StringRef &variable_name,
2255                                         llvm::StringRef &variable_format) {
2256   Error error;
2257   variable_name = llvm::StringRef();
2258   variable_format = llvm::StringRef();
2259 
2260   const size_t paren_pos = format_str.find('}');
2261   if (paren_pos != llvm::StringRef::npos) {
2262     const size_t percent_pos = format_str.find('%');
2263     if (percent_pos < paren_pos) {
2264       if (percent_pos > 0) {
2265         if (percent_pos > 1)
2266           variable_name = format_str.substr(0, percent_pos);
2267         variable_format =
2268             format_str.substr(percent_pos + 1, paren_pos - (percent_pos + 1));
2269       }
2270     } else {
2271       variable_name = format_str.substr(0, paren_pos);
2272     }
2273     // Strip off elements and the formatting and the trailing '}'
2274     format_str = format_str.substr(paren_pos + 1);
2275   } else {
2276     error.SetErrorStringWithFormat(
2277         "missing terminating '}' character for '${%s'",
2278         format_str.str().c_str());
2279   }
2280   return error;
2281 }
2282 
2283 bool FormatEntity::FormatFileSpec(const FileSpec &file_spec, Stream &s,
2284                                   llvm::StringRef variable_name,
2285                                   llvm::StringRef variable_format) {
2286   if (variable_name.empty() || variable_name.equals(".fullpath")) {
2287     file_spec.Dump(&s);
2288     return true;
2289   } else if (variable_name.equals(".basename")) {
2290     s.PutCString(file_spec.GetFilename().AsCString(""));
2291     return true;
2292   } else if (variable_name.equals(".dirname")) {
2293     s.PutCString(file_spec.GetFilename().AsCString(""));
2294     return true;
2295   }
2296   return false;
2297 }
2298 
2299 static std::string MakeMatch(const llvm::StringRef &prefix,
2300                              const char *suffix) {
2301   std::string match(prefix.str());
2302   match.append(suffix);
2303   return match;
2304 }
2305 
2306 static void AddMatches(const FormatEntity::Entry::Definition *def,
2307                        const llvm::StringRef &prefix,
2308                        const llvm::StringRef &match_prefix,
2309                        StringList &matches) {
2310   const size_t n = def->num_children;
2311   if (n > 0) {
2312     for (size_t i = 0; i < n; ++i) {
2313       std::string match = prefix.str();
2314       if (match_prefix.empty())
2315         matches.AppendString(MakeMatch(prefix, def->children[i].name));
2316       else if (strncmp(def->children[i].name, match_prefix.data(),
2317                        match_prefix.size()) == 0)
2318         matches.AppendString(
2319             MakeMatch(prefix, def->children[i].name + match_prefix.size()));
2320     }
2321   }
2322 }
2323 
2324 size_t FormatEntity::AutoComplete(llvm::StringRef str, int match_start_point,
2325                                   int max_return_elements, bool &word_complete,
2326                                   StringList &matches) {
2327   word_complete = false;
2328   str = str.drop_front(match_start_point);
2329   matches.Clear();
2330 
2331   const size_t dollar_pos = str.rfind('$');
2332   if (dollar_pos == llvm::StringRef::npos)
2333     return 0;
2334 
2335   // Hitting TAB after $ at the end of the string add a "{"
2336   if (dollar_pos == str.size() - 1) {
2337     std::string match = str.str();
2338     match.append("{");
2339     matches.AppendString(match);
2340     return 1;
2341   }
2342 
2343   if (str[dollar_pos + 1] != '{')
2344     return 0;
2345 
2346   const size_t close_pos = str.find('}', dollar_pos + 2);
2347   if (close_pos != llvm::StringRef::npos)
2348     return 0;
2349 
2350   const size_t format_pos = str.find('%', dollar_pos + 2);
2351   if (format_pos != llvm::StringRef::npos)
2352     return 0;
2353 
2354   llvm::StringRef partial_variable(str.substr(dollar_pos + 2));
2355   if (partial_variable.empty()) {
2356     // Suggest all top level entites as we are just past "${"
2357     AddMatches(&g_root, str, llvm::StringRef(), matches);
2358     return matches.GetSize();
2359   }
2360 
2361   // We have a partially specified variable, find it
2362   llvm::StringRef remainder;
2363   const FormatEntity::Entry::Definition *entry_def =
2364       FindEntry(partial_variable, &g_root, remainder);
2365   if (!entry_def)
2366     return 0;
2367 
2368   const size_t n = entry_def->num_children;
2369 
2370   if (remainder.empty()) {
2371     // Exact match
2372     if (n > 0) {
2373       // "${thread.info" <TAB>
2374       matches.AppendString(MakeMatch(str, "."));
2375     } else {
2376       // "${thread.id" <TAB>
2377       matches.AppendString(MakeMatch(str, "}"));
2378       word_complete = true;
2379     }
2380   } else if (remainder.equals(".")) {
2381     // "${thread." <TAB>
2382     AddMatches(entry_def, str, llvm::StringRef(), matches);
2383   } else {
2384     // We have a partial match
2385     // "${thre" <TAB>
2386     AddMatches(entry_def, str, remainder, matches);
2387   }
2388   return matches.GetSize();
2389 }
2390