brintos

brintos / llvm-project-archived public Read only

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