diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h --- a/lldb/include/lldb/Core/FormatEntity.h +++ b/lldb/include/lldb/Core/FormatEntity.h @@ -9,9 +9,6 @@ #ifndef LLDB_CORE_FORMATENTITY_H #define LLDB_CORE_FORMATENTITY_H -#include "lldb/Utility/CompletionRequest.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/Status.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-types.h" #include @@ -23,12 +20,16 @@ namespace lldb_private { class Address; +class CompletionRequest; class ExecutionContext; +class FileSpec; +class Status; class Stream; class StringList; class SymbolContext; class ValueObject; } + namespace llvm { class StringRef; } @@ -103,20 +104,52 @@ }; struct Definition { + /// The name/string placeholder that corresponds to this definition. const char *name; - const char *string; // Insert this exact string into the output - Entry::Type type; - uint64_t data; - uint32_t num_children; - Definition *children; // An array of "num_children" Definition entries, - bool keep_separator; + /// Insert this exact string into the output + const char *string = nullptr; + /// Entry::Type corresponding to this definition. + const Entry::Type type; + /// Data that is returned as the value of the format string. + const uint64_t data = 0; + /// The number of children of this node in the tree of format strings. + const uint32_t num_children = 0; + /// An array of "num_children" Definition entries. + const Definition *children = nullptr; + /// Whether the separator is kept during parsing or not. It's used + /// for entries with parameters. + const bool keep_separator = false; + + constexpr Definition(const char *name, const FormatEntity::Entry::Type t) + : name(name), type(t) {} + + constexpr Definition(const char *name, const char *string) + : name(name), string(string), type(Entry::Type::EscapeCode) {} + + constexpr Definition(const char *name, const FormatEntity::Entry::Type t, + const uint64_t data) + : name(name), string(nullptr), type(t), data(data) {} + + constexpr Definition(const char *name, const FormatEntity::Entry::Type t, + const uint64_t num_children, + const Definition *children, + const bool keep_separator = false) + : name(name), type(t), num_children(num_children), children(children), + keep_separator(keep_separator) {} }; + template + static constexpr Definition + DefinitionWithChildren(const char *name, const FormatEntity::Entry::Type t, + const Definition (&children)[N], + bool keep_separator = false) { + return Definition(name, t, N, children, keep_separator); + } + Entry(Type t = Type::Invalid, const char *s = nullptr, const char *f = nullptr) - : string(s ? s : ""), printf_format(f ? f : ""), children(), - definition(nullptr), type(t), fmt(lldb::eFormatDefault), number(0), - deref(false) {} + : string(s ? s : ""), printf_format(f ? f : ""), children(), type(t), + fmt(lldb::eFormatDefault), number(0), deref(false) {} Entry(llvm::StringRef s); Entry(char ch); @@ -133,7 +166,6 @@ string.clear(); printf_format.clear(); children.clear(); - definition = nullptr; type = Type::Invalid; fmt = lldb::eFormatDefault; number = 0; @@ -157,8 +189,6 @@ } if (children != rhs.children) return false; - if (definition != rhs.definition) - return false; if (type != rhs.type) return false; if (fmt != rhs.fmt) @@ -171,7 +201,6 @@ std::string string; std::string printf_format; std::vector children; - Definition *definition; Type type; lldb::Format fmt; lldb::addr_t number; diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -41,11 +41,13 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" #include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" @@ -76,203 +78,196 @@ using namespace lldb; using namespace lldb_private; -enum FileKind { FileError = 0, Basename, Dirname, Fullpath }; - -#define ENTRY(n, t) \ - { n, nullptr, FormatEntity::Entry::Type::t, 0, 0, nullptr, false } -#define ENTRY_VALUE(n, t, v) \ - { n, nullptr, FormatEntity::Entry::Type::t, v, 0, nullptr, false } -#define ENTRY_CHILDREN(n, t, c) \ - { \ - n, nullptr, FormatEntity::Entry::Type::t, 0, \ - static_cast(llvm::array_lengthof(c)), c, false \ - } -#define ENTRY_CHILDREN_KEEP_SEP(n, t, c) \ - { \ - n, nullptr, FormatEntity::Entry::Type::t, 0, \ - static_cast(llvm::array_lengthof(c)), c, true \ - } -#define ENTRY_STRING(n, s) \ - { n, s, FormatEntity::Entry::Type::EscapeCode, 0, 0, nullptr, false } -static FormatEntity::Entry::Definition g_string_entry[] = { - ENTRY("*", ParentString)}; - -static FormatEntity::Entry::Definition g_addr_entries[] = { - ENTRY("load", AddressLoad), - ENTRY("file", AddressFile), - ENTRY("load", AddressLoadOrFile), -}; +using Definition = lldb_private::FormatEntity::Entry::Definition; +using Entry = FormatEntity::Entry; +using EntryType = FormatEntity::Entry::Type; -static FormatEntity::Entry::Definition g_file_child_entries[] = { - ENTRY_VALUE("basename", ParentNumber, FileKind::Basename), - ENTRY_VALUE("dirname", ParentNumber, FileKind::Dirname), - ENTRY_VALUE("fullpath", ParentNumber, FileKind::Fullpath)}; - -static FormatEntity::Entry::Definition g_frame_child_entries[] = { - ENTRY("index", FrameIndex), - ENTRY("pc", FrameRegisterPC), - ENTRY("fp", FrameRegisterFP), - ENTRY("sp", FrameRegisterSP), - ENTRY("flags", FrameRegisterFlags), - ENTRY("no-debug", FrameNoDebug), - ENTRY_CHILDREN("reg", FrameRegisterByName, g_string_entry), - ENTRY("is-artificial", FrameIsArtificial), -}; - -static FormatEntity::Entry::Definition g_function_child_entries[] = { - ENTRY("id", FunctionID), - ENTRY("name", FunctionName), - ENTRY("name-without-args", FunctionNameNoArgs), - ENTRY("name-with-args", FunctionNameWithArgs), - ENTRY("mangled-name", FunctionMangledName), - ENTRY("addr-offset", FunctionAddrOffset), - ENTRY("concrete-only-addr-offset-no-padding", FunctionAddrOffsetConcrete), - ENTRY("line-offset", FunctionLineOffset), - ENTRY("pc-offset", FunctionPCOffset), - ENTRY("initial-function", FunctionInitial), - ENTRY("changed", FunctionChanged), - ENTRY("is-optimized", FunctionIsOptimized)}; - -static FormatEntity::Entry::Definition g_line_child_entries[] = { - ENTRY_CHILDREN("file", LineEntryFile, g_file_child_entries), - ENTRY("number", LineEntryLineNumber), - ENTRY("column", LineEntryColumn), - ENTRY("start-addr", LineEntryStartAddress), - ENTRY("end-addr", LineEntryEndAddress), -}; - -static FormatEntity::Entry::Definition g_module_child_entries[] = { - ENTRY_CHILDREN("file", ModuleFile, g_file_child_entries), -}; +enum FileKind { FileError = 0, Basename, Dirname, Fullpath }; -static FormatEntity::Entry::Definition g_process_child_entries[] = { - ENTRY("id", ProcessID), - ENTRY_VALUE("name", ProcessFile, FileKind::Basename), - ENTRY_CHILDREN("file", ProcessFile, g_file_child_entries), +constexpr Definition g_string_entry[] = { + Definition("*", EntryType::ParentString)}; + +constexpr Definition g_addr_entries[] = { + Definition("load", EntryType::AddressLoad), + Definition("file", EntryType::AddressFile)}; + +constexpr Definition g_file_child_entries[] = { + Definition("basename", EntryType::ParentNumber, FileKind::Basename), + Definition("dirname", EntryType::ParentNumber, FileKind::Dirname), + Definition("fullpath", EntryType::ParentNumber, FileKind::Fullpath)}; + +constexpr Definition g_frame_child_entries[] = { + Definition("index", EntryType::FrameIndex), + Definition("pc", EntryType::FrameRegisterPC), + Definition("fp", EntryType::FrameRegisterFP), + Definition("sp", EntryType::FrameRegisterSP), + Definition("flags", EntryType::FrameRegisterFlags), + Definition("no-debug", EntryType::FrameNoDebug), + Entry::DefinitionWithChildren("reg", EntryType::FrameRegisterByName, + g_string_entry), + Definition("is-artificial", EntryType::FrameIsArtificial), }; -static FormatEntity::Entry::Definition g_svar_child_entries[] = { - ENTRY("*", ParentString)}; - -static FormatEntity::Entry::Definition g_var_child_entries[] = { - ENTRY("*", ParentString)}; - -static FormatEntity::Entry::Definition g_thread_child_entries[] = { - ENTRY("id", ThreadID), - ENTRY("protocol_id", ThreadProtocolID), - ENTRY("index", ThreadIndexID), - ENTRY_CHILDREN("info", ThreadInfo, g_string_entry), - ENTRY("queue", ThreadQueue), - ENTRY("name", ThreadName), - ENTRY("stop-reason", ThreadStopReason), - ENTRY("stop-reason-raw", ThreadStopReasonRaw), - ENTRY("return-value", ThreadReturnValue), - ENTRY("completed-expression", ThreadCompletedExpression), +constexpr Definition g_function_child_entries[] = { + Definition("id", EntryType::FunctionID), + Definition("name", EntryType::FunctionName), + Definition("name-without-args", EntryType::FunctionNameNoArgs), + Definition("name-with-args", EntryType::FunctionNameWithArgs), + Definition("mangled-name", EntryType::FunctionMangledName), + Definition("addr-offset", EntryType::FunctionAddrOffset), + Definition("concrete-only-addr-offset-no-padding", + EntryType::FunctionAddrOffsetConcrete), + Definition("line-offset", EntryType::FunctionLineOffset), + Definition("pc-offset", EntryType::FunctionPCOffset), + Definition("initial-function", EntryType::FunctionInitial), + Definition("changed", EntryType::FunctionChanged), + Definition("is-optimized", EntryType::FunctionIsOptimized)}; + +constexpr Definition g_line_child_entries[] = { + Entry::DefinitionWithChildren("file", EntryType::LineEntryFile, + g_file_child_entries), + Definition("number", EntryType::LineEntryLineNumber), + Definition("column", EntryType::LineEntryColumn), + Definition("start-addr", EntryType::LineEntryStartAddress), + Definition("end-addr", EntryType::LineEntryEndAddress), }; -static FormatEntity::Entry::Definition g_target_child_entries[] = { - ENTRY("arch", TargetArch), -}; +constexpr Definition g_module_child_entries[] = {Entry::DefinitionWithChildren( + "file", EntryType::ModuleFile, g_file_child_entries)}; + +constexpr Definition g_process_child_entries[] = { + Definition("id", EntryType::ProcessID), + Definition("name", EntryType::ProcessFile, FileKind::Basename), + Entry::DefinitionWithChildren("file", EntryType::ProcessFile, + g_file_child_entries)}; + +constexpr Definition g_svar_child_entries[] = { + Definition("*", EntryType::ParentString)}; + +constexpr Definition g_var_child_entries[] = { + Definition("*", EntryType::ParentString)}; + +constexpr Definition g_thread_child_entries[] = { + Definition("id", EntryType::ThreadID), + Definition("protocol_id", EntryType::ThreadProtocolID), + Definition("index", EntryType::ThreadIndexID), + Entry::DefinitionWithChildren("info", EntryType::ThreadInfo, + g_string_entry), + Definition("queue", EntryType::ThreadQueue), + Definition("name", EntryType::ThreadName), + Definition("stop-reason", EntryType::ThreadStopReason), + Definition("stop-reason-raw", EntryType::ThreadStopReasonRaw), + Definition("return-value", EntryType::ThreadReturnValue), + Definition("completed-expression", EntryType::ThreadCompletedExpression)}; + +constexpr Definition g_target_child_entries[] = { + Definition("arch", EntryType::TargetArch)}; #define _TO_STR2(_val) #_val #define _TO_STR(_val) _TO_STR2(_val) -static FormatEntity::Entry::Definition g_ansi_fg_entries[] = { - ENTRY_STRING("black", - ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLACK) ANSI_ESC_END), - ENTRY_STRING("red", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_RED) ANSI_ESC_END), - ENTRY_STRING("green", - ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_GREEN) ANSI_ESC_END), - ENTRY_STRING("yellow", - ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_YELLOW) ANSI_ESC_END), - ENTRY_STRING("blue", - ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLUE) ANSI_ESC_END), - ENTRY_STRING("purple", - ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_PURPLE) ANSI_ESC_END), - ENTRY_STRING("cyan", - ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_CYAN) ANSI_ESC_END), - ENTRY_STRING("white", - ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_WHITE) ANSI_ESC_END), -}; - -static FormatEntity::Entry::Definition g_ansi_bg_entries[] = { - ENTRY_STRING("black", - ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLACK) ANSI_ESC_END), - ENTRY_STRING("red", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_RED) ANSI_ESC_END), - ENTRY_STRING("green", - ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_GREEN) ANSI_ESC_END), - ENTRY_STRING("yellow", - ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_YELLOW) ANSI_ESC_END), - ENTRY_STRING("blue", - ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLUE) ANSI_ESC_END), - ENTRY_STRING("purple", - ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_PURPLE) ANSI_ESC_END), - ENTRY_STRING("cyan", - ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_CYAN) ANSI_ESC_END), - ENTRY_STRING("white", - ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_WHITE) ANSI_ESC_END), -}; - -static FormatEntity::Entry::Definition g_ansi_entries[] = { - ENTRY_CHILDREN("fg", Invalid, g_ansi_fg_entries), - ENTRY_CHILDREN("bg", Invalid, g_ansi_bg_entries), - ENTRY_STRING("normal", - ANSI_ESC_START _TO_STR(ANSI_CTRL_NORMAL) ANSI_ESC_END), - ENTRY_STRING("bold", ANSI_ESC_START _TO_STR(ANSI_CTRL_BOLD) ANSI_ESC_END), - ENTRY_STRING("faint", ANSI_ESC_START _TO_STR(ANSI_CTRL_FAINT) ANSI_ESC_END), - ENTRY_STRING("italic", - ANSI_ESC_START _TO_STR(ANSI_CTRL_ITALIC) ANSI_ESC_END), - ENTRY_STRING("underline", - ANSI_ESC_START _TO_STR(ANSI_CTRL_UNDERLINE) ANSI_ESC_END), - ENTRY_STRING("slow-blink", - ANSI_ESC_START _TO_STR(ANSI_CTRL_SLOW_BLINK) ANSI_ESC_END), - ENTRY_STRING("fast-blink", - ANSI_ESC_START _TO_STR(ANSI_CTRL_FAST_BLINK) ANSI_ESC_END), - ENTRY_STRING("negative", - ANSI_ESC_START _TO_STR(ANSI_CTRL_IMAGE_NEGATIVE) ANSI_ESC_END), - ENTRY_STRING("conceal", - ANSI_ESC_START _TO_STR(ANSI_CTRL_CONCEAL) ANSI_ESC_END), - ENTRY_STRING("crossed-out", - ANSI_ESC_START _TO_STR(ANSI_CTRL_CROSSED_OUT) ANSI_ESC_END), +constexpr Definition g_ansi_fg_entries[] = { + Definition("black", + ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLACK) ANSI_ESC_END), + Definition("red", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_RED) ANSI_ESC_END), + Definition("green", + ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_GREEN) ANSI_ESC_END), + Definition("yellow", + ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_YELLOW) ANSI_ESC_END), + Definition("blue", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLUE) ANSI_ESC_END), + Definition("purple", + ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_PURPLE) ANSI_ESC_END), + Definition("cyan", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_CYAN) ANSI_ESC_END), + Definition("white", + ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_WHITE) ANSI_ESC_END), }; -static FormatEntity::Entry::Definition g_script_child_entries[] = { - ENTRY("frame", ScriptFrame), ENTRY("process", ScriptProcess), - ENTRY("target", ScriptTarget), ENTRY("thread", ScriptThread), - ENTRY("var", ScriptVariable), ENTRY("svar", ScriptVariableSynthetic), - ENTRY("thread", ScriptThread), +constexpr Definition g_ansi_bg_entries[] = { + Definition("black", + ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLACK) ANSI_ESC_END), + Definition("red", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_RED) ANSI_ESC_END), + Definition("green", + ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_GREEN) ANSI_ESC_END), + Definition("yellow", + ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_YELLOW) ANSI_ESC_END), + Definition("blue", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLUE) ANSI_ESC_END), + Definition("purple", + ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_PURPLE) ANSI_ESC_END), + Definition("cyan", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_CYAN) ANSI_ESC_END), + Definition("white", + ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_WHITE) ANSI_ESC_END), }; -static FormatEntity::Entry::Definition g_top_level_entries[] = { - ENTRY_CHILDREN("addr", AddressLoadOrFile, g_addr_entries), - ENTRY("addr-file-or-load", AddressLoadOrFile), - ENTRY_CHILDREN("ansi", Invalid, g_ansi_entries), - ENTRY("current-pc-arrow", CurrentPCArrow), - ENTRY_CHILDREN("file", File, g_file_child_entries), - ENTRY("language", Lang), - ENTRY_CHILDREN("frame", Invalid, g_frame_child_entries), - ENTRY_CHILDREN("function", Invalid, g_function_child_entries), - ENTRY_CHILDREN("line", Invalid, g_line_child_entries), - ENTRY_CHILDREN("module", Invalid, g_module_child_entries), - ENTRY_CHILDREN("process", Invalid, g_process_child_entries), - ENTRY_CHILDREN("script", Invalid, g_script_child_entries), - ENTRY_CHILDREN_KEEP_SEP("svar", VariableSynthetic, g_svar_child_entries), - ENTRY_CHILDREN("thread", Invalid, g_thread_child_entries), - ENTRY_CHILDREN("target", Invalid, g_target_child_entries), - ENTRY_CHILDREN_KEEP_SEP("var", Variable, g_var_child_entries), +constexpr Definition g_ansi_entries[] = { + Entry::DefinitionWithChildren("fg", EntryType::Invalid, g_ansi_fg_entries), + Entry::DefinitionWithChildren("bg", EntryType::Invalid, g_ansi_bg_entries), + Definition("normal", ANSI_ESC_START _TO_STR(ANSI_CTRL_NORMAL) ANSI_ESC_END), + Definition("bold", ANSI_ESC_START _TO_STR(ANSI_CTRL_BOLD) ANSI_ESC_END), + Definition("faint", ANSI_ESC_START _TO_STR(ANSI_CTRL_FAINT) ANSI_ESC_END), + Definition("italic", ANSI_ESC_START _TO_STR(ANSI_CTRL_ITALIC) ANSI_ESC_END), + Definition("underline", + ANSI_ESC_START _TO_STR(ANSI_CTRL_UNDERLINE) ANSI_ESC_END), + Definition("slow-blink", + ANSI_ESC_START _TO_STR(ANSI_CTRL_SLOW_BLINK) ANSI_ESC_END), + Definition("fast-blink", + ANSI_ESC_START _TO_STR(ANSI_CTRL_FAST_BLINK) ANSI_ESC_END), + Definition("negative", + ANSI_ESC_START _TO_STR(ANSI_CTRL_IMAGE_NEGATIVE) ANSI_ESC_END), + Definition("conceal", + ANSI_ESC_START _TO_STR(ANSI_CTRL_CONCEAL) ANSI_ESC_END), + Definition("crossed-out", + ANSI_ESC_START _TO_STR(ANSI_CTRL_CROSSED_OUT) ANSI_ESC_END), }; -static FormatEntity::Entry::Definition g_root = - ENTRY_CHILDREN("", Root, g_top_level_entries); +constexpr Definition g_script_child_entries[] = { + Definition("frame", EntryType::ScriptFrame), + Definition("process", EntryType::ScriptProcess), + Definition("target", EntryType::ScriptTarget), + Definition("thread", EntryType::ScriptThread), + Definition("var", EntryType::ScriptVariable), + Definition("svar", EntryType::ScriptVariableSynthetic), + Definition("thread", EntryType::ScriptThread)}; + +constexpr Definition g_top_level_entries[] = { + Entry::DefinitionWithChildren("addr", EntryType::AddressLoadOrFile, + g_addr_entries), + Definition("addr-file-or-load", EntryType::AddressLoadOrFile), + Entry::DefinitionWithChildren("ansi", EntryType::Invalid, g_ansi_entries), + Definition("current-pc-arrow", EntryType::CurrentPCArrow), + Entry::DefinitionWithChildren("file", EntryType::File, + g_file_child_entries), + Definition("language", EntryType::Lang), + Entry::DefinitionWithChildren("frame", EntryType::Invalid, + g_frame_child_entries), + Entry::DefinitionWithChildren("function", EntryType::Invalid, + g_function_child_entries), + Entry::DefinitionWithChildren("line", EntryType::Invalid, + g_line_child_entries), + Entry::DefinitionWithChildren("module", EntryType::Invalid, + g_module_child_entries), + Entry::DefinitionWithChildren("process", EntryType::Invalid, + g_process_child_entries), + Entry::DefinitionWithChildren("script", EntryType::Invalid, + g_script_child_entries), + Entry::DefinitionWithChildren("svar", EntryType::VariableSynthetic, + g_svar_child_entries, true), + Entry::DefinitionWithChildren("thread", EntryType::Invalid, + g_thread_child_entries), + Entry::DefinitionWithChildren("target", EntryType::Invalid, + g_target_child_entries), + Entry::DefinitionWithChildren("var", EntryType::Variable, + g_var_child_entries, true)}; + +constexpr Definition g_root = Entry::DefinitionWithChildren( + "", EntryType::Root, g_top_level_entries); FormatEntity::Entry::Entry(llvm::StringRef s) : string(s.data(), s.size()), printf_format(), children(), - definition(nullptr), type(Type::String), fmt(lldb::eFormatDefault), - number(0), deref(false) {} + type(Type::String), fmt(lldb::eFormatDefault), number(0), deref(false) {} FormatEntity::Entry::Entry(char ch) - : string(1, ch), printf_format(), children(), definition(nullptr), - type(Type::String), fmt(lldb::eFormatDefault), number(0), deref(false) {} + : string(1, ch), printf_format(), children(), type(Type::String), + fmt(lldb::eFormatDefault), number(0), deref(false) {} void FormatEntity::Entry::AppendChar(char ch) { if (children.empty() || children.back().type != Entry::Type::String) @@ -598,9 +593,7 @@ } static bool DumpRegister(Stream &s, StackFrame *frame, RegisterKind reg_kind, - uint32_t reg_num, Format format) - -{ + uint32_t reg_num, Format format) { if (frame) { RegisterContext *reg_ctx = frame->GetRegisterContext().get(); @@ -624,7 +617,6 @@ } static ValueObjectSP ExpandIndexedExpression(ValueObject *valobj, size_t index, - StackFrame *frame, bool deref_pointer) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS)); const char *ptr_deref_format = "[%d]"; @@ -956,9 +948,7 @@ bool success = true; for (int64_t index = index_lower; index <= index_higher; ++index) { - ValueObject *item = - ExpandIndexedExpression(target, index, exe_ctx->GetFramePtr(), false) - .get(); + ValueObject *item = ExpandIndexedExpression(target, index, false).get(); if (!item) { LLDB_LOGF(log, @@ -1523,17 +1513,22 @@ 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) { + + 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; @@ -1543,6 +1538,7 @@ name = sc->function->GetName().AsCString(nullptr); else if (sc->symbol) name = sc->symbol->GetName().AsCString(nullptr); + if (name) { s.PutCString(name); @@ -1564,6 +1560,9 @@ return false; case Entry::Type::FunctionNameNoArgs: { + if (!sc) + return false; + Language *language_plugin = nullptr; bool language_plugin_handled = false; StreamString ss; @@ -1571,11 +1570,12 @@ language_plugin = Language::FindPlugin(sc->function->GetLanguage()); else if (sc->symbol) language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); - if (language_plugin) { + + 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; @@ -1594,6 +1594,9 @@ return false; case Entry::Type::FunctionNameWithArgs: { + if (!sc) + return false; + Language *language_plugin = nullptr; bool language_plugin_handled = false; StreamString ss; @@ -1601,10 +1604,11 @@ language_plugin = Language::FindPlugin(sc->function->GetLanguage()); else if (sc->symbol) language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); - if (language_plugin) { + + 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; @@ -1756,6 +1760,9 @@ return false; case Entry::Type::FunctionMangledName: { + if (!sc) + return false; + const char *name = nullptr; if (sc->symbol) name = @@ -1778,7 +1785,6 @@ } return true; } - case Entry::Type::FunctionAddrOffset: if (addr) { if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, false, false, @@ -1796,9 +1802,11 @@ return false; case Entry::Type::FunctionLineOffset: - return (DumpAddressOffsetFromFunction(s, sc, exe_ctx, - sc->line_entry.range.GetBaseAddress(), - false, false, false)); + 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) { @@ -1817,7 +1825,7 @@ case Entry::Type::FunctionIsOptimized: { bool is_optimized = false; - if (sc->function && sc->function->GetIsOptimized()) { + if (sc && sc->function && sc->function->GetIsOptimized()) { is_optimized = true; } return is_optimized; @@ -1891,8 +1899,8 @@ return false; } -static bool DumpCommaSeparatedChildEntryNames( - Stream &s, const FormatEntity::Entry::Definition *parent) { +static bool DumpCommaSeparatedChildEntryNames(Stream &s, + const Definition *parent) { if (parent->children) { const size_t n = parent->num_children; for (size_t i = 0; i < n; ++i) { @@ -1906,8 +1914,7 @@ } static Status ParseEntry(const llvm::StringRef &format_str, - const FormatEntity::Entry::Definition *parent, - FormatEntity::Entry &entry) { + const Definition *parent, FormatEntity::Entry &entry) { Status error; const size_t sep_pos = format_str.find_first_of(".[:"); @@ -1917,7 +1924,7 @@ const size_t n = parent->num_children; for (size_t i = 0; i < n; ++i) { - const FormatEntity::Entry::Definition *entry_def = parent->children + i; + const Definition *entry_def = parent->children + i; if (key.equals(entry_def->name) || entry_def->name[0] == '*') { llvm::StringRef value; if (sep_char) @@ -1990,16 +1997,15 @@ return error; } -static const FormatEntity::Entry::Definition * -FindEntry(const llvm::StringRef &format_str, - const FormatEntity::Entry::Definition *parent, - llvm::StringRef &remainder) { +static const Definition *FindEntry(const llvm::StringRef &format_str, + const Definition *parent, + llvm::StringRef &remainder) { Status error; std::pair p = format_str.split('.'); const size_t n = parent->num_children; for (size_t i = 0; i < n; ++i) { - const FormatEntity::Entry::Definition *entry_def = parent->children + i; + const Definition *entry_def = parent->children + i; if (p.first.equals(entry_def->name) || entry_def->name[0] == '*') { if (p.second.empty()) { if (format_str.back() == '.') @@ -2363,8 +2369,7 @@ return match; } -static void AddMatches(const FormatEntity::Entry::Definition *def, - const llvm::StringRef &prefix, +static void AddMatches(const Definition *def, const llvm::StringRef &prefix, const llvm::StringRef &match_prefix, StringList &matches) { const size_t n = def->num_children; @@ -2418,8 +2423,7 @@ // We have a partially specified variable, find it llvm::StringRef remainder; - const FormatEntity::Entry::Definition *entry_def = - FindEntry(partial_variable, &g_root, remainder); + const Definition *entry_def = FindEntry(partial_variable, &g_root, remainder); if (!entry_def) return; diff --git a/lldb/unittests/Core/CMakeLists.txt b/lldb/unittests/Core/CMakeLists.txt --- a/lldb/unittests/Core/CMakeLists.txt +++ b/lldb/unittests/Core/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_unittest(LLDBCoreTests CommunicationTest.cpp + FormatEntityTest.cpp MangledTest.cpp ModuleSpecTest.cpp RichManglingContextTest.cpp diff --git a/lldb/unittests/Core/FormatEntityTest.cpp b/lldb/unittests/Core/FormatEntityTest.cpp new file mode 100644 --- /dev/null +++ b/lldb/unittests/Core/FormatEntityTest.cpp @@ -0,0 +1,159 @@ +//===-- FormatEntityTest.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/FormatEntity.h" +#include "lldb/Utility/Status.h" + +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" + +using namespace lldb_private; + +using Definition = FormatEntity::Entry::Definition; +using Entry = FormatEntity::Entry; + +TEST(FormatEntityTest, DefinitionConstructionNameAndType) { + Definition d("foo", FormatEntity::Entry::Type::Invalid); + + EXPECT_EQ(d.name, "foo"); + EXPECT_EQ(d.string, nullptr); + EXPECT_EQ(d.type, FormatEntity::Entry::Type::Invalid); + EXPECT_EQ(d.data, 0UL); + EXPECT_EQ(d.num_children, 0UL); + EXPECT_EQ(d.children, nullptr); + EXPECT_FALSE(d.keep_separator); +} + +TEST(FormatEntityTest, DefinitionConstructionNameAndString) { + Definition d("foo", "string"); + + EXPECT_EQ(d.name, "foo"); + EXPECT_EQ(d.string, "string"); + EXPECT_EQ(d.type, FormatEntity::Entry::Type::EscapeCode); + EXPECT_EQ(d.data, 0UL); + EXPECT_EQ(d.num_children, 0UL); + EXPECT_EQ(d.children, nullptr); + EXPECT_FALSE(d.keep_separator); +} + +TEST(FormatEntityTest, DefinitionConstructionNameTypeData) { + Definition d("foo", FormatEntity::Entry::Type::Invalid, 33); + + EXPECT_EQ(d.name, "foo"); + EXPECT_EQ(d.string, nullptr); + EXPECT_EQ(d.type, FormatEntity::Entry::Type::Invalid); + EXPECT_EQ(d.data, 33UL); + EXPECT_EQ(d.num_children, 0UL); + EXPECT_EQ(d.children, nullptr); + EXPECT_FALSE(d.keep_separator); +} + +TEST(FormatEntityTest, DefinitionConstructionNameTypeChildren) { + Definition d("foo", FormatEntity::Entry::Type::Invalid, 33); + Definition parent("parent", FormatEntity::Entry::Type::Invalid, 1, &d); + EXPECT_EQ(parent.name, "parent"); + EXPECT_EQ(parent.string, nullptr); + EXPECT_EQ(parent.type, FormatEntity::Entry::Type::Invalid); + EXPECT_EQ(parent.num_children, 1UL); + EXPECT_EQ(parent.children, &d); + EXPECT_FALSE(parent.keep_separator); + + EXPECT_EQ(parent.children[0].name, "foo"); + EXPECT_EQ(parent.children[0].string, nullptr); + EXPECT_EQ(parent.children[0].type, FormatEntity::Entry::Type::Invalid); + EXPECT_EQ(parent.children[0].data, 33UL); + EXPECT_EQ(parent.children[0].num_children, 0UL); + EXPECT_EQ(parent.children[0].children, nullptr); + EXPECT_FALSE(d.keep_separator); +} + +constexpr llvm::StringRef lookupStrings[] = { + "${addr.load}", + "${addr.file}", + "${ansi.fg.black}", + "${ansi.fg.red}", + "${ansi.fg.green}", + "${ansi.fg.yellow}", + "${ansi.fg.blue}", + "${ansi.fg.purple}", + "${ansi.fg.cyan}", + "${ansi.fg.white}", + "${ansi.bg.black}", + "${ansi.bg.red}", + "${ansi.bg.green}", + "${ansi.bg.yellow}", + "${ansi.bg.blue}", + "${ansi.bg.purple}", + "${ansi.bg.cyan}", + "${ansi.bg.white}", + "${file.basename}", + "${file.dirname}", + "${file.fullpath}", + "${frame.index}", + "${frame.pc}", + "${frame.fp}", + "${frame.sp}", + "${frame.flags}", + "${frame.no-debug}", + "${frame.reg.*}", + "${frame.is-artificial}", + "${function.id}", + "${function.name}", + "${function.name-without-args}", + "${function.name-with-args}", + "${function.mangled-name}", + "${function.addr-offset}", + "${function.concrete-only-addr-offset-no-padding}", + "${function.line-offset}", + "${function.pc-offset}", + "${function.initial-function}", + "${function.changed}", + "${function.is-optimized}", + "${line.file.basename}", + "${line.file.dirname}", + "${line.file.fullpath}", + "${line.number}", + "${line.column}", + "${line.start-addr}", + "${line.end-addr}", + "${module.file.basename}", + "${module.file.dirname}", + "${module.file.fullpath}", + "${process.id}", + "${process.name}", + "${process.file.basename}", + "${process.file.dirname}", + "${process.file.fullpath}", + "${script.frame}", + "${script.process}", + "${script.target}", + "${script.thread}", + "${script.var}", + "${script.svar}", + "${script.thread}", + "${svar.dummy-svar-to-test-wildcard}", + "${thread.id}", + "${thread.protocol_id}", + "${thread.index}", + "${thread.info.*}", + "${thread.queue}", + "${thread.name}", + "${thread.stop-reason}", + "${thread.stop-reason-raw}", + "${thread.return-value}", + "${thread.completed-expression}", + "${target.arch}", + "${var.dummy-var-to-test-wildcard}"}; + +TEST(FormatEntity, LookupAllEntriesInTree) { + for (const llvm::StringRef testString : lookupStrings) { + Entry e; + EXPECT_TRUE(FormatEntity::Parse(testString, e).Success()) + << "Formatting " << testString << " did not succeed"; + } +}