in lldb/source/Core/FormatEntity.cpp [1080:1900]
bool FormatEntity::Format(const Entry &entry, Stream &s,
const SymbolContext *sc,
const ExecutionContext *exe_ctx, const Address *addr,
ValueObject *valobj, bool function_changed,
bool initial_function) {
switch (entry.type) {
case Entry::Type::Invalid:
case Entry::Type::ParentNumber: // Only used for
// FormatEntity::Entry::Definition encoding
case Entry::Type::ParentString: // Only used for
// FormatEntity::Entry::Definition encoding
return false;
case Entry::Type::EscapeCode:
if (exe_ctx) {
if (Target *target = exe_ctx->GetTargetPtr()) {
Debugger &debugger = target->GetDebugger();
if (debugger.GetUseColor()) {
s.PutCString(entry.string);
}
}
}
// Always return true, so colors being disabled is transparent.
return true;
case Entry::Type::Root:
for (const auto &child : entry.children) {
if (!Format(child, s, sc, exe_ctx, addr, valobj, function_changed,
initial_function)) {
return false; // If any item of root fails, then the formatting fails
}
}
return true; // Only return true if all items succeeded
case Entry::Type::String:
s.PutCString(entry.string);
return true;
case Entry::Type::Scope: {
StreamString scope_stream;
bool success = false;
for (const auto &child : entry.children) {
success = Format(child, scope_stream, sc, exe_ctx, addr, valobj,
function_changed, initial_function);
if (!success)
break;
}
// Only if all items in a scope succeed, then do we print the output into
// the main stream
if (success)
s.Write(scope_stream.GetString().data(), scope_stream.GetString().size());
}
return true; // Scopes always successfully print themselves
case Entry::Type::Variable:
case Entry::Type::VariableSynthetic:
case Entry::Type::ScriptVariable:
case Entry::Type::ScriptVariableSynthetic:
return DumpValue(s, sc, exe_ctx, entry, valobj);
case Entry::Type::AddressFile:
case Entry::Type::AddressLoad:
case Entry::Type::AddressLoadOrFile:
return (
addr != nullptr && addr->IsValid() &&
DumpAddressAndContent(s, sc, exe_ctx, *addr,
entry.type == Entry::Type::AddressLoadOrFile));
case Entry::Type::ProcessID:
if (exe_ctx) {
Process *process = exe_ctx->GetProcessPtr();
if (process) {
const char *format = "%" PRIu64;
if (!entry.printf_format.empty())
format = entry.printf_format.c_str();
s.Printf(format, process->GetID());
return true;
}
}
return false;
case Entry::Type::ProcessFile:
if (exe_ctx) {
Process *process = exe_ctx->GetProcessPtr();
if (process) {
Module *exe_module = process->GetTarget().GetExecutableModulePointer();
if (exe_module) {
if (DumpFile(s, exe_module->GetFileSpec(), (FileKind)entry.number))
return true;
}
}
}
return false;
case Entry::Type::ScriptProcess:
if (exe_ctx) {
Process *process = exe_ctx->GetProcessPtr();
if (process)
return RunScriptFormatKeyword(s, sc, exe_ctx, process,
entry.string.c_str());
}
return false;
case Entry::Type::ThreadID:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread) {
const char *format = "0x%4.4" PRIx64;
if (!entry.printf_format.empty()) {
// Watch for the special "tid" format...
if (entry.printf_format == "tid") {
// TODO(zturner): Rather than hardcoding this to be platform
// specific, it should be controlled by a setting and the default
// value of the setting can be different depending on the platform.
Target &target = thread->GetProcess()->GetTarget();
ArchSpec arch(target.GetArchitecture());
llvm::Triple::OSType ostype = arch.IsValid()
? arch.GetTriple().getOS()
: llvm::Triple::UnknownOS;
if ((ostype == llvm::Triple::FreeBSD) ||
(ostype == llvm::Triple::Linux) ||
(ostype == llvm::Triple::NetBSD)) {
format = "%" PRIu64;
}
} else {
format = entry.printf_format.c_str();
}
}
s.Printf(format, thread->GetID());
return true;
}
}
return false;
case Entry::Type::ThreadProtocolID:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread) {
const char *format = "0x%4.4" PRIx64;
if (!entry.printf_format.empty())
format = entry.printf_format.c_str();
s.Printf(format, thread->GetProtocolID());
return true;
}
}
return false;
case Entry::Type::ThreadIndexID:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread) {
const char *format = "%" PRIu32;
if (!entry.printf_format.empty())
format = entry.printf_format.c_str();
s.Printf(format, thread->GetIndexID());
return true;
}
}
return false;
case Entry::Type::ThreadName:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread) {
const char *cstr = thread->GetName();
if (cstr && cstr[0]) {
s.PutCString(cstr);
return true;
}
}
}
return false;
case Entry::Type::ThreadQueue:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread) {
const char *cstr = thread->GetQueueName();
if (cstr && cstr[0]) {
s.PutCString(cstr);
return true;
}
}
}
return false;
case Entry::Type::ThreadStopReason:
if (exe_ctx) {
if (Thread *thread = exe_ctx->GetThreadPtr()) {
std::string stop_description = thread->GetStopDescription();
if (!stop_description.empty()) {
s.PutCString(stop_description);
return true;
}
}
}
return false;
case Entry::Type::ThreadStopReasonRaw:
if (exe_ctx) {
if (Thread *thread = exe_ctx->GetThreadPtr()) {
std::string stop_description = thread->GetStopDescriptionRaw();
if (!stop_description.empty()) {
s.PutCString(stop_description);
return true;
}
}
}
return false;
case Entry::Type::ThreadReturnValue:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread) {
StopInfoSP stop_info_sp = thread->GetStopInfo();
if (stop_info_sp && stop_info_sp->IsValid()) {
ValueObjectSP return_valobj_sp =
StopInfo::GetReturnValueObject(stop_info_sp);
if (return_valobj_sp) {
return_valobj_sp->Dump(s);
return true;
}
}
}
}
return false;
case Entry::Type::ThreadCompletedExpression:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread) {
StopInfoSP stop_info_sp = thread->GetStopInfo();
if (stop_info_sp && stop_info_sp->IsValid()) {
ExpressionVariableSP expression_var_sp =
StopInfo::GetExpressionVariable(stop_info_sp);
if (expression_var_sp && expression_var_sp->GetValueObject()) {
expression_var_sp->GetValueObject()->Dump(s);
return true;
}
}
}
}
return false;
case Entry::Type::ScriptThread:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread)
return RunScriptFormatKeyword(s, sc, exe_ctx, thread,
entry.string.c_str());
}
return false;
case Entry::Type::ThreadInfo:
if (exe_ctx) {
Thread *thread = exe_ctx->GetThreadPtr();
if (thread) {
StructuredData::ObjectSP object_sp = thread->GetExtendedInfo();
if (object_sp &&
object_sp->GetType() == eStructuredDataTypeDictionary) {
if (FormatThreadExtendedInfoRecurse(entry, object_sp, sc, exe_ctx, s))
return true;
}
}
}
return false;
case Entry::Type::TargetArch:
if (exe_ctx) {
Target *target = exe_ctx->GetTargetPtr();
if (target) {
const ArchSpec &arch = target->GetArchitecture();
if (arch.IsValid()) {
s.PutCString(arch.GetArchitectureName());
return true;
}
}
}
return false;
case Entry::Type::ScriptTarget:
if (exe_ctx) {
Target *target = exe_ctx->GetTargetPtr();
if (target)
return RunScriptFormatKeyword(s, sc, exe_ctx, target,
entry.string.c_str());
}
return false;
case Entry::Type::ModuleFile:
if (sc) {
Module *module = sc->module_sp.get();
if (module) {
if (DumpFile(s, module->GetFileSpec(), (FileKind)entry.number))
return true;
}
}
return false;
case Entry::Type::File:
if (sc) {
CompileUnit *cu = sc->comp_unit;
if (cu) {
if (DumpFile(s, cu->GetPrimaryFile(), (FileKind)entry.number))
return true;
}
}
return false;
case Entry::Type::Lang:
if (sc) {
CompileUnit *cu = sc->comp_unit;
if (cu) {
const char *lang_name =
Language::GetNameForLanguageType(cu->GetLanguage());
if (lang_name) {
s.PutCString(lang_name);
return true;
}
}
}
return false;
case Entry::Type::FrameIndex:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
const char *format = "%" PRIu32;
if (!entry.printf_format.empty())
format = entry.printf_format.c_str();
s.Printf(format, frame->GetFrameIndex());
return true;
}
}
return false;
case Entry::Type::FrameRegisterPC:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
const Address &pc_addr = frame->GetFrameCodeAddress();
if (pc_addr.IsValid()) {
if (DumpAddressAndContent(s, sc, exe_ctx, pc_addr, false))
return true;
}
}
}
return false;
case Entry::Type::FrameRegisterSP:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP,
(lldb::Format)entry.number))
return true;
}
}
return false;
case Entry::Type::FrameRegisterFP:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP,
(lldb::Format)entry.number))
return true;
}
}
return false;
case Entry::Type::FrameRegisterFlags:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
if (DumpRegister(s, frame, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FLAGS, (lldb::Format)entry.number))
return true;
}
}
return false;
case Entry::Type::FrameNoDebug:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
return !frame->HasDebugInformation();
}
}
return true;
case Entry::Type::FrameRegisterByName:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
if (DumpRegister(s, frame, entry.string.c_str(),
(lldb::Format)entry.number))
return true;
}
}
return false;
case Entry::Type::FrameIsArtificial: {
if (exe_ctx)
if (StackFrame *frame = exe_ctx->GetFramePtr())
return frame->IsArtificial();
return false;
}
case Entry::Type::ScriptFrame:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame)
return RunScriptFormatKeyword(s, sc, exe_ctx, frame,
entry.string.c_str());
}
return false;
case Entry::Type::FunctionID:
if (sc) {
if (sc->function) {
s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID());
return true;
} else if (sc->symbol) {
s.Printf("symbol[%u]", sc->symbol->GetID());
return true;
}
}
return false;
case Entry::Type::FunctionDidChange:
return function_changed;
case Entry::Type::FunctionInitialFunction:
return initial_function;
case Entry::Type::FunctionName: {
if (!sc)
return false;
Language *language_plugin = nullptr;
bool language_plugin_handled = false;
StreamString ss;
if (sc->function)
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
else if (sc->symbol)
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
if (language_plugin)
language_plugin_handled = language_plugin->GetFunctionDisplayName(
sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
if (language_plugin_handled) {
s << ss.GetString();
return true;
} else {
const char *name = nullptr;
if (sc->function)
name = sc->function->GetName().AsCString(nullptr);
else if (sc->symbol)
name = sc->symbol->GetName().AsCString(nullptr);
if (name) {
s.PutCString(name);
if (sc->block) {
Block *inline_block = sc->block->GetContainingInlinedBlock();
if (inline_block) {
const InlineFunctionInfo *inline_info =
sc->block->GetInlinedFunctionInfo();
if (inline_info) {
s.PutCString(" [inlined] ");
inline_info->GetName().Dump(&s);
}
}
}
return true;
}
}
}
return false;
case Entry::Type::FunctionNameNoArgs: {
if (!sc)
return false;
Language *language_plugin = nullptr;
bool language_plugin_handled = false;
StreamString ss;
if (sc->function)
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
else if (sc->symbol)
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
if (language_plugin)
language_plugin_handled = language_plugin->GetFunctionDisplayName(
sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
ss);
if (language_plugin_handled) {
s << ss.GetString();
return true;
} else {
ConstString name;
if (sc->function)
name = sc->function->GetNameNoArguments();
else if (sc->symbol)
name = sc->symbol->GetNameNoArguments();
if (name) {
s.PutCString(name.GetCString());
return true;
}
}
}
return false;
case Entry::Type::FunctionNameWithArgs: {
if (!sc)
return false;
Language *language_plugin = nullptr;
bool language_plugin_handled = false;
StreamString ss;
if (sc->function)
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
else if (sc->symbol)
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
if (language_plugin)
language_plugin_handled = language_plugin->GetFunctionDisplayName(
sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss);
if (language_plugin_handled) {
s << ss.GetString();
return true;
} else {
// Print the function name with arguments in it
if (sc->function) {
ExecutionContextScope *exe_scope =
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
const char *cstr = sc->function->GetName().AsCString(nullptr);
if (cstr) {
const InlineFunctionInfo *inline_info = nullptr;
VariableListSP variable_list_sp;
bool get_function_vars = true;
if (sc->block) {
Block *inline_block = sc->block->GetContainingInlinedBlock();
if (inline_block) {
get_function_vars = false;
inline_info = sc->block->GetInlinedFunctionInfo();
if (inline_info)
variable_list_sp = inline_block->GetBlockVariableList(true);
}
}
if (get_function_vars) {
variable_list_sp =
sc->function->GetBlock(true).GetBlockVariableList(true);
}
if (inline_info) {
s.PutCString(cstr);
s.PutCString(" [inlined] ");
cstr = inline_info->GetName().GetCString();
}
VariableList args;
if (variable_list_sp)
variable_list_sp->AppendVariablesWithScope(
eValueTypeVariableArgument, args);
if (args.GetSize() > 0) {
const char *open_paren = strchr(cstr, '(');
const char *close_paren = nullptr;
const char *generic = strchr(cstr, '<');
// if before the arguments list begins there is a template sign
// then scan to the end of the generic args before you try to find
// the arguments list
if (generic && open_paren && generic < open_paren) {
int generic_depth = 1;
++generic;
for (; *generic && generic_depth > 0; generic++) {
if (*generic == '<')
generic_depth++;
if (*generic == '>')
generic_depth--;
}
if (*generic)
open_paren = strchr(generic, '(');
else
open_paren = nullptr;
}
if (open_paren) {
if (IsToken(open_paren, "(anonymous namespace)")) {
open_paren =
strchr(open_paren + strlen("(anonymous namespace)"), '(');
if (open_paren)
close_paren = strchr(open_paren, ')');
} else
close_paren = strchr(open_paren, ')');
}
if (open_paren)
s.Write(cstr, open_paren - cstr + 1);
else {
s.PutCString(cstr);
s.PutChar('(');
}
const size_t num_args = args.GetSize();
for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) {
std::string buffer;
VariableSP var_sp(args.GetVariableAtIndex(arg_idx));
ValueObjectSP var_value_sp(
ValueObjectVariable::Create(exe_scope, var_sp));
StreamString ss;
llvm::StringRef var_representation;
const char *var_name = var_value_sp->GetName().GetCString();
if (var_value_sp->GetCompilerType().IsValid()) {
if (var_value_sp && exe_scope->CalculateTarget())
var_value_sp =
var_value_sp->GetQualifiedRepresentationIfAvailable(
exe_scope->CalculateTarget()
->TargetProperties::GetPreferDynamicValue(),
exe_scope->CalculateTarget()
->TargetProperties::GetEnableSyntheticValue());
if (var_value_sp->GetCompilerType().IsAggregateType() &&
DataVisualization::ShouldPrintAsOneLiner(*var_value_sp)) {
static StringSummaryFormat format(
TypeSummaryImpl::Flags()
.SetHideItemNames(false)
.SetShowMembersOneLiner(true),
"");
format.FormatObject(var_value_sp.get(), buffer,
TypeSummaryOptions());
var_representation = buffer;
} else
var_value_sp->DumpPrintableRepresentation(
ss,
ValueObject::ValueObjectRepresentationStyle::
eValueObjectRepresentationStyleSummary,
eFormatDefault,
ValueObject::PrintableRepresentationSpecialCases::eAllow,
false);
}
if (!ss.GetString().empty())
var_representation = ss.GetString();
if (arg_idx > 0)
s.PutCString(", ");
if (var_value_sp->GetError().Success()) {
if (!var_representation.empty())
s.Printf("%s=%s", var_name, var_representation.str().c_str());
else
s.Printf("%s=%s at %s", var_name,
var_value_sp->GetTypeName().GetCString(),
var_value_sp->GetLocationAsCString());
} else
s.Printf("%s=<unavailable>", var_name);
}
if (close_paren)
s.PutCString(close_paren);
else
s.PutChar(')');
} else {
s.PutCString(cstr);
}
return true;
}
} else if (sc->symbol) {
const char *cstr = sc->symbol->GetName().AsCString(nullptr);
if (cstr) {
s.PutCString(cstr);
return true;
}
}
}
}
return false;
case Entry::Type::FunctionMangledName: {
if (!sc)
return false;
const char *name = nullptr;
if (sc->symbol)
name =
sc->symbol->GetMangled().GetName(Mangled::ePreferMangled).AsCString();
else if (sc->function)
name = sc->function->GetMangled()
.GetName(Mangled::ePreferMangled)
.AsCString();
if (!name)
return false;
s.PutCString(name);
if (sc->block && sc->block->GetContainingInlinedBlock()) {
if (const InlineFunctionInfo *inline_info =
sc->block->GetInlinedFunctionInfo()) {
s.PutCString(" [inlined] ");
inline_info->GetName().Dump(&s);
}
}
return true;
}
case Entry::Type::FunctionAddrOffset:
if (addr) {
if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, false, false,
false))
return true;
}
return false;
case Entry::Type::FunctionAddrOffsetConcrete:
if (addr) {
if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, true, true,
true))
return true;
}
return false;
case Entry::Type::FunctionLineOffset:
if (sc)
return (DumpAddressOffsetFromFunction(
s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false,
false));
return false;
case Entry::Type::FunctionPCOffset:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
if (DumpAddressOffsetFromFunction(s, sc, exe_ctx,
frame->GetFrameCodeAddress(), false,
false, false))
return true;
}
}
return false;
case Entry::Type::FunctionChanged:
return function_changed;
case Entry::Type::FunctionIsOptimized: {
bool is_optimized = false;
if (sc && sc->function && sc->function->GetIsOptimized()) {
is_optimized = true;
}
return is_optimized;
}
case Entry::Type::FunctionInitial:
return initial_function;
case Entry::Type::LineEntryFile:
if (sc && sc->line_entry.IsValid()) {
Module *module = sc->module_sp.get();
if (module) {
if (DumpFile(s, sc->line_entry.file, (FileKind)entry.number))
return true;
}
}
return false;
case Entry::Type::LineEntryLineNumber:
if (sc && sc->line_entry.IsValid()) {
const char *format = "%" PRIu32;
if (!entry.printf_format.empty())
format = entry.printf_format.c_str();
s.Printf(format, sc->line_entry.line);
return true;
}
return false;
case Entry::Type::LineEntryColumn:
if (sc && sc->line_entry.IsValid() && sc->line_entry.column) {
const char *format = "%" PRIu32;
if (!entry.printf_format.empty())
format = entry.printf_format.c_str();
s.Printf(format, sc->line_entry.column);
return true;
}
return false;
case Entry::Type::LineEntryStartAddress:
case Entry::Type::LineEntryEndAddress:
if (sc && sc->line_entry.range.GetBaseAddress().IsValid()) {
Address addr = sc->line_entry.range.GetBaseAddress();
if (entry.type == Entry::Type::LineEntryEndAddress)
addr.Slide(sc->line_entry.range.GetByteSize());
if (DumpAddressAndContent(s, sc, exe_ctx, addr, false))
return true;
}
return false;
case Entry::Type::CurrentPCArrow:
if (addr && exe_ctx && exe_ctx->GetFramePtr()) {
RegisterContextSP reg_ctx =
exe_ctx->GetFramePtr()->GetRegisterContextSP();
if (reg_ctx) {
addr_t pc_loadaddr = reg_ctx->GetPC();
if (pc_loadaddr != LLDB_INVALID_ADDRESS) {
Address pc;
pc.SetLoadAddress(pc_loadaddr, exe_ctx->GetTargetPtr());
if (pc == *addr) {
s.Printf("-> ");
return true;
}
}
}
s.Printf(" ");
return true;
}
return false;
}
return false;
}