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