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/ValueObject.h"
23 #include "lldb/Core/ValueObjectVariable.h"
24 #include "lldb/DataFormatters/DataVisualization.h"
25 #include "lldb/DataFormatters/FormatManager.h"
26 #include "lldb/DataFormatters/ValueObjectPrinter.h"
27 #include "lldb/Expression/ExpressionVariable.h"
28 #include "lldb/Interpreter/CommandInterpreter.h"
29 #include "lldb/Symbol/Block.h"
30 #include "lldb/Symbol/CompileUnit.h"
31 #include "lldb/Symbol/Function.h"
32 #include "lldb/Symbol/LineEntry.h"
33 #include "lldb/Symbol/Symbol.h"
34 #include "lldb/Symbol/VariableList.h"
35 #include "lldb/Target/ExecutionContext.h"
36 #include "lldb/Target/Language.h"
37 #include "lldb/Target/Process.h"
38 #include "lldb/Target/RegisterContext.h"
39 #include "lldb/Target/SectionLoadList.h"
40 #include "lldb/Target/StackFrame.h"
41 #include "lldb/Target/StopInfo.h"
42 #include "lldb/Target/Target.h"
43 #include "lldb/Target/Thread.h"
44 #include "lldb/Utility/AnsiTerminal.h"
45 #include "lldb/Utility/FileSpec.h"
46 #include "lldb/Utility/Stream.h"
47 #include "lldb/Utility/StreamString.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,                                 \
68         static_cast<uint32_t>(llvm::array_lengthof(c)), c, 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,                                 \
74         static_cast<uint32_t>(llvm::array_lengthof(c)), c, 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                 (ostype == llvm::Triple::NetBSD)) {
1192               format = "%" PRIu64;
1193             }
1194           } else {
1195             format = entry.printf_format.c_str();
1196           }
1197         }
1198         s.Printf(format, thread->GetID());
1199         return true;
1200       }
1201     }
1202     return false;
1203 
1204   case Entry::Type::ThreadProtocolID:
1205     if (exe_ctx) {
1206       Thread *thread = exe_ctx->GetThreadPtr();
1207       if (thread) {
1208         const char *format = "0x%4.4" PRIx64;
1209         if (!entry.printf_format.empty())
1210           format = entry.printf_format.c_str();
1211         s.Printf(format, thread->GetProtocolID());
1212         return true;
1213       }
1214     }
1215     return false;
1216 
1217   case Entry::Type::ThreadIndexID:
1218     if (exe_ctx) {
1219       Thread *thread = exe_ctx->GetThreadPtr();
1220       if (thread) {
1221         const char *format = "%" PRIu32;
1222         if (!entry.printf_format.empty())
1223           format = entry.printf_format.c_str();
1224         s.Printf(format, thread->GetIndexID());
1225         return true;
1226       }
1227     }
1228     return false;
1229 
1230   case Entry::Type::ThreadName:
1231     if (exe_ctx) {
1232       Thread *thread = exe_ctx->GetThreadPtr();
1233       if (thread) {
1234         const char *cstr = thread->GetName();
1235         if (cstr && cstr[0]) {
1236           s.PutCString(cstr);
1237           return true;
1238         }
1239       }
1240     }
1241     return false;
1242 
1243   case Entry::Type::ThreadQueue:
1244     if (exe_ctx) {
1245       Thread *thread = exe_ctx->GetThreadPtr();
1246       if (thread) {
1247         const char *cstr = thread->GetQueueName();
1248         if (cstr && cstr[0]) {
1249           s.PutCString(cstr);
1250           return true;
1251         }
1252       }
1253     }
1254     return false;
1255 
1256   case Entry::Type::ThreadStopReason:
1257     if (exe_ctx) {
1258       Thread *thread = exe_ctx->GetThreadPtr();
1259       if (thread) {
1260         StopInfoSP stop_info_sp = thread->GetStopInfo();
1261         if (stop_info_sp && stop_info_sp->IsValid()) {
1262           const char *cstr = stop_info_sp->GetDescription();
1263           if (cstr && cstr[0]) {
1264             s.PutCString(cstr);
1265             return true;
1266           }
1267         }
1268       }
1269     }
1270     return false;
1271 
1272   case Entry::Type::ThreadReturnValue:
1273     if (exe_ctx) {
1274       Thread *thread = exe_ctx->GetThreadPtr();
1275       if (thread) {
1276         StopInfoSP stop_info_sp = thread->GetStopInfo();
1277         if (stop_info_sp && stop_info_sp->IsValid()) {
1278           ValueObjectSP return_valobj_sp =
1279               StopInfo::GetReturnValueObject(stop_info_sp);
1280           if (return_valobj_sp) {
1281             return_valobj_sp->Dump(s);
1282             return true;
1283           }
1284         }
1285       }
1286     }
1287     return false;
1288 
1289   case Entry::Type::ThreadCompletedExpression:
1290     if (exe_ctx) {
1291       Thread *thread = exe_ctx->GetThreadPtr();
1292       if (thread) {
1293         StopInfoSP stop_info_sp = thread->GetStopInfo();
1294         if (stop_info_sp && stop_info_sp->IsValid()) {
1295           ExpressionVariableSP expression_var_sp =
1296               StopInfo::GetExpressionVariable(stop_info_sp);
1297           if (expression_var_sp && expression_var_sp->GetValueObject()) {
1298             expression_var_sp->GetValueObject()->Dump(s);
1299             return true;
1300           }
1301         }
1302       }
1303     }
1304     return false;
1305 
1306   case Entry::Type::ScriptThread:
1307     if (exe_ctx) {
1308       Thread *thread = exe_ctx->GetThreadPtr();
1309       if (thread)
1310         return RunScriptFormatKeyword(s, sc, exe_ctx, thread,
1311                                       entry.string.c_str());
1312     }
1313     return false;
1314 
1315   case Entry::Type::ThreadInfo:
1316     if (exe_ctx) {
1317       Thread *thread = exe_ctx->GetThreadPtr();
1318       if (thread) {
1319         StructuredData::ObjectSP object_sp = thread->GetExtendedInfo();
1320         if (object_sp &&
1321             object_sp->GetType() == StructuredData::Type::eTypeDictionary) {
1322           if (FormatThreadExtendedInfoRecurse(entry, object_sp, sc, exe_ctx, s))
1323             return true;
1324         }
1325       }
1326     }
1327     return false;
1328 
1329   case Entry::Type::TargetArch:
1330     if (exe_ctx) {
1331       Target *target = exe_ctx->GetTargetPtr();
1332       if (target) {
1333         const ArchSpec &arch = target->GetArchitecture();
1334         if (arch.IsValid()) {
1335           s.PutCString(arch.GetArchitectureName());
1336           return true;
1337         }
1338       }
1339     }
1340     return false;
1341 
1342   case Entry::Type::ScriptTarget:
1343     if (exe_ctx) {
1344       Target *target = exe_ctx->GetTargetPtr();
1345       if (target)
1346         return RunScriptFormatKeyword(s, sc, exe_ctx, target,
1347                                       entry.string.c_str());
1348     }
1349     return false;
1350 
1351   case Entry::Type::ModuleFile:
1352     if (sc) {
1353       Module *module = sc->module_sp.get();
1354       if (module) {
1355         if (DumpFile(s, module->GetFileSpec(), (FileKind)entry.number))
1356           return true;
1357       }
1358     }
1359     return false;
1360 
1361   case Entry::Type::File:
1362     if (sc) {
1363       CompileUnit *cu = sc->comp_unit;
1364       if (cu) {
1365         // CompileUnit is a FileSpec
1366         if (DumpFile(s, *cu, (FileKind)entry.number))
1367           return true;
1368       }
1369     }
1370     return false;
1371 
1372   case Entry::Type::Lang:
1373     if (sc) {
1374       CompileUnit *cu = sc->comp_unit;
1375       if (cu) {
1376         const char *lang_name =
1377             Language::GetNameForLanguageType(cu->GetLanguage());
1378         if (lang_name) {
1379           s.PutCString(lang_name);
1380           return true;
1381         }
1382       }
1383     }
1384     return false;
1385 
1386   case Entry::Type::FrameIndex:
1387     if (exe_ctx) {
1388       StackFrame *frame = exe_ctx->GetFramePtr();
1389       if (frame) {
1390         const char *format = "%" PRIu32;
1391         if (!entry.printf_format.empty())
1392           format = entry.printf_format.c_str();
1393         s.Printf(format, frame->GetFrameIndex());
1394         return true;
1395       }
1396     }
1397     return false;
1398 
1399   case Entry::Type::FrameRegisterPC:
1400     if (exe_ctx) {
1401       StackFrame *frame = exe_ctx->GetFramePtr();
1402       if (frame) {
1403         const Address &pc_addr = frame->GetFrameCodeAddress();
1404         if (pc_addr.IsValid()) {
1405           if (DumpAddress(s, sc, exe_ctx, pc_addr, false))
1406             return true;
1407         }
1408       }
1409     }
1410     return false;
1411 
1412   case Entry::Type::FrameRegisterSP:
1413     if (exe_ctx) {
1414       StackFrame *frame = exe_ctx->GetFramePtr();
1415       if (frame) {
1416         if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP,
1417                          (lldb::Format)entry.number))
1418           return true;
1419       }
1420     }
1421     return false;
1422 
1423   case Entry::Type::FrameRegisterFP:
1424     if (exe_ctx) {
1425       StackFrame *frame = exe_ctx->GetFramePtr();
1426       if (frame) {
1427         if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP,
1428                          (lldb::Format)entry.number))
1429           return true;
1430       }
1431     }
1432     return false;
1433 
1434   case Entry::Type::FrameRegisterFlags:
1435     if (exe_ctx) {
1436       StackFrame *frame = exe_ctx->GetFramePtr();
1437       if (frame) {
1438         if (DumpRegister(s, frame, eRegisterKindGeneric,
1439                          LLDB_REGNUM_GENERIC_FLAGS, (lldb::Format)entry.number))
1440           return true;
1441       }
1442     }
1443     return false;
1444 
1445   case Entry::Type::FrameNoDebug:
1446     if (exe_ctx) {
1447       StackFrame *frame = exe_ctx->GetFramePtr();
1448       if (frame) {
1449         return !frame->HasDebugInformation();
1450       }
1451     }
1452     return true;
1453 
1454   case Entry::Type::FrameRegisterByName:
1455     if (exe_ctx) {
1456       StackFrame *frame = exe_ctx->GetFramePtr();
1457       if (frame) {
1458         if (DumpRegister(s, frame, entry.string.c_str(),
1459                          (lldb::Format)entry.number))
1460           return true;
1461       }
1462     }
1463     return false;
1464 
1465   case Entry::Type::ScriptFrame:
1466     if (exe_ctx) {
1467       StackFrame *frame = exe_ctx->GetFramePtr();
1468       if (frame)
1469         return RunScriptFormatKeyword(s, sc, exe_ctx, frame,
1470                                       entry.string.c_str());
1471     }
1472     return false;
1473 
1474   case Entry::Type::FunctionID:
1475     if (sc) {
1476       if (sc->function) {
1477         s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID());
1478         return true;
1479       } else if (sc->symbol) {
1480         s.Printf("symbol[%u]", sc->symbol->GetID());
1481         return true;
1482       }
1483     }
1484     return false;
1485 
1486   case Entry::Type::FunctionDidChange:
1487     return function_changed;
1488 
1489   case Entry::Type::FunctionInitialFunction:
1490     return initial_function;
1491 
1492   case Entry::Type::FunctionName: {
1493     Language *language_plugin = nullptr;
1494     bool language_plugin_handled = false;
1495     StreamString ss;
1496     if (sc->function)
1497       language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1498     else if (sc->symbol)
1499       language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1500     if (language_plugin) {
1501       language_plugin_handled = language_plugin->GetFunctionDisplayName(
1502           sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
1503     }
1504     if (language_plugin_handled) {
1505       s << ss.GetString();
1506       return true;
1507     } else {
1508       const char *name = nullptr;
1509       if (sc->function)
1510         name = sc->function->GetName().AsCString(nullptr);
1511       else if (sc->symbol)
1512         name = sc->symbol->GetName().AsCString(nullptr);
1513       if (name) {
1514         s.PutCString(name);
1515 
1516         if (sc->block) {
1517           Block *inline_block = sc->block->GetContainingInlinedBlock();
1518           if (inline_block) {
1519             const InlineFunctionInfo *inline_info =
1520                 sc->block->GetInlinedFunctionInfo();
1521             if (inline_info) {
1522               s.PutCString(" [inlined] ");
1523               inline_info->GetName(sc->function->GetLanguage()).Dump(&s);
1524             }
1525           }
1526         }
1527         return true;
1528       }
1529     }
1530   }
1531     return false;
1532 
1533   case Entry::Type::FunctionNameNoArgs: {
1534     Language *language_plugin = nullptr;
1535     bool language_plugin_handled = false;
1536     StreamString ss;
1537     if (sc->function)
1538       language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1539     else if (sc->symbol)
1540       language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1541     if (language_plugin) {
1542       language_plugin_handled = language_plugin->GetFunctionDisplayName(
1543           sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
1544           ss);
1545     }
1546     if (language_plugin_handled) {
1547       s << ss.GetString();
1548       return true;
1549     } else {
1550       ConstString name;
1551       if (sc->function)
1552         name = sc->function->GetNameNoArguments();
1553       else if (sc->symbol)
1554         name = sc->symbol->GetNameNoArguments();
1555       if (name) {
1556         s.PutCString(name.GetCString());
1557         return true;
1558       }
1559     }
1560   }
1561     return false;
1562 
1563   case Entry::Type::FunctionNameWithArgs: {
1564     Language *language_plugin = nullptr;
1565     bool language_plugin_handled = false;
1566     StreamString ss;
1567     if (sc->function)
1568       language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1569     else if (sc->symbol)
1570       language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1571     if (language_plugin) {
1572       language_plugin_handled = language_plugin->GetFunctionDisplayName(
1573           sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss);
1574     }
1575     if (language_plugin_handled) {
1576       s << ss.GetString();
1577       return true;
1578     } else {
1579       // Print the function name with arguments in it
1580       if (sc->function) {
1581         ExecutionContextScope *exe_scope =
1582             exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
1583         const char *cstr = sc->function->GetName().AsCString(nullptr);
1584         if (cstr) {
1585           const InlineFunctionInfo *inline_info = nullptr;
1586           VariableListSP variable_list_sp;
1587           bool get_function_vars = true;
1588           if (sc->block) {
1589             Block *inline_block = sc->block->GetContainingInlinedBlock();
1590 
1591             if (inline_block) {
1592               get_function_vars = false;
1593               inline_info = sc->block->GetInlinedFunctionInfo();
1594               if (inline_info)
1595                 variable_list_sp = inline_block->GetBlockVariableList(true);
1596             }
1597           }
1598 
1599           if (get_function_vars) {
1600             variable_list_sp =
1601                 sc->function->GetBlock(true).GetBlockVariableList(true);
1602           }
1603 
1604           if (inline_info) {
1605             s.PutCString(cstr);
1606             s.PutCString(" [inlined] ");
1607             cstr =
1608                 inline_info->GetName(sc->function->GetLanguage()).GetCString();
1609           }
1610 
1611           VariableList args;
1612           if (variable_list_sp)
1613             variable_list_sp->AppendVariablesWithScope(
1614                 eValueTypeVariableArgument, args);
1615           if (args.GetSize() > 0) {
1616             const char *open_paren = strchr(cstr, '(');
1617             const char *close_paren = nullptr;
1618             const char *generic = strchr(cstr, '<');
1619             // if before the arguments list begins there is a template sign
1620             // then scan to the end of the generic args before you try to find
1621             // the arguments list
1622             if (generic && open_paren && generic < open_paren) {
1623               int generic_depth = 1;
1624               ++generic;
1625               for (; *generic && generic_depth > 0; generic++) {
1626                 if (*generic == '<')
1627                   generic_depth++;
1628                 if (*generic == '>')
1629                   generic_depth--;
1630               }
1631               if (*generic)
1632                 open_paren = strchr(generic, '(');
1633               else
1634                 open_paren = nullptr;
1635             }
1636             if (open_paren) {
1637               if (IsToken(open_paren, "(anonymous namespace)")) {
1638                 open_paren =
1639                     strchr(open_paren + strlen("(anonymous namespace)"), '(');
1640                 if (open_paren)
1641                   close_paren = strchr(open_paren, ')');
1642               } else
1643                 close_paren = strchr(open_paren, ')');
1644             }
1645 
1646             if (open_paren)
1647               s.Write(cstr, open_paren - cstr + 1);
1648             else {
1649               s.PutCString(cstr);
1650               s.PutChar('(');
1651             }
1652             const size_t num_args = args.GetSize();
1653             for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) {
1654               std::string buffer;
1655 
1656               VariableSP var_sp(args.GetVariableAtIndex(arg_idx));
1657               ValueObjectSP var_value_sp(
1658                   ValueObjectVariable::Create(exe_scope, var_sp));
1659               StreamString ss;
1660               llvm::StringRef var_representation;
1661               const char *var_name = var_value_sp->GetName().GetCString();
1662               if (var_value_sp->GetCompilerType().IsValid()) {
1663                 if (var_value_sp && exe_scope->CalculateTarget())
1664                   var_value_sp =
1665                       var_value_sp->GetQualifiedRepresentationIfAvailable(
1666                           exe_scope->CalculateTarget()
1667                               ->TargetProperties::GetPreferDynamicValue(),
1668                           exe_scope->CalculateTarget()
1669                               ->TargetProperties::GetEnableSyntheticValue());
1670                 if (var_value_sp->GetCompilerType().IsAggregateType() &&
1671                     DataVisualization::ShouldPrintAsOneLiner(*var_value_sp)) {
1672                   static StringSummaryFormat format(
1673                       TypeSummaryImpl::Flags()
1674                           .SetHideItemNames(false)
1675                           .SetShowMembersOneLiner(true),
1676                       "");
1677                   format.FormatObject(var_value_sp.get(), buffer,
1678                                       TypeSummaryOptions());
1679                   var_representation = buffer;
1680                 } else
1681                   var_value_sp->DumpPrintableRepresentation(
1682                       ss, ValueObject::ValueObjectRepresentationStyle::
1683                               eValueObjectRepresentationStyleSummary,
1684                       eFormatDefault,
1685                       ValueObject::PrintableRepresentationSpecialCases::eAllow,
1686                       false);
1687               }
1688 
1689               if (!ss.GetString().empty())
1690                 var_representation = ss.GetString();
1691               if (arg_idx > 0)
1692                 s.PutCString(", ");
1693               if (var_value_sp->GetError().Success()) {
1694                 if (!var_representation.empty())
1695                   s.Printf("%s=%s", var_name, var_representation.str().c_str());
1696                 else
1697                   s.Printf("%s=%s at %s", var_name,
1698                            var_value_sp->GetTypeName().GetCString(),
1699                            var_value_sp->GetLocationAsCString());
1700               } else
1701                 s.Printf("%s=<unavailable>", var_name);
1702             }
1703 
1704             if (close_paren)
1705               s.PutCString(close_paren);
1706             else
1707               s.PutChar(')');
1708 
1709           } else {
1710             s.PutCString(cstr);
1711           }
1712           return true;
1713         }
1714       } else if (sc->symbol) {
1715         const char *cstr = sc->symbol->GetName().AsCString(nullptr);
1716         if (cstr) {
1717           s.PutCString(cstr);
1718           return true;
1719         }
1720       }
1721     }
1722   }
1723     return false;
1724 
1725   case Entry::Type::FunctionAddrOffset:
1726     if (addr) {
1727       if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, false, false,
1728                                         false))
1729         return true;
1730     }
1731     return false;
1732 
1733   case Entry::Type::FunctionAddrOffsetConcrete:
1734     if (addr) {
1735       if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, true, true,
1736                                         true))
1737         return true;
1738     }
1739     return false;
1740 
1741   case Entry::Type::FunctionLineOffset:
1742     return (DumpAddressOffsetFromFunction(s, sc, exe_ctx,
1743                                           sc->line_entry.range.GetBaseAddress(),
1744                                           false, false, false));
1745 
1746   case Entry::Type::FunctionPCOffset:
1747     if (exe_ctx) {
1748       StackFrame *frame = exe_ctx->GetFramePtr();
1749       if (frame) {
1750         if (DumpAddressOffsetFromFunction(s, sc, exe_ctx,
1751                                           frame->GetFrameCodeAddress(), false,
1752                                           false, false))
1753           return true;
1754       }
1755     }
1756     return false;
1757 
1758   case Entry::Type::FunctionChanged:
1759     return function_changed;
1760 
1761   case Entry::Type::FunctionIsOptimized: {
1762     bool is_optimized = false;
1763     if (sc->function && sc->function->GetIsOptimized()) {
1764       is_optimized = true;
1765     }
1766     return is_optimized;
1767   }
1768 
1769   case Entry::Type::FunctionInitial:
1770     return initial_function;
1771 
1772   case Entry::Type::LineEntryFile:
1773     if (sc && sc->line_entry.IsValid()) {
1774       Module *module = sc->module_sp.get();
1775       if (module) {
1776         if (DumpFile(s, sc->line_entry.file, (FileKind)entry.number))
1777           return true;
1778       }
1779     }
1780     return false;
1781 
1782   case Entry::Type::LineEntryLineNumber:
1783     if (sc && sc->line_entry.IsValid()) {
1784       const char *format = "%" PRIu32;
1785       if (!entry.printf_format.empty())
1786         format = entry.printf_format.c_str();
1787       s.Printf(format, sc->line_entry.line);
1788       return true;
1789     }
1790     return false;
1791 
1792   case Entry::Type::LineEntryStartAddress:
1793   case Entry::Type::LineEntryEndAddress:
1794     if (sc && sc->line_entry.range.GetBaseAddress().IsValid()) {
1795       Address addr = sc->line_entry.range.GetBaseAddress();
1796 
1797       if (entry.type == Entry::Type::LineEntryEndAddress)
1798         addr.Slide(sc->line_entry.range.GetByteSize());
1799       if (DumpAddress(s, sc, exe_ctx, addr, false))
1800         return true;
1801     }
1802     return false;
1803 
1804   case Entry::Type::CurrentPCArrow:
1805     if (addr && exe_ctx && exe_ctx->GetFramePtr()) {
1806       RegisterContextSP reg_ctx =
1807           exe_ctx->GetFramePtr()->GetRegisterContextSP();
1808       if (reg_ctx) {
1809         addr_t pc_loadaddr = reg_ctx->GetPC();
1810         if (pc_loadaddr != LLDB_INVALID_ADDRESS) {
1811           Address pc;
1812           pc.SetLoadAddress(pc_loadaddr, exe_ctx->GetTargetPtr());
1813           if (pc == *addr) {
1814             s.Printf("-> ");
1815             return true;
1816           }
1817         }
1818       }
1819       s.Printf("   ");
1820       return true;
1821     }
1822     return false;
1823   }
1824   return false;
1825 }
1826 
1827 static bool DumpCommaSeparatedChildEntryNames(
1828     Stream &s, const FormatEntity::Entry::Definition *parent) {
1829   if (parent->children) {
1830     const size_t n = parent->num_children;
1831     for (size_t i = 0; i < n; ++i) {
1832       if (i > 0)
1833         s.PutCString(", ");
1834       s.Printf("\"%s\"", parent->children[i].name);
1835     }
1836     return true;
1837   }
1838   return false;
1839 }
1840 
1841 static Error ParseEntry(const llvm::StringRef &format_str,
1842                         const FormatEntity::Entry::Definition *parent,
1843                         FormatEntity::Entry &entry) {
1844   Error error;
1845 
1846   const size_t sep_pos = format_str.find_first_of(".[:");
1847   const char sep_char =
1848       (sep_pos == llvm::StringRef::npos) ? '\0' : format_str[sep_pos];
1849   llvm::StringRef key = format_str.substr(0, sep_pos);
1850 
1851   const size_t n = parent->num_children;
1852   for (size_t i = 0; i < n; ++i) {
1853     const FormatEntity::Entry::Definition *entry_def = parent->children + i;
1854     if (key.equals(entry_def->name) || entry_def->name[0] == '*') {
1855       llvm::StringRef value;
1856       if (sep_char)
1857         value =
1858             format_str.substr(sep_pos + (entry_def->keep_separator ? 0 : 1));
1859       switch (entry_def->type) {
1860       case FormatEntity::Entry::Type::ParentString:
1861         entry.string = format_str.str();
1862         return error; // Success
1863 
1864       case FormatEntity::Entry::Type::ParentNumber:
1865         entry.number = entry_def->data;
1866         return error; // Success
1867 
1868       case FormatEntity::Entry::Type::InsertString:
1869         entry.type = entry_def->type;
1870         entry.string = entry_def->string;
1871         return error; // Success
1872 
1873       default:
1874         entry.type = entry_def->type;
1875         break;
1876       }
1877 
1878       if (value.empty()) {
1879         if (entry_def->type == FormatEntity::Entry::Type::Invalid) {
1880           if (entry_def->children) {
1881             StreamString error_strm;
1882             error_strm.Printf("'%s' can't be specified on its own, you must "
1883                               "access one of its children: ",
1884                               entry_def->name);
1885             DumpCommaSeparatedChildEntryNames(error_strm, entry_def);
1886             error.SetErrorStringWithFormat("%s", error_strm.GetData());
1887           } else if (sep_char == ':') {
1888             // Any value whose separator is a with a ':' means this value has a
1889             // string argument
1890             // that needs to be stored in the entry (like "${script.var:}").
1891             // In this case the string value is the empty string which is ok.
1892           } else {
1893             error.SetErrorStringWithFormat("%s", "invalid entry definitions");
1894           }
1895         }
1896       } else {
1897         if (entry_def->children) {
1898           error = ParseEntry(value, entry_def, entry);
1899         } else if (sep_char == ':') {
1900           // Any value whose separator is a with a ':' means this value has a
1901           // string argument
1902           // that needs to be stored in the entry (like
1903           // "${script.var:modulename.function}")
1904           entry.string = value.str();
1905         } else {
1906           error.SetErrorStringWithFormat(
1907               "'%s' followed by '%s' but it has no children", key.str().c_str(),
1908               value.str().c_str());
1909         }
1910       }
1911       return error;
1912     }
1913   }
1914   StreamString error_strm;
1915   if (parent->type == FormatEntity::Entry::Type::Root)
1916     error_strm.Printf(
1917         "invalid top level item '%s'. Valid top level items are: ",
1918         key.str().c_str());
1919   else
1920     error_strm.Printf("invalid member '%s' in '%s'. Valid members are: ",
1921                       key.str().c_str(), parent->name);
1922   DumpCommaSeparatedChildEntryNames(error_strm, parent);
1923   error.SetErrorStringWithFormat("%s", error_strm.GetData());
1924   return error;
1925 }
1926 
1927 static const FormatEntity::Entry::Definition *
1928 FindEntry(const llvm::StringRef &format_str,
1929           const FormatEntity::Entry::Definition *parent,
1930           llvm::StringRef &remainder) {
1931   Error error;
1932 
1933   std::pair<llvm::StringRef, llvm::StringRef> p = format_str.split('.');
1934   const size_t n = parent->num_children;
1935   for (size_t i = 0; i < n; ++i) {
1936     const FormatEntity::Entry::Definition *entry_def = parent->children + i;
1937     if (p.first.equals(entry_def->name) || entry_def->name[0] == '*') {
1938       if (p.second.empty()) {
1939         if (format_str.back() == '.')
1940           remainder = format_str.drop_front(format_str.size() - 1);
1941         else
1942           remainder = llvm::StringRef(); // Exact match
1943         return entry_def;
1944       } else {
1945         if (entry_def->children) {
1946           return FindEntry(p.second, entry_def, remainder);
1947         } else {
1948           remainder = p.second;
1949           return entry_def;
1950         }
1951       }
1952     }
1953   }
1954   remainder = format_str;
1955   return parent;
1956 }
1957 
1958 Error FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry,
1959                                   uint32_t depth) {
1960   Error error;
1961   while (!format.empty() && error.Success()) {
1962     const size_t non_special_chars = format.find_first_of("${}\\");
1963 
1964     if (non_special_chars == llvm::StringRef::npos) {
1965       // No special characters, just string bytes so add them and we are done
1966       parent_entry.AppendText(format);
1967       return error;
1968     }
1969 
1970     if (non_special_chars > 0) {
1971       // We have a special character, so add all characters before these as a
1972       // plain string
1973       parent_entry.AppendText(format.substr(0, non_special_chars));
1974       format = format.drop_front(non_special_chars);
1975     }
1976 
1977     switch (format[0]) {
1978     case '\0':
1979       return error;
1980 
1981     case '{': {
1982       format = format.drop_front(); // Skip the '{'
1983       Entry scope_entry(Entry::Type::Scope);
1984       error = FormatEntity::ParseInternal(format, scope_entry, depth + 1);
1985       if (error.Fail())
1986         return error;
1987       parent_entry.AppendEntry(std::move(scope_entry));
1988     } break;
1989 
1990     case '}':
1991       if (depth == 0)
1992         error.SetErrorString("unmatched '}' character");
1993       else
1994         format =
1995             format
1996                 .drop_front(); // Skip the '}' as we are at the end of the scope
1997       return error;
1998 
1999     case '\\': {
2000       format = format.drop_front(); // Skip the '\' character
2001       if (format.empty()) {
2002         error.SetErrorString(
2003             "'\\' character was not followed by another character");
2004         return error;
2005       }
2006 
2007       const char desens_char = format[0];
2008       format = format.drop_front(); // Skip the desensitized char character
2009       switch (desens_char) {
2010       case 'a':
2011         parent_entry.AppendChar('\a');
2012         break;
2013       case 'b':
2014         parent_entry.AppendChar('\b');
2015         break;
2016       case 'f':
2017         parent_entry.AppendChar('\f');
2018         break;
2019       case 'n':
2020         parent_entry.AppendChar('\n');
2021         break;
2022       case 'r':
2023         parent_entry.AppendChar('\r');
2024         break;
2025       case 't':
2026         parent_entry.AppendChar('\t');
2027         break;
2028       case 'v':
2029         parent_entry.AppendChar('\v');
2030         break;
2031       case '\'':
2032         parent_entry.AppendChar('\'');
2033         break;
2034       case '\\':
2035         parent_entry.AppendChar('\\');
2036         break;
2037       case '0':
2038         // 1 to 3 octal chars
2039         {
2040           // Make a string that can hold onto the initial zero char,
2041           // up to 3 octal digits, and a terminating NULL.
2042           char oct_str[5] = {0, 0, 0, 0, 0};
2043 
2044           int i;
2045           for (i = 0; (format[i] >= '0' && format[i] <= '7') && i < 4; ++i)
2046             oct_str[i] = format[i];
2047 
2048           // We don't want to consume the last octal character since
2049           // the main for loop will do this for us, so we advance p by
2050           // one less than i (even if i is zero)
2051           format = format.drop_front(i);
2052           unsigned long octal_value = ::strtoul(oct_str, nullptr, 8);
2053           if (octal_value <= UINT8_MAX) {
2054             parent_entry.AppendChar((char)octal_value);
2055           } else {
2056             error.SetErrorString("octal number is larger than a single byte");
2057             return error;
2058           }
2059         }
2060         break;
2061 
2062       case 'x':
2063         // hex number in the format
2064         if (isxdigit(format[0])) {
2065           // Make a string that can hold onto two hex chars plus a
2066           // NULL terminator
2067           char hex_str[3] = {0, 0, 0};
2068           hex_str[0] = format[0];
2069 
2070           format = format.drop_front();
2071 
2072           if (isxdigit(format[0])) {
2073             hex_str[1] = format[0];
2074             format = format.drop_front();
2075           }
2076 
2077           unsigned long hex_value = strtoul(hex_str, nullptr, 16);
2078           if (hex_value <= UINT8_MAX) {
2079             parent_entry.AppendChar((char)hex_value);
2080           } else {
2081             error.SetErrorString("hex number is larger than a single byte");
2082             return error;
2083           }
2084         } else {
2085           parent_entry.AppendChar(desens_char);
2086         }
2087         break;
2088 
2089       default:
2090         // Just desensitize any other character by just printing what
2091         // came after the '\'
2092         parent_entry.AppendChar(desens_char);
2093         break;
2094       }
2095     } break;
2096 
2097     case '$':
2098       if (format.size() == 1) {
2099         // '$' at the end of a format string, just print the '$'
2100         parent_entry.AppendText("$");
2101       } else {
2102         format = format.drop_front(); // Skip the '$'
2103 
2104         if (format[0] == '{') {
2105           format = format.drop_front(); // Skip the '{'
2106 
2107           llvm::StringRef variable, variable_format;
2108           error = FormatEntity::ExtractVariableInfo(format, variable,
2109                                                     variable_format);
2110           if (error.Fail())
2111             return error;
2112           bool verify_is_thread_id = false;
2113           Entry entry;
2114           if (!variable_format.empty()) {
2115             entry.printf_format = variable_format.str();
2116 
2117             // If the format contains a '%' we are going to assume this is
2118             // a printf style format. So if you want to format your thread ID
2119             // using "0x%llx" you can use:
2120             // ${thread.id%0x%llx}
2121             //
2122             // If there is no '%' in the format, then it is assumed to be a
2123             // LLDB format name, or one of the extended formats specified in
2124             // the switch statement below.
2125 
2126             if (entry.printf_format.find('%') == std::string::npos) {
2127               bool clear_printf = false;
2128 
2129               if (FormatManager::GetFormatFromCString(
2130                       entry.printf_format.c_str(), false, entry.fmt)) {
2131                 // We have an LLDB format, so clear the printf format
2132                 clear_printf = true;
2133               } else if (entry.printf_format.size() == 1) {
2134                 switch (entry.printf_format[0]) {
2135                 case '@': // if this is an @ sign, print ObjC description
2136                   entry.number = ValueObject::
2137                       eValueObjectRepresentationStyleLanguageSpecific;
2138                   clear_printf = true;
2139                   break;
2140                 case 'V': // if this is a V, print the value using the default
2141                           // format
2142                   entry.number =
2143                       ValueObject::eValueObjectRepresentationStyleValue;
2144                   clear_printf = true;
2145                   break;
2146                 case 'L': // if this is an L, print the location of the value
2147                   entry.number =
2148                       ValueObject::eValueObjectRepresentationStyleLocation;
2149                   clear_printf = true;
2150                   break;
2151                 case 'S': // if this is an S, print the summary after all
2152                   entry.number =
2153                       ValueObject::eValueObjectRepresentationStyleSummary;
2154                   clear_printf = true;
2155                   break;
2156                 case '#': // if this is a '#', print the number of children
2157                   entry.number =
2158                       ValueObject::eValueObjectRepresentationStyleChildrenCount;
2159                   clear_printf = true;
2160                   break;
2161                 case 'T': // if this is a 'T', print the type
2162                   entry.number =
2163                       ValueObject::eValueObjectRepresentationStyleType;
2164                   clear_printf = true;
2165                   break;
2166                 case 'N': // if this is a 'N', print the name
2167                   entry.number =
2168                       ValueObject::eValueObjectRepresentationStyleName;
2169                   clear_printf = true;
2170                   break;
2171                 case '>': // if this is a '>', print the expression path
2172                   entry.number = ValueObject::
2173                       eValueObjectRepresentationStyleExpressionPath;
2174                   clear_printf = true;
2175                   break;
2176                 default:
2177                   error.SetErrorStringWithFormat("invalid format: '%s'",
2178                                                  entry.printf_format.c_str());
2179                   return error;
2180                 }
2181               } else if (FormatManager::GetFormatFromCString(
2182                              entry.printf_format.c_str(), true, entry.fmt)) {
2183                 clear_printf = true;
2184               } else if (entry.printf_format == "tid") {
2185                 verify_is_thread_id = true;
2186               } else {
2187                 error.SetErrorStringWithFormat("invalid format: '%s'",
2188                                                entry.printf_format.c_str());
2189                 return error;
2190               }
2191 
2192               // Our format string turned out to not be a printf style format
2193               // so lets clear the string
2194               if (clear_printf)
2195                 entry.printf_format.clear();
2196             }
2197           }
2198 
2199           // Check for dereferences
2200           if (variable[0] == '*') {
2201             entry.deref = true;
2202             variable = variable.drop_front();
2203           }
2204 
2205           error = ParseEntry(variable, &g_root, entry);
2206           if (error.Fail())
2207             return error;
2208 
2209           if (verify_is_thread_id) {
2210             if (entry.type != Entry::Type::ThreadID &&
2211                 entry.type != Entry::Type::ThreadProtocolID) {
2212               error.SetErrorString("the 'tid' format can only be used on "
2213                                    "${thread.id} and ${thread.protocol_id}");
2214             }
2215           }
2216 
2217           switch (entry.type) {
2218           case Entry::Type::Variable:
2219           case Entry::Type::VariableSynthetic:
2220             if (entry.number == 0) {
2221               if (entry.string.empty())
2222                 entry.number =
2223                     ValueObject::eValueObjectRepresentationStyleValue;
2224               else
2225                 entry.number =
2226                     ValueObject::eValueObjectRepresentationStyleSummary;
2227             }
2228             break;
2229           default:
2230             // Make sure someone didn't try to dereference anything but ${var}
2231             // or ${svar}
2232             if (entry.deref) {
2233               error.SetErrorStringWithFormat(
2234                   "${%s} can't be dereferenced, only ${var} and ${svar} can.",
2235                   variable.str().c_str());
2236               return error;
2237             }
2238           }
2239           // Check if this entry just wants to insert a constant string
2240           // value into the parent_entry, if so, insert the string with
2241           // AppendText, else append the entry to the parent_entry.
2242           if (entry.type == Entry::Type::InsertString)
2243             parent_entry.AppendText(entry.string.c_str());
2244           else
2245             parent_entry.AppendEntry(std::move(entry));
2246         }
2247       }
2248       break;
2249     }
2250   }
2251   return error;
2252 }
2253 
2254 Error FormatEntity::ExtractVariableInfo(llvm::StringRef &format_str,
2255                                         llvm::StringRef &variable_name,
2256                                         llvm::StringRef &variable_format) {
2257   Error error;
2258   variable_name = llvm::StringRef();
2259   variable_format = llvm::StringRef();
2260 
2261   const size_t paren_pos = format_str.find('}');
2262   if (paren_pos != llvm::StringRef::npos) {
2263     const size_t percent_pos = format_str.find('%');
2264     if (percent_pos < paren_pos) {
2265       if (percent_pos > 0) {
2266         if (percent_pos > 1)
2267           variable_name = format_str.substr(0, percent_pos);
2268         variable_format =
2269             format_str.substr(percent_pos + 1, paren_pos - (percent_pos + 1));
2270       }
2271     } else {
2272       variable_name = format_str.substr(0, paren_pos);
2273     }
2274     // Strip off elements and the formatting and the trailing '}'
2275     format_str = format_str.substr(paren_pos + 1);
2276   } else {
2277     error.SetErrorStringWithFormat(
2278         "missing terminating '}' character for '${%s'",
2279         format_str.str().c_str());
2280   }
2281   return error;
2282 }
2283 
2284 bool FormatEntity::FormatFileSpec(const FileSpec &file_spec, Stream &s,
2285                                   llvm::StringRef variable_name,
2286                                   llvm::StringRef variable_format) {
2287   if (variable_name.empty() || variable_name.equals(".fullpath")) {
2288     file_spec.Dump(&s);
2289     return true;
2290   } else if (variable_name.equals(".basename")) {
2291     s.PutCString(file_spec.GetFilename().AsCString(""));
2292     return true;
2293   } else if (variable_name.equals(".dirname")) {
2294     s.PutCString(file_spec.GetFilename().AsCString(""));
2295     return true;
2296   }
2297   return false;
2298 }
2299 
2300 static std::string MakeMatch(const llvm::StringRef &prefix,
2301                              const char *suffix) {
2302   std::string match(prefix.str());
2303   match.append(suffix);
2304   return match;
2305 }
2306 
2307 static void AddMatches(const FormatEntity::Entry::Definition *def,
2308                        const llvm::StringRef &prefix,
2309                        const llvm::StringRef &match_prefix,
2310                        StringList &matches) {
2311   const size_t n = def->num_children;
2312   if (n > 0) {
2313     for (size_t i = 0; i < n; ++i) {
2314       std::string match = prefix.str();
2315       if (match_prefix.empty())
2316         matches.AppendString(MakeMatch(prefix, def->children[i].name));
2317       else if (strncmp(def->children[i].name, match_prefix.data(),
2318                        match_prefix.size()) == 0)
2319         matches.AppendString(
2320             MakeMatch(prefix, def->children[i].name + match_prefix.size()));
2321     }
2322   }
2323 }
2324 
2325 size_t FormatEntity::AutoComplete(llvm::StringRef str, int match_start_point,
2326                                   int max_return_elements, bool &word_complete,
2327                                   StringList &matches) {
2328   word_complete = false;
2329   str = str.drop_front(match_start_point);
2330   matches.Clear();
2331 
2332   const size_t dollar_pos = str.rfind('$');
2333   if (dollar_pos == llvm::StringRef::npos)
2334     return 0;
2335 
2336   // Hitting TAB after $ at the end of the string add a "{"
2337   if (dollar_pos == str.size() - 1) {
2338     std::string match = str.str();
2339     match.append("{");
2340     matches.AppendString(match);
2341     return 1;
2342   }
2343 
2344   if (str[dollar_pos + 1] != '{')
2345     return 0;
2346 
2347   const size_t close_pos = str.find('}', dollar_pos + 2);
2348   if (close_pos != llvm::StringRef::npos)
2349     return 0;
2350 
2351   const size_t format_pos = str.find('%', dollar_pos + 2);
2352   if (format_pos != llvm::StringRef::npos)
2353     return 0;
2354 
2355   llvm::StringRef partial_variable(str.substr(dollar_pos + 2));
2356   if (partial_variable.empty()) {
2357     // Suggest all top level entites as we are just past "${"
2358     AddMatches(&g_root, str, llvm::StringRef(), matches);
2359     return matches.GetSize();
2360   }
2361 
2362   // We have a partially specified variable, find it
2363   llvm::StringRef remainder;
2364   const FormatEntity::Entry::Definition *entry_def =
2365       FindEntry(partial_variable, &g_root, remainder);
2366   if (!entry_def)
2367     return 0;
2368 
2369   const size_t n = entry_def->num_children;
2370 
2371   if (remainder.empty()) {
2372     // Exact match
2373     if (n > 0) {
2374       // "${thread.info" <TAB>
2375       matches.AppendString(MakeMatch(str, "."));
2376     } else {
2377       // "${thread.id" <TAB>
2378       matches.AppendString(MakeMatch(str, "}"));
2379       word_complete = true;
2380     }
2381   } else if (remainder.equals(".")) {
2382     // "${thread." <TAB>
2383     AddMatches(entry_def, str, llvm::StringRef(), matches);
2384   } else {
2385     // We have a partial match
2386     // "${thre" <TAB>
2387     AddMatches(entry_def, str, remainder, matches);
2388   }
2389   return matches.GetSize();
2390 }
2391