diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-12-09 13:28:42 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-12-09 13:28:42 +0000 |
| commit | b1c73532ee8997fe5dfbeb7d223027bdf99758a0 (patch) | |
| tree | 7d6e51c294ab6719475d660217aa0c0ad0526292 /lldb/source/Core | |
| parent | 7fa27ce4a07f19b07799a767fc29416f3b625afb (diff) | |
Diffstat (limited to 'lldb/source/Core')
25 files changed, 787 insertions, 270 deletions
diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp index 189d50fe962a..19d34db44ea5 100644 --- a/lldb/source/Core/Address.cpp +++ b/lldb/source/Core/Address.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Core/Address.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Declaration.h" #include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/Module.h" @@ -28,6 +29,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" @@ -405,7 +407,7 @@ bool Address::GetDescription(Stream &s, Target &target, bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style, uint32_t addr_size, - bool all_ranges) const { + bool all_ranges, llvm::StringRef pattern) const { // If the section was nullptr, only load address is going to work unless we // are trying to deref a pointer SectionSP section_sp(GetSection()); @@ -501,7 +503,6 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, pointer_size = target->GetArchitecture().GetAddressByteSize(); else if (module_sp) pointer_size = module_sp->GetArchitecture().GetAddressByteSize(); - bool showed_info = false; if (section_sp) { SectionType sect_type = section_sp->GetType(); @@ -515,7 +516,16 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, if (symbol) { const char *symbol_name = symbol->GetName().AsCString(); if (symbol_name) { - s->PutCString(symbol_name); + llvm::StringRef ansi_prefix; + llvm::StringRef ansi_suffix; + if (target) { + ansi_prefix = + target->GetDebugger().GetRegexMatchAnsiPrefix(); + ansi_suffix = + target->GetDebugger().GetRegexMatchAnsiSuffix(); + } + s->PutCStringColorHighlighted(symbol_name, pattern, + ansi_prefix, ansi_suffix); addr_t delta = file_Addr - symbol->GetAddressRef().GetFileAddress(); if (delta) @@ -643,7 +653,7 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, pointer_sc.symbol != nullptr) { s->PutCString(": "); pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, - false, true, true); + false, true, true, pattern); } } } @@ -682,19 +692,22 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, // address. sc.DumpStopContext(s, exe_scope, *this, show_fullpaths, show_module, show_inlined_frames, - show_function_arguments, show_function_name); + show_function_arguments, show_function_name, + pattern); } else { // We found a symbol but it was in a different section so it // isn't the symbol we should be showing, just show the section // name + offset - Dump(s, exe_scope, DumpStyleSectionNameOffset); + Dump(s, exe_scope, DumpStyleSectionNameOffset, DumpStyleInvalid, + UINT32_MAX, false, pattern); } } } } } else { if (fallback_style != DumpStyleInvalid) - return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); + return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size, + false, pattern); return false; } break; @@ -715,7 +728,7 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, sc.symbol->GetAddressRef().GetSection() != GetSection()) sc.symbol = nullptr; } - sc.GetDescription(s, eDescriptionLevelBrief, target); + sc.GetDescription(s, eDescriptionLevelBrief, target, pattern); if (sc.block) { bool can_create = true; @@ -763,7 +776,8 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, } } else { if (fallback_style != DumpStyleInvalid) - return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); + return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size, + false, pattern); return false; } break; diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 4287cb1fff02..8d81967bdb50 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -4,7 +4,7 @@ let Definition = "modulelist" in { def EnableExternalLookup: Property<"enable-external-lookup", "Boolean">, Global, DefaultTrue, - Desc<"Control the use of external tools and repositories to locate symbol files. Directories listed in target.debug-file-search-paths and directory of the executable are always checked first for separate debug info files. Then depending on this setting: On macOS, Spotlight would be also used to locate a matching .dSYM bundle based on the UUID of the executable. On NetBSD, directory /usr/libdata/debug would be also searched. On platforms other than NetBSD directory /usr/lib/debug would be also searched.">; + Desc<"Control the use of external tools and repositories to locate symbol files. Directories listed in target.debug-file-search-paths and directory of the executable are always checked first for separate debug info files. Then depending on this setting: On macOS, Spotlight would be also used to locate a matching .dSYM bundle based on the UUID of the executable. On NetBSD, directory /usr/libdata/debug would be also searched. On platforms other than NetBSD directory /usr/lib/debug would be also searched. If all other methods fail there may be symbol-locator plugins that, if configured properly, will also attempt to acquire symbols. The debuginfod plugin defaults to the DEGUFINFOD_URLS environment variable which is configurable through the 'plugin.symbol-locator.debuginfod.server_urls' setting.">; def EnableBackgroundLookup: Property<"enable-background-lookup", "Boolean">, Global, DefaultFalse, @@ -65,6 +65,14 @@ let Definition = "debugger" in { DefaultEnumValue<"OptionValueString::eOptionEncodeCharacterEscapeSequences">, DefaultStringValue<"(lldb) ">, Desc<"The debugger command line prompt displayed for the user.">; + def PromptAnsiPrefix: Property<"prompt-ansi-prefix", "String">, + Global, + DefaultStringValue<"${ansi.faint}">, + Desc<"When in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the prompt.">; + def PromptAnsiSuffix: Property<"prompt-ansi-suffix", "String">, + Global, + DefaultStringValue<"${ansi.normal}">, + Desc<"When in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the prompt.">; def ScriptLanguage: Property<"script-lang", "Enum">, Global, DefaultEnumValue<"eScriptLanguagePython">, @@ -173,8 +181,8 @@ let Definition = "debugger" in { Desc<"If true, LLDB will print the values of variables declared in an expression. Currently only supported in the REPL (default: true).">; def TabSize: Property<"tab-size", "UInt64">, Global, - DefaultUnsignedValue<4>, - Desc<"The tab size to use when indenting code in multi-line input mode (default: 4).">; + DefaultUnsignedValue<2>, + Desc<"The tab size to use when indenting code in multi-line input mode (default: 2).">; def EscapeNonPrintables: Property<"escape-non-printables", "Boolean">, Global, DefaultTrue, @@ -195,6 +203,18 @@ let Definition = "debugger" in { Global, DefaultStringValue<"${ansi.normal}">, Desc<"When displaying suggestion in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the suggestion.">; + def ShowRegexMatchAnsiPrefix: Property<"show-regex-match-ansi-prefix", "String">, + Global, + DefaultStringValue<"${ansi.fg.red}">, + Desc<"When displaying a regex match in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the match.">; + def ShowRegexMatchAnsiSuffix: Property<"show-regex-match-ansi-suffix", "String">, + Global, + DefaultStringValue<"${ansi.normal}">, + Desc<"When displaying a regex match in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the match.">; + def ShowDontUsePoHint: Property<"show-dont-use-po-hint", "Boolean">, + Global, + DefaultTrue, + Desc<"If true, and object description was requested for a type that does not implement it, LLDB will print a hint telling the user to consider using p instead.">; def DWIMPrintVerbosity: Property<"dwim-print-verbosity", "Enum">, Global, DefaultEnumValue<"eDWIMPrintVerbosityNone">, diff --git a/lldb/source/Core/DataFileCache.cpp b/lldb/source/Core/DataFileCache.cpp index b29327db5ca3..a8127efc1df0 100644 --- a/lldb/source/Core/DataFileCache.cpp +++ b/lldb/source/Core/DataFileCache.cpp @@ -285,7 +285,7 @@ bool ConstStringTable::Encode(DataEncoder &encoder) { size_t length_offset = encoder.GetByteSize(); encoder.AppendU32(0); // Total length of all strings which will be fixed up. size_t strtab_offset = encoder.GetByteSize(); - encoder.AppendU8(0); // Start the string table with with an empty string. + encoder.AppendU8(0); // Start the string table with an empty string. for (auto s: m_strings) { // Make sure all of the offsets match up with what we handed out! assert(m_string_to_offset.find(s)->second == diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index f54108629185..97311b4716ac 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -16,12 +16,12 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamAsynchronousIO.h" -#include "lldb/Core/StreamFile.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Expression/REPL.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Host/Terminal.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -236,6 +236,13 @@ Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx, // codes. SetPrompt(GetPrompt()); } else if (property_path == + g_debugger_properties[ePropertyPromptAnsiPrefix].name || + property_path == + g_debugger_properties[ePropertyPromptAnsiSuffix].name) { + // Prompt colors changed. Ping the prompt so it can reset the ansi + // terminal codes. + SetPrompt(GetPrompt()); + } else if (property_path == g_debugger_properties[ePropertyUseSourceCache].name) { // use-source-cache changed. Wipe out the cache contents if it was // disabled. @@ -301,6 +308,18 @@ llvm::StringRef Debugger::GetPrompt() const { idx, g_debugger_properties[idx].default_cstr_value); } +llvm::StringRef Debugger::GetPromptAnsiPrefix() const { + const uint32_t idx = ePropertyPromptAnsiPrefix; + return GetPropertyAtIndexAs<llvm::StringRef>( + idx, g_debugger_properties[idx].default_cstr_value); +} + +llvm::StringRef Debugger::GetPromptAnsiSuffix() const { + const uint32_t idx = ePropertyPromptAnsiSuffix; + return GetPropertyAtIndexAs<llvm::StringRef>( + idx, g_debugger_properties[idx].default_cstr_value); +} + void Debugger::SetPrompt(llvm::StringRef p) { constexpr uint32_t idx = ePropertyPrompt; SetPropertyAtIndex(idx, p); @@ -434,6 +453,24 @@ llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const { idx, g_debugger_properties[idx].default_cstr_value); } +llvm::StringRef Debugger::GetRegexMatchAnsiPrefix() const { + const uint32_t idx = ePropertyShowRegexMatchAnsiPrefix; + return GetPropertyAtIndexAs<llvm::StringRef>( + idx, g_debugger_properties[idx].default_cstr_value); +} + +llvm::StringRef Debugger::GetRegexMatchAnsiSuffix() const { + const uint32_t idx = ePropertyShowRegexMatchAnsiSuffix; + return GetPropertyAtIndexAs<llvm::StringRef>( + idx, g_debugger_properties[idx].default_cstr_value); +} + +bool Debugger::GetShowDontUsePoHint() const { + const uint32_t idx = ePropertyShowDontUsePoHint; + return GetPropertyAtIndexAs<bool>( + idx, g_debugger_properties[idx].default_uint_value != 0); +} + bool Debugger::GetUseSourceCache() const { const uint32_t idx = ePropertyUseSourceCache; return GetPropertyAtIndexAs<bool>( @@ -905,7 +942,7 @@ void Debugger::Clear() { for (TargetSP target_sp : m_target_list.Targets()) { if (target_sp) { if (ProcessSP process_sp = target_sp->GetProcessSP()) - process_sp->Finalize(); + process_sp->Finalize(false /* not destructing */); target_sp->Destroy(); } } @@ -923,15 +960,6 @@ void Debugger::Clear() { }); } -bool Debugger::GetCloseInputOnEOF() const { - // return m_input_comm.GetCloseOnEOF(); - return false; -} - -void Debugger::SetCloseInputOnEOF(bool b) { - // m_input_comm.SetCloseOnEOF(b); -} - bool Debugger::GetAsyncExecution() { return !m_command_interpreter_up->GetSynchronous(); } @@ -1275,17 +1303,17 @@ bool Debugger::InterruptRequested() { return GetCommandInterpreter().WasInterrupted(); } -Debugger::InterruptionReport::InterruptionReport(std::string function_name, - const llvm::formatv_object_base &payload) : - m_function_name(std::move(function_name)), - m_interrupt_time(std::chrono::system_clock::now()), - m_thread_id(llvm::get_threadid()) { +Debugger::InterruptionReport::InterruptionReport( + std::string function_name, const llvm::formatv_object_base &payload) + : m_function_name(std::move(function_name)), + m_interrupt_time(std::chrono::system_clock::now()), + m_thread_id(llvm::get_threadid()) { llvm::raw_string_ostream desc(m_description); desc << payload << "\n"; } void Debugger::ReportInterruption(const InterruptionReport &report) { - // For now, just log the description: + // For now, just log the description: Log *log = GetLog(LLDBLog::Host); LLDB_LOG(log, "Interruption: {0}", report.m_description); } diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp index 104e9100e388..166b5fdf22f0 100644 --- a/lldb/source/Core/Disassembler.cpp +++ b/lldb/source/Core/Disassembler.cpp @@ -645,18 +645,29 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size, instruction_control_flow_kind)); } + bool show_color = false; + if (exe_ctx) { + if (TargetSP target_sp = exe_ctx->GetTargetSP()) { + show_color = target_sp->GetDebugger().GetUseColor(); + } + } const size_t opcode_pos = ss.GetSizeOfLastLine(); + const std::string &opcode_name = + show_color ? m_markup_opcode_name : m_opcode_name; + const std::string &mnemonics = show_color ? m_markup_mnemonics : m_mnemonics; // The default opcode size of 7 characters is plenty for most architectures // but some like arm can pull out the occasional vqrshrun.s16. We won't get - // consistent column spacing in these cases, unfortunately. + // consistent column spacing in these cases, unfortunately. Also note that we + // need to directly use m_opcode_name here (instead of opcode_name) so we + // don't include color codes as characters. if (m_opcode_name.length() >= opcode_column_width) { opcode_column_width = m_opcode_name.length() + 1; } - ss.PutCString(m_opcode_name); + ss.PutCString(opcode_name); ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' '); - ss.PutCString(m_mnemonics); + ss.PutCString(mnemonics); if (!m_comment.empty()) { ss.FillLastLineToColumn( diff --git a/lldb/source/Core/DumpDataExtractor.cpp b/lldb/source/Core/DumpDataExtractor.cpp index cb76b118325b..986c9a181919 100644 --- a/lldb/source/Core/DumpDataExtractor.cpp +++ b/lldb/source/Core/DumpDataExtractor.cpp @@ -620,10 +620,17 @@ lldb::offset_t lldb_private::DumpDataExtractor( case 2: case 4: case 8: - s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64, - (int)(2 * item_byte_size), (int)(2 * item_byte_size), - DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, - item_bit_offset)); + if (Target::GetGlobalProperties() + .ShowHexVariableValuesWithLeadingZeroes()) { + s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64, + (int)(2 * item_byte_size), (int)(2 * item_byte_size), + DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, + item_bit_offset)); + } else { + s->Printf(wantsuppercase ? "0x%" PRIX64 : "0x%" PRIx64, + DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, + item_bit_offset)); + } break; default: { assert(item_bit_size == 0 && item_bit_offset == 0); diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp index 2e5378f654a5..7871be6fc451 100644 --- a/lldb/source/Core/DynamicLoader.cpp +++ b/lldb/source/Core/DynamicLoader.cpp @@ -8,12 +8,12 @@ #include "lldb/Target/DynamicLoader.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Platform.h" @@ -188,7 +188,7 @@ static ModuleSP ReadUnnamedMemoryModule(Process *process, addr_t addr, ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( Process *process, llvm::StringRef name, UUID uuid, addr_t value, bool value_is_offset, bool force_symbol_search, bool notify, - bool set_address_in_target) { + bool set_address_in_target, bool allow_memory_image_last_resort) { ModuleSP memory_module_sp; ModuleSP module_sp; PlatformSP platform_sp = process->GetTarget().GetPlatform(); @@ -218,9 +218,9 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( if (!module_sp) { FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); module_spec.GetSymbolFileSpec() = - Symbols::LocateExecutableSymbolFile(module_spec, search_paths); + PluginManager::LocateExecutableSymbolFile(module_spec, search_paths); ModuleSpec objfile_module_spec = - Symbols::LocateExecutableObjectFile(module_spec); + PluginManager::LocateExecutableObjectFile(module_spec); module_spec.GetFileSpec() = objfile_module_spec.GetFileSpec(); if (FileSystem::Instance().Exists(module_spec.GetFileSpec()) && FileSystem::Instance().Exists(module_spec.GetSymbolFileSpec())) { @@ -231,10 +231,13 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( // If we haven't found a binary, or we don't have a SymbolFile, see // if there is an external search tool that can find it. if (!module_sp || !module_sp->GetSymbolFileFileSpec()) { - Symbols::DownloadObjectAndSymbolFile(module_spec, error, - force_symbol_search); + PluginManager::DownloadObjectAndSymbolFile(module_spec, error, + force_symbol_search); if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { module_sp = std::make_shared<Module>(module_spec); + } else if (force_symbol_search && error.AsCString("") && + error.AsCString("")[0] != '\0') { + target.GetDebugger().GetErrorStream() << error.AsCString(); } } @@ -245,7 +248,8 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( // If we couldn't find the binary anywhere else, as a last resort, // read it out of memory. - if (!module_sp.get() && value != LLDB_INVALID_ADDRESS && !value_is_offset) { + if (allow_memory_image_last_resort && !module_sp.get() && + value != LLDB_INVALID_ADDRESS && !value_is_offset) { if (!memory_module_sp) memory_module_sp = ReadUnnamedMemoryModule(process, value, name); if (memory_module_sp) @@ -266,8 +270,8 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( if (value != LLDB_INVALID_ADDRESS) { LLDB_LOGF(log, "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading " - "binary UUID %s at %s 0x%" PRIx64, - uuid.GetAsString().c_str(), + "binary %s UUID %s at %s 0x%" PRIx64, + name.str().c_str(), uuid.GetAsString().c_str(), value_is_offset ? "offset" : "address", value); module_sp->SetLoadAddress(target, value, value_is_offset, changed); } else { @@ -275,8 +279,8 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( // offset 0. LLDB_LOGF(log, "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading " - "binary UUID %s at file address", - uuid.GetAsString().c_str()); + "binary %s UUID %s at file address", + name.str().c_str(), uuid.GetAsString().c_str()); module_sp->SetLoadAddress(target, 0, true /* value_is_slide */, changed); } @@ -284,8 +288,8 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( // In-memory image, load at its true address, offset 0. LLDB_LOGF(log, "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading binary " - "UUID %s from memory at address 0x%" PRIx64, - uuid.GetAsString().c_str(), value); + "%s UUID %s from memory at address 0x%" PRIx64, + name.str().c_str(), uuid.GetAsString().c_str(), value); module_sp->SetLoadAddress(target, 0, true /* value_is_slide */, changed); } @@ -297,10 +301,26 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( target.ModulesDidLoad(added_module); } } else { - LLDB_LOGF(log, "Unable to find binary with UUID %s and load it at " - "%s 0x%" PRIx64, - uuid.GetAsString().c_str(), - value_is_offset ? "offset" : "address", value); + if (force_symbol_search) { + Stream &s = target.GetDebugger().GetErrorStream(); + s.Printf("Unable to find file"); + if (!name.empty()) + s.Printf(" %s", name.str().c_str()); + if (uuid.IsValid()) + s.Printf(" with UUID %s", uuid.GetAsString().c_str()); + if (value != LLDB_INVALID_ADDRESS) { + if (value_is_offset) + s.Printf(" with slide 0x%" PRIx64, value); + else + s.Printf(" at address 0x%" PRIx64, value); + } + s.Printf("\n"); + } + LLDB_LOGF(log, + "Unable to find binary %s with UUID %s and load it at " + "%s 0x%" PRIx64, + name.str().c_str(), uuid.GetAsString().c_str(), + value_is_offset ? "offset" : "address", value); } return module_sp; diff --git a/lldb/source/Core/EmulateInstruction.cpp b/lldb/source/Core/EmulateInstruction.cpp index 753bee25de6d..d240b4d3b331 100644 --- a/lldb/source/Core/EmulateInstruction.cpp +++ b/lldb/source/Core/EmulateInstruction.cpp @@ -11,7 +11,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/DumpRegisterValue.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp index 00ab20243855..94986457552d 100644 --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -286,13 +286,6 @@ void FormatEntity::Entry::AppendText(const char *cstr) { return AppendText(llvm::StringRef(cstr)); } -Status FormatEntity::Parse(const llvm::StringRef &format_str, Entry &entry) { - entry.Clear(); - entry.type = Entry::Type::Root; - llvm::StringRef modifiable_format(format_str); - return ParseInternal(modifiable_format, entry, 0); -} - #define ENUM_TO_CSTR(eee) \ case FormatEntity::Entry::Type::eee: \ return #eee @@ -1252,9 +1245,10 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, 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)) { + if (ostype == llvm::Triple::FreeBSD || + ostype == llvm::Triple::Linux || + ostype == llvm::Triple::NetBSD || + ostype == llvm::Triple::OpenBSD) { format = "%" PRIu64; } } else { @@ -1991,8 +1985,8 @@ static const Definition *FindEntry(const llvm::StringRef &format_str, return parent; } -Status FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry, - uint32_t depth) { +static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry, + uint32_t depth) { Status error; while (!format.empty() && error.Success()) { const size_t non_special_chars = format.find_first_of("${}\\"); @@ -2017,7 +2011,7 @@ Status FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry, case '{': { format = format.drop_front(); // Skip the '{' Entry scope_entry(Entry::Type::Scope); - error = FormatEntity::ParseInternal(format, scope_entry, depth + 1); + error = ParseInternal(format, scope_entry, depth + 1); if (error.Fail()) return error; parent_entry.AppendEntry(std::move(scope_entry)); @@ -2467,3 +2461,10 @@ void FormatEntity::PrettyPrintFunctionArguments( out_stream.Printf("%s=<unavailable>", var_name); } } + +Status FormatEntity::Parse(const llvm::StringRef &format_str, Entry &entry) { + entry.Clear(); + entry.type = Entry::Type::Root; + llvm::StringRef modifiable_format(format_str); + return ParseInternal(modifiable_format, entry, 0); +} diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index 49f39f2ce492..695c2481e353 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -14,9 +14,9 @@ #include <string> #include "lldb/Core/Debugger.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Host/Config.h" #include "lldb/Host/File.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/Predicate.h" #include "lldb/Utility/Status.h" @@ -226,7 +226,7 @@ IOHandlerEditline::IOHandlerEditline( Debugger &debugger, IOHandler::Type type, const char *editline_name, // Used for saving history files llvm::StringRef prompt, llvm::StringRef continuation_prompt, - bool multi_line, bool color_prompts, uint32_t line_number_start, + bool multi_line, bool color, uint32_t line_number_start, IOHandlerDelegate &delegate) : IOHandlerEditline(debugger, type, FileSP(), // Inherit input from top input reader @@ -234,7 +234,7 @@ IOHandlerEditline::IOHandlerEditline( StreamFileSP(), // Inherit error from top input reader 0, // Flags editline_name, // Used for saving history files - prompt, continuation_prompt, multi_line, color_prompts, + prompt, continuation_prompt, multi_line, color, line_number_start, delegate) {} IOHandlerEditline::IOHandlerEditline( @@ -243,7 +243,7 @@ IOHandlerEditline::IOHandlerEditline( uint32_t flags, const char *editline_name, // Used for saving history files llvm::StringRef prompt, llvm::StringRef continuation_prompt, - bool multi_line, bool color_prompts, uint32_t line_number_start, + bool multi_line, bool color, uint32_t line_number_start, IOHandlerDelegate &delegate) : IOHandler(debugger, type, input_sp, output_sp, error_sp, flags), #if LLDB_ENABLE_LIBEDIT @@ -251,8 +251,8 @@ IOHandlerEditline::IOHandlerEditline( #endif m_delegate(delegate), m_prompt(), m_continuation_prompt(), m_current_lines_ptr(nullptr), m_base_line_number(line_number_start), - m_curr_line_idx(UINT32_MAX), m_multi_line(multi_line), - m_color_prompts(color_prompts), m_interrupt_exits(true) { + m_curr_line_idx(UINT32_MAX), m_multi_line(multi_line), m_color(color), + m_interrupt_exits(true) { SetPrompt(prompt); #if LLDB_ENABLE_LIBEDIT @@ -262,9 +262,9 @@ IOHandlerEditline::IOHandlerEditline( m_input_sp && m_input_sp->GetIsRealTerminal(); if (use_editline) { - m_editline_up = std::make_unique<Editline>( - editline_name, GetInputFILE(), GetOutputFILE(), GetErrorFILE(), - GetOutputMutex(), m_color_prompts); + m_editline_up = std::make_unique<Editline>(editline_name, GetInputFILE(), + GetOutputFILE(), GetErrorFILE(), + GetOutputMutex()); m_editline_up->SetIsInputCompleteCallback( [this](Editline *editline, StringList &lines) { return this->IsInputCompleteCallback(editline, lines); @@ -278,10 +278,12 @@ IOHandlerEditline::IOHandlerEditline( m_editline_up->SetSuggestionCallback([this](llvm::StringRef line) { return this->SuggestionCallback(line); }); - m_editline_up->SetSuggestionAnsiPrefix(ansi::FormatAnsiTerminalCodes( - debugger.GetAutosuggestionAnsiPrefix())); - m_editline_up->SetSuggestionAnsiSuffix(ansi::FormatAnsiTerminalCodes( - debugger.GetAutosuggestionAnsiSuffix())); + if (m_color) { + m_editline_up->SetSuggestionAnsiPrefix(ansi::FormatAnsiTerminalCodes( + debugger.GetAutosuggestionAnsiPrefix())); + m_editline_up->SetSuggestionAnsiSuffix(ansi::FormatAnsiTerminalCodes( + debugger.GetAutosuggestionAnsiSuffix())); + } } // See if the delegate supports fixing indentation const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters(); @@ -474,8 +476,15 @@ bool IOHandlerEditline::SetPrompt(llvm::StringRef prompt) { m_prompt = std::string(prompt); #if LLDB_ENABLE_LIBEDIT - if (m_editline_up) + if (m_editline_up) { m_editline_up->SetPrompt(m_prompt.empty() ? nullptr : m_prompt.c_str()); + if (m_color) { + m_editline_up->SetPromptAnsiPrefix( + ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiPrefix())); + m_editline_up->SetPromptAnsiSuffix( + ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiSuffix())); + } + } #endif return true; } @@ -508,6 +517,21 @@ uint32_t IOHandlerEditline::GetCurrentLineIndex() const { return m_curr_line_idx; } +StringList IOHandlerEditline::GetCurrentLines() const { +#if LLDB_ENABLE_LIBEDIT + if (m_editline_up) + return m_editline_up->GetInputAsStringList(); +#endif + // When libedit is not used, the current lines can be gotten from + // `m_current_lines_ptr`, which is updated whenever a new line is processed. + // This doesn't happen when libedit is used, in which case + // `m_current_lines_ptr` is only updated when the full input is terminated. + + if (m_current_lines_ptr) + return *m_current_lines_ptr; + return StringList(); +} + bool IOHandlerEditline::GetLines(StringList &lines, bool &interrupted) { m_current_lines_ptr = &lines; diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp index 79d3da63059c..abf0b6b801f3 100644 --- a/lldb/source/Core/IOHandlerCursesGUI.cpp +++ b/lldb/source/Core/IOHandlerCursesGUI.cpp @@ -25,7 +25,6 @@ #include <string> #include "lldb/Core/Debugger.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/ValueObjectUpdater.h" #include "lldb/Host/File.h" #include "lldb/Utility/AnsiTerminal.h" @@ -3179,13 +3178,13 @@ public: m_debugger.GetListener(), llvm::StringRef(), &core_file_spec, false)); if (!process_sp) { - SetError("Unable to find process plug-in for core file!"); + SetError("Unknown core file format!"); return; } Status status = process_sp->LoadCore(); if (status.Fail()) { - SetError("Can't find plug-in for core file!"); + SetError("Unknown core file format!"); return; } } @@ -4615,30 +4614,48 @@ public: typedef std::shared_ptr<TreeDelegate> TreeDelegateSP; -class TreeItem { +struct TreeItemData { + TreeItemData(TreeItem *parent, TreeDelegate &delegate, + bool might_have_children, bool is_expanded) + : m_parent(parent), m_delegate(&delegate), + m_might_have_children(might_have_children), m_is_expanded(is_expanded) { + } + +protected: + TreeItem *m_parent; + TreeDelegate *m_delegate; + void *m_user_data = nullptr; + uint64_t m_identifier = 0; + std::string m_text; + int m_row_idx = -1; // Zero based visible row index, -1 if not visible or for + // the root item + bool m_might_have_children; + bool m_is_expanded = false; +}; + +class TreeItem : public TreeItemData { public: TreeItem(TreeItem *parent, TreeDelegate &delegate, bool might_have_children) - : m_parent(parent), m_delegate(delegate), m_children(), - m_might_have_children(might_have_children) { - if (m_parent == nullptr) - m_is_expanded = m_delegate.TreeDelegateExpandRootByDefault(); - } + : TreeItemData(parent, delegate, might_have_children, + parent == nullptr + ? delegate.TreeDelegateExpandRootByDefault() + : false), + m_children() {} + + TreeItem(const TreeItem &) = delete; + TreeItem &operator=(const TreeItem &rhs) = delete; - TreeItem &operator=(const TreeItem &rhs) { + TreeItem &operator=(TreeItem &&rhs) { if (this != &rhs) { - m_parent = rhs.m_parent; - m_delegate = rhs.m_delegate; - m_user_data = rhs.m_user_data; - m_identifier = rhs.m_identifier; - m_row_idx = rhs.m_row_idx; - m_children = rhs.m_children; - m_might_have_children = rhs.m_might_have_children; - m_is_expanded = rhs.m_is_expanded; + TreeItemData::operator=(std::move(rhs)); + AdoptChildren(rhs.m_children); } return *this; } - TreeItem(const TreeItem &) = default; + TreeItem(TreeItem &&rhs) : TreeItemData(std::move(rhs)) { + AdoptChildren(rhs.m_children); + } size_t GetDepth() const { if (m_parent) @@ -4650,18 +4667,28 @@ public: void ClearChildren() { m_children.clear(); } - void Resize(size_t n, const TreeItem &t) { m_children.resize(n, t); } + void Resize(size_t n, TreeDelegate &delegate, bool might_have_children) { + if (m_children.size() >= n) { + m_children.erase(m_children.begin() + n, m_children.end()); + return; + } + m_children.reserve(n); + std::generate_n(std::back_inserter(m_children), n - m_children.size(), + [&, parent = this]() { + return TreeItem(parent, delegate, might_have_children); + }); + } TreeItem &operator[](size_t i) { return m_children[i]; } void SetRowIndex(int row_idx) { m_row_idx = row_idx; } size_t GetNumChildren() { - m_delegate.TreeDelegateGenerateChildren(*this); + m_delegate->TreeDelegateGenerateChildren(*this); return m_children.size(); } - void ItemWasSelected() { m_delegate.TreeDelegateItemSelected(*this); } + void ItemWasSelected() { m_delegate->TreeDelegateItemSelected(*this); } void CalculateRowIndexes(int &row_idx) { SetRowIndex(row_idx); @@ -4728,7 +4755,7 @@ public: if (highlight) window.AttributeOn(A_REVERSE); - m_delegate.TreeDelegateDrawTreeItem(*this, window); + m_delegate->TreeDelegateDrawTreeItem(*this, window); if (highlight) window.AttributeOff(A_REVERSE); @@ -4812,16 +4839,13 @@ public: void SetMightHaveChildren(bool b) { m_might_have_children = b; } protected: - TreeItem *m_parent; - TreeDelegate &m_delegate; - void *m_user_data = nullptr; - uint64_t m_identifier = 0; - std::string m_text; - int m_row_idx = -1; // Zero based visible row index, -1 if not visible or for - // the root item + void AdoptChildren(std::vector<TreeItem> &children) { + m_children = std::move(children); + for (auto &child : m_children) + child.m_parent = this; + } + std::vector<TreeItem> m_children; - bool m_might_have_children; - bool m_is_expanded = false; }; class TreeWindowDelegate : public WindowDelegate { @@ -5118,9 +5142,8 @@ public: m_stop_id = process_sp->GetStopID(); m_tid = thread_sp->GetID(); - TreeItem t(&item, *m_frame_delegate_sp, false); size_t num_frames = thread_sp->GetStackFrameCount(); - item.Resize(num_frames, t); + item.Resize(num_frames, *m_frame_delegate_sp, false); for (size_t i = 0; i < num_frames; ++i) { item[i].SetUserData(thread_sp.get()); item[i].SetIdentifier(i); @@ -5220,12 +5243,11 @@ public: std::make_shared<ThreadTreeDelegate>(m_debugger); } - TreeItem t(&item, *m_thread_delegate_sp, false); ThreadList &threads = process_sp->GetThreadList(); std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); ThreadSP selected_thread = threads.GetSelectedThread(); size_t num_threads = threads.GetSize(); - item.Resize(num_threads, t); + item.Resize(num_threads, *m_thread_delegate_sp, false); for (size_t i = 0; i < num_threads; ++i) { ThreadSP thread = threads.GetThreadAtIndex(i); item[i].SetIdentifier(thread->GetID()); @@ -5405,9 +5427,8 @@ public: if (!m_string_delegate_sp) m_string_delegate_sp = std::make_shared<TextTreeDelegate>(); - TreeItem details_tree_item(&item, *m_string_delegate_sp, false); - item.Resize(details.GetSize(), details_tree_item); + item.Resize(details.GetSize(), *m_string_delegate_sp, false); for (size_t i = 0; i < details.GetSize(); i++) { item[i].SetText(details.GetStringAtIndex(i)); } @@ -5449,10 +5470,9 @@ public: if (!m_breakpoint_location_delegate_sp) m_breakpoint_location_delegate_sp = std::make_shared<BreakpointLocationTreeDelegate>(m_debugger); - TreeItem breakpoint_location_tree_item( - &item, *m_breakpoint_location_delegate_sp, true); - item.Resize(breakpoint->GetNumLocations(), breakpoint_location_tree_item); + item.Resize(breakpoint->GetNumLocations(), + *m_breakpoint_location_delegate_sp, true); for (size_t i = 0; i < breakpoint->GetNumLocations(); i++) { item[i].SetIdentifier(i); item[i].SetUserData(breakpoint.get()); @@ -5496,9 +5516,8 @@ public: if (!m_breakpoint_delegate_sp) m_breakpoint_delegate_sp = std::make_shared<BreakpointTreeDelegate>(m_debugger); - TreeItem breakpoint_tree_item(&item, *m_breakpoint_delegate_sp, true); - item.Resize(breakpoints.GetSize(), breakpoint_tree_item); + item.Resize(breakpoints.GetSize(), *m_breakpoint_delegate_sp, true); for (size_t i = 0; i < breakpoints.GetSize(); i++) { item[i].SetIdentifier(i); } diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index d1973a9a8f7f..4587119519e9 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -58,6 +58,24 @@ Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef const name) { if (name.startswith("___Z")) return Mangled::eManglingSchemeItanium; + // Swift's older style of mangling used "_T" as a mangling prefix. This can + // lead to false positives with other symbols that just so happen to start + // with "_T". To minimize the chance of that happening, we only return true + // for select old-style swift mangled names. The known cases are ObjC classes + // and protocols. Classes are either prefixed with "_TtC" or "_TtGC". + // Protocols are prefixed with "_TtP". + if (name.startswith("_TtC") || name.startswith("_TtGC") || + name.startswith("_TtP")) + return Mangled::eManglingSchemeSwift; + + // Swift 4.2 used "$S" and "_$S". + // Swift 5 and onward uses "$s" and "_$s". + // Swift also uses "@__swiftmacro_" as a prefix for mangling filenames. + if (name.startswith("$S") || name.startswith("_$S") || + name.startswith("$s") || name.startswith("_$s") || + name.startswith("@__swiftmacro_")) + return Mangled::eManglingSchemeSwift; + return Mangled::eManglingSchemeNone; } @@ -228,6 +246,7 @@ bool Mangled::GetRichManglingInfo(RichManglingContext &context, case eManglingSchemeRustV0: case eManglingSchemeD: + case eManglingSchemeSwift: // Rich demangling scheme is not supported return false; } @@ -265,6 +284,10 @@ ConstString Mangled::GetDemangledName() const { case eManglingSchemeD: demangled_name = GetDLangDemangledStr(m_mangled); break; + case eManglingSchemeSwift: + // Demangling a swift name requires the swift compiler. This is + // explicitly unsupported on llvm.org. + break; case eManglingSchemeNone: llvm_unreachable("eManglingSchemeNone was handled already"); } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 672d86496bde..e6279a0feda8 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -23,11 +23,11 @@ #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" -#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolLocator.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Symtab.h" #include "lldb/Symbol/Type.h" @@ -233,12 +233,12 @@ Module::Module(const ModuleSpec &module_spec) } Module::Module(const FileSpec &file_spec, const ArchSpec &arch, - const ConstString *object_name, lldb::offset_t object_offset, + ConstString object_name, lldb::offset_t object_offset, const llvm::sys::TimePoint<> &object_mod_time) : m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)), - m_arch(arch), m_file(file_spec), m_object_offset(object_offset), - m_object_mod_time(object_mod_time), m_file_has_changed(false), - m_first_file_changed_log(false) { + m_arch(arch), m_file(file_spec), m_object_name(object_name), + m_object_offset(object_offset), m_object_mod_time(object_mod_time), + m_file_has_changed(false), m_first_file_changed_log(false) { // Scope for locker below... { std::lock_guard<std::recursive_mutex> guard( @@ -246,9 +246,6 @@ Module::Module(const FileSpec &file_spec, const ArchSpec &arch, GetModuleCollection().push_back(this); } - if (object_name) - m_object_name = *object_name; - Log *log(GetLog(LLDBLog::Object | LLDBLog::Modules)); if (log != nullptr) LLDB_LOGF(log, "%p Module::Module((%s) '%s%s%s%s')", @@ -1285,7 +1282,8 @@ ObjectFile *Module::GetObjectFile() { // those values that overwrite unspecified unknown values. m_arch.MergeFrom(m_objfile_sp->GetArchitecture()); } else { - ReportError("failed to load objfile for {0}", + ReportError("failed to load objfile for {0}\nDebugging will be " + "degraded for this module.", GetFileSpec().GetPath().c_str()); } } @@ -1316,7 +1314,7 @@ UnwindTable &Module::GetUnwindTable() { if (!m_unwind_table) { m_unwind_table.emplace(*this); if (!m_symfile_spec) - Symbols::DownloadSymbolFileAsync(GetUUID()); + SymbolLocator::DownloadSymbolFileAsync(GetUUID()); } return *m_unwind_table; } diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index d0d0b2050e18..04a9df7dd63b 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -9,12 +9,12 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Host/FileSystem.h" #include "lldb/Interpreter/OptionValueFileSpec.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Property.h" -#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/TypeList.h" @@ -75,8 +75,7 @@ enum { } // namespace ModuleListProperties::ModuleListProperties() { - m_collection_sp = - std::make_shared<OptionValueProperties>(ConstString("symbols")); + m_collection_sp = std::make_shared<OptionValueProperties>("symbols"); m_collection_sp->Initialize(g_modulelist_properties); m_collection_sp->SetValueChangedCallback(ePropertySymLinkPaths, [this] { UpdateSymlinkMappings(); }); @@ -348,7 +347,7 @@ size_t ModuleList::RemoveOrphans(bool mandatory) { } size_t remove_count = 0; // Modules might hold shared pointers to other modules, so removing one - // module might make other other modules orphans. Keep removing modules until + // module might make other modules orphans. Keep removing modules until // there are no further modules that can be removed. bool made_progress = true; while (made_progress) { @@ -907,7 +906,7 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp, // Fixup the incoming path in case the path points to a valid file, yet the // arch or UUID (if one was passed in) don't match. ModuleSpec located_binary_modulespec = - Symbols::LocateExecutableObjectFile(module_spec); + PluginManager::LocateExecutableObjectFile(module_spec); // Don't look for the file if it appears to be the same one we already // checked for above... @@ -1079,3 +1078,11 @@ bool ModuleList::AnyOf( return false; } + + +void ModuleList::Swap(ModuleList &other) { + // scoped_lock locks both mutexes at once. + std::scoped_lock<std::recursive_mutex, std::recursive_mutex> lock( + m_modules_mutex, other.m_modules_mutex); + m_modules.swap(other.m_modules); +} diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index ac274112e53d..dea380e47f4e 100644 --- a/lldb/source/Core/PluginManager.cpp +++ b/lldb/source/Core/PluginManager.cpp @@ -1081,6 +1081,119 @@ PluginManager::GetSymbolVendorCreateCallbackAtIndex(uint32_t idx) { return GetSymbolVendorInstances().GetCallbackAtIndex(idx); } +#pragma mark SymbolLocator + +struct SymbolLocatorInstance + : public PluginInstance<SymbolLocatorCreateInstance> { + SymbolLocatorInstance( + llvm::StringRef name, llvm::StringRef description, + CallbackType create_callback, + SymbolLocatorLocateExecutableObjectFile locate_executable_object_file, + SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file, + SymbolLocatorDownloadObjectAndSymbolFile download_object_symbol_file, + SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle, + DebuggerInitializeCallback debugger_init_callback) + : PluginInstance<SymbolLocatorCreateInstance>( + name, description, create_callback, debugger_init_callback), + locate_executable_object_file(locate_executable_object_file), + locate_executable_symbol_file(locate_executable_symbol_file), + download_object_symbol_file(download_object_symbol_file), + find_symbol_file_in_bundle(find_symbol_file_in_bundle) {} + + SymbolLocatorLocateExecutableObjectFile locate_executable_object_file; + SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file; + SymbolLocatorDownloadObjectAndSymbolFile download_object_symbol_file; + SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle; +}; +typedef PluginInstances<SymbolLocatorInstance> SymbolLocatorInstances; + +static SymbolLocatorInstances &GetSymbolLocatorInstances() { + static SymbolLocatorInstances g_instances; + return g_instances; +} + +bool PluginManager::RegisterPlugin( + llvm::StringRef name, llvm::StringRef description, + SymbolLocatorCreateInstance create_callback, + SymbolLocatorLocateExecutableObjectFile locate_executable_object_file, + SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file, + SymbolLocatorDownloadObjectAndSymbolFile download_object_symbol_file, + SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle, + DebuggerInitializeCallback debugger_init_callback) { + return GetSymbolLocatorInstances().RegisterPlugin( + name, description, create_callback, locate_executable_object_file, + locate_executable_symbol_file, download_object_symbol_file, + find_symbol_file_in_bundle, debugger_init_callback); +} + +bool PluginManager::UnregisterPlugin( + SymbolLocatorCreateInstance create_callback) { + return GetSymbolLocatorInstances().UnregisterPlugin(create_callback); +} + +SymbolLocatorCreateInstance +PluginManager::GetSymbolLocatorCreateCallbackAtIndex(uint32_t idx) { + return GetSymbolLocatorInstances().GetCallbackAtIndex(idx); +} + +ModuleSpec +PluginManager::LocateExecutableObjectFile(const ModuleSpec &module_spec) { + auto &instances = GetSymbolLocatorInstances().GetInstances(); + for (auto &instance : instances) { + if (instance.locate_executable_object_file) { + std::optional<ModuleSpec> result = + instance.locate_executable_object_file(module_spec); + if (result) + return *result; + } + } + return {}; +} + +FileSpec PluginManager::LocateExecutableSymbolFile( + const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { + auto &instances = GetSymbolLocatorInstances().GetInstances(); + for (auto &instance : instances) { + if (instance.locate_executable_symbol_file) { + std::optional<FileSpec> result = instance.locate_executable_symbol_file( + module_spec, default_search_paths); + if (result) + return *result; + } + } + return {}; +} + +bool PluginManager::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + Status &error, + bool force_lookup, + bool copy_executable) { + auto &instances = GetSymbolLocatorInstances().GetInstances(); + for (auto &instance : instances) { + if (instance.download_object_symbol_file) { + if (instance.download_object_symbol_file(module_spec, error, force_lookup, + copy_executable)) + return true; + } + } + return false; +} + +FileSpec PluginManager::FindSymbolFileInBundle(const FileSpec &symfile_bundle, + const UUID *uuid, + const ArchSpec *arch) { + auto &instances = GetSymbolLocatorInstances().GetInstances(); + for (auto &instance : instances) { + if (instance.find_symbol_file_in_bundle) { + std::optional<FileSpec> result = + instance.find_symbol_file_in_bundle(symfile_bundle, uuid, arch); + if (result) + return *result; + } + } + return {}; +} + #pragma mark Trace struct TraceInstance @@ -1422,6 +1535,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) { GetPlatformInstances().PerformDebuggerCallback(debugger); GetProcessInstances().PerformDebuggerCallback(debugger); GetSymbolFileInstances().PerformDebuggerCallback(debugger); + GetSymbolLocatorInstances().PerformDebuggerCallback(debugger); GetOperatingSystemInstances().PerformDebuggerCallback(debugger); GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger); GetTracePluginInstances().PerformDebuggerCallback(debugger); @@ -1549,6 +1663,7 @@ static constexpr llvm::StringLiteral kProcessPluginName("process"); static constexpr llvm::StringLiteral kTracePluginName("trace"); static constexpr llvm::StringLiteral kObjectFilePluginName("object-file"); static constexpr llvm::StringLiteral kSymbolFilePluginName("symbol-file"); +static constexpr llvm::StringLiteral kSymbolLocatorPluginName("symbol-locator"); static constexpr llvm::StringLiteral kJITLoaderPluginName("jit-loader"); static constexpr llvm::StringLiteral kStructuredDataPluginName("structured-data"); @@ -1597,6 +1712,20 @@ bool PluginManager::CreateSettingForProcessPlugin( description, is_global_property); } +lldb::OptionValuePropertiesSP +PluginManager::GetSettingForSymbolLocatorPlugin(Debugger &debugger, + llvm::StringRef setting_name) { + return GetSettingForPlugin(debugger, setting_name, kSymbolLocatorPluginName); +} + +bool PluginManager::CreateSettingForSymbolLocatorPlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + llvm::StringRef description, bool is_global_property) { + return CreateSettingForPlugin(debugger, kSymbolLocatorPluginName, + "Settings for symbol locator plug-ins", + properties_sp, description, is_global_property); +} + bool PluginManager::CreateSettingForTracePlugin( Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, llvm::StringRef description, bool is_global_property) { diff --git a/lldb/source/Core/Progress.cpp b/lldb/source/Core/Progress.cpp index 08be73f1470f..ea3f874916a9 100644 --- a/lldb/source/Core/Progress.cpp +++ b/lldb/source/Core/Progress.cpp @@ -30,10 +30,9 @@ Progress::~Progress() { // Make sure to always report progress completed when this object is // destructed so it indicates the progress dialog/activity should go away. std::lock_guard<std::mutex> guard(m_mutex); - if (!m_completed) { + if (!m_completed) m_completed = m_total; - ReportProgress(); - } + ReportProgress(); } void Progress::Increment(uint64_t amount, std::string update) { diff --git a/lldb/source/Core/SearchFilter.cpp b/lldb/source/Core/SearchFilter.cpp index 4f9519b5cc9a..b3ff73bbf58f 100644 --- a/lldb/source/Core/SearchFilter.cpp +++ b/lldb/source/Core/SearchFilter.cpp @@ -471,13 +471,13 @@ SearchFilterSP SearchFilterByModule::CreateFromStructuredData( return nullptr; } - llvm::StringRef module; - success = modules_array->GetItemAtIndexAsString(0, module); - if (!success) { + std::optional<llvm::StringRef> maybe_module = + modules_array->GetItemAtIndexAsString(0); + if (!maybe_module) { error.SetErrorString("SFBM::CFSD: filter module item not a string."); return nullptr; } - FileSpec module_spec(module); + FileSpec module_spec(*maybe_module); return std::make_shared<SearchFilterByModule>(target_sp, module_spec); } @@ -596,14 +596,14 @@ SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData( FileSpecList modules; size_t num_modules = modules_array->GetSize(); for (size_t i = 0; i < num_modules; i++) { - llvm::StringRef module; - success = modules_array->GetItemAtIndexAsString(i, module); - if (!success) { + std::optional<llvm::StringRef> maybe_module = + modules_array->GetItemAtIndexAsString(i); + if (!maybe_module) { error.SetErrorStringWithFormat( "SFBM::CFSD: filter module item %zu not a string.", i); return nullptr; } - modules.EmplaceBack(module); + modules.EmplaceBack(*maybe_module); } return std::make_shared<SearchFilterByModuleList>(target_sp, modules); } @@ -644,14 +644,14 @@ lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData( if (success) { size_t num_modules = modules_array->GetSize(); for (size_t i = 0; i < num_modules; i++) { - llvm::StringRef module; - success = modules_array->GetItemAtIndexAsString(i, module); - if (!success) { + std::optional<llvm::StringRef> maybe_module = + modules_array->GetItemAtIndexAsString(i); + if (!maybe_module) { error.SetErrorStringWithFormat( "SFBM::CFSD: filter module item %zu not a string.", i); return result_sp; } - modules.EmplaceBack(module); + modules.EmplaceBack(*maybe_module); } } @@ -666,14 +666,14 @@ lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData( size_t num_cus = cus_array->GetSize(); FileSpecList cus; for (size_t i = 0; i < num_cus; i++) { - llvm::StringRef cu; - success = cus_array->GetItemAtIndexAsString(i, cu); - if (!success) { + std::optional<llvm::StringRef> maybe_cu = + cus_array->GetItemAtIndexAsString(i); + if (!maybe_cu) { error.SetErrorStringWithFormat( "SFBM::CFSD: filter CU item %zu not a string.", i); return nullptr; } - cus.EmplaceBack(cu); + cus.EmplaceBack(*maybe_cu); } return std::make_shared<SearchFilterByModuleListAndCU>( diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 212b3119894f..9e98b59deb03 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -149,6 +149,8 @@ const char *Section::GetTypeAsCString() const { return "ctf"; case eSectionTypeOther: return "regular"; + case eSectionTypeSwiftModules: + return "swift-modules"; } return "unknown"; } @@ -455,6 +457,7 @@ bool Section::ContainsOnlyDebugInfo() const { case eSectionTypeDWARFAppleObjC: case eSectionTypeDWARFGNUDebugAltLink: case eSectionTypeCTF: + case eSectionTypeSwiftModules: return true; } return false; diff --git a/lldb/source/Core/StreamFile.cpp b/lldb/source/Core/StreamFile.cpp deleted file mode 100644 index 8aac0b6d6306..000000000000 --- a/lldb/source/Core/StreamFile.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===-- StreamFile.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/StreamFile.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" - -#include <cstdio> - -using namespace lldb; -using namespace lldb_private; - -StreamFile::StreamFile(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) - : Stream(flags, addr_size, byte_order) { - m_file_sp = std::make_shared<File>(); -} - -StreamFile::StreamFile(int fd, bool transfer_ownership) : Stream() { - m_file_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionWriteOnly, - transfer_ownership); -} - -StreamFile::StreamFile(FILE *fh, bool transfer_ownership) : Stream() { - m_file_sp = std::make_shared<NativeFile>(fh, transfer_ownership); -} - -StreamFile::StreamFile(const char *path, File::OpenOptions options, - uint32_t permissions) - : Stream() { - auto file = FileSystem::Instance().Open(FileSpec(path), options, permissions); - if (file) - m_file_sp = std::move(file.get()); - else { - // TODO refactor this so the error gets popagated up instead of logged here. - LLDB_LOG_ERROR(GetLog(LLDBLog::Host), file.takeError(), - "Cannot open {1}: {0}", path); - m_file_sp = std::make_shared<File>(); - } -} - -StreamFile::~StreamFile() = default; - -void StreamFile::Flush() { m_file_sp->Flush(); } - -size_t StreamFile::WriteImpl(const void *s, size_t length) { - m_file_sp->Write(s, length); - return length; -} diff --git a/lldb/source/Core/ThreadedCommunication.cpp b/lldb/source/Core/ThreadedCommunication.cpp index 755a158a5359..7d8aae5d8ff6 100644 --- a/lldb/source/Core/ThreadedCommunication.cpp +++ b/lldb/source/Core/ThreadedCommunication.cpp @@ -23,6 +23,7 @@ #include <chrono> #include <cstring> #include <memory> +#include <shared_mutex> #include <cerrno> #include <cinttypes> @@ -155,6 +156,8 @@ size_t ThreadedCommunication::Read(void *dst, size_t dst_len, } bool ThreadedCommunication::StartReadThread(Status *error_ptr) { + std::lock_guard<std::mutex> lock(m_read_thread_mutex); + if (error_ptr) error_ptr->Clear(); @@ -189,6 +192,8 @@ bool ThreadedCommunication::StartReadThread(Status *error_ptr) { } bool ThreadedCommunication::StopReadThread(Status *error_ptr) { + std::lock_guard<std::mutex> lock(m_read_thread_mutex); + if (!m_read_thread.IsJoinable()) return true; @@ -199,13 +204,13 @@ bool ThreadedCommunication::StopReadThread(Status *error_ptr) { BroadcastEvent(eBroadcastBitReadThreadShouldExit, nullptr); - // error = m_read_thread.Cancel(); - Status error = m_read_thread.Join(nullptr); return error.Success(); } bool ThreadedCommunication::JoinReadThread(Status *error_ptr) { + std::lock_guard<std::mutex> lock(m_read_thread_mutex); + if (!m_read_thread.IsJoinable()) return true; diff --git a/lldb/source/Core/UserSettingsController.cpp b/lldb/source/Core/UserSettingsController.cpp index f5dd926cf050..72217117557f 100644 --- a/lldb/source/Core/UserSettingsController.cpp +++ b/lldb/source/Core/UserSettingsController.cpp @@ -30,6 +30,13 @@ class Property; using namespace lldb; using namespace lldb_private; +Properties::Properties() = default; + +Properties::Properties(const lldb::OptionValuePropertiesSP &collection_sp) + : m_collection_sp(collection_sp) {} + +Properties::~Properties() = default; + lldb::OptionValueSP Properties::GetPropertyValue(const ExecutionContext *exe_ctx, llvm::StringRef path, Status &error) const { diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp index 5a2631ca501f..995cc934c820 100644 --- a/lldb/source/Core/Value.cpp +++ b/lldb/source/Core/Value.cpp @@ -98,7 +98,9 @@ void Value::AppendBytes(const void *bytes, int len) { } void Value::Dump(Stream *strm) { - m_value.GetValue(strm, true); + if (!strm) + return; + m_value.GetValue(*strm, true); strm->Printf(", value_type = %s, context = %p, context_type = %s", Value::GetValueTypeAsCString(m_value_type), m_context, Value::GetContextTypeAsCString(m_context_type)); @@ -572,7 +574,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, return error; } -Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) { +Scalar &Value::ResolveValue(ExecutionContext *exe_ctx, Module *module) { const CompilerType &compiler_type = GetCompilerType(); if (compiler_type.IsValid()) { switch (m_value_type) { @@ -587,7 +589,7 @@ Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) { { DataExtractor data; lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS); - Status error(GetValueAsData(exe_ctx, data, nullptr)); + Status error(GetValueAsData(exe_ctx, data, module)); if (error.Success()) { Scalar scalar; if (compiler_type.GetValueAsScalar( diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index d60a1d6f7a10..a7f7ee64282d 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/ValueObjectDynamicValue.h" #include "lldb/Core/ValueObjectMemory.h" #include "lldb/Core/ValueObjectSyntheticFilter.h" +#include "lldb/Core/ValueObjectVTable.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/DumpValueObjectOptions.h" #include "lldb/DataFormatters/FormatManager.h" @@ -218,10 +219,8 @@ bool ValueObject::UpdateFormatsIfNeeded() { SetValueFormat(DataVisualization::GetFormat(*this, eNoDynamicValues)); SetSummaryFormat( DataVisualization::GetSummaryFormat(*this, GetDynamicValueType())); -#if LLDB_ENABLE_PYTHON SetSyntheticChildren( DataVisualization::GetSyntheticChildren(*this, GetDynamicValueType())); -#endif } return any_change; @@ -336,7 +335,7 @@ bool ValueObject::ResolveValue(Scalar &scalar) { { ExecutionContext exe_ctx(GetExecutionContextRef()); Value tmp_value(m_value); - scalar = tmp_value.ResolveValue(&exe_ctx); + scalar = tmp_value.ResolveValue(&exe_ctx, GetModule().get()); if (scalar.IsValid()) { const uint32_t bitfield_bit_size = GetBitfieldBitSize(); if (bitfield_bit_size) @@ -440,23 +439,6 @@ ValueObject::GetChildAtNamePath(llvm::ArrayRef<llvm::StringRef> names) { return root; } -lldb::ValueObjectSP ValueObject::GetChildAtNamePath( - llvm::ArrayRef<std::pair<ConstString, bool>> names, - ConstString *name_of_error) { - if (names.size() == 0) - return GetSP(); - ValueObjectSP root(GetSP()); - for (std::pair<ConstString, bool> name : names) { - root = root->GetChildMemberWithName(name.first, name.second); - if (!root) { - if (name_of_error) - *name_of_error = name.first; - return root; - } - } - return root; -} - size_t ValueObject::GetIndexOfChildWithName(llvm::StringRef name) { bool omit_empty_base_classes = true; return GetCompilerType().GetIndexOfChildWithName(name, @@ -1170,7 +1152,7 @@ bool ValueObject::DumpPrintableRepresentation( Stream &s, ValueObjectRepresentationStyle val_obj_display, Format custom_format, PrintableRepresentationSpecialCases special, bool do_dump_error) { - + // If the ValueObject has an error, we might end up dumping the type, which // is useful, but if we don't even have a type, then don't examine the object // further as that's not meaningful, only the error is. @@ -2148,11 +2130,10 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl( temp_expression = temp_expression.drop_front(); // skip . or > size_t next_sep_pos = temp_expression.find_first_of("-.[", 1); - ConstString child_name; if (next_sep_pos == llvm::StringRef::npos) // if no other separator just // expand this last layer { - child_name.SetString(temp_expression); + llvm::StringRef child_name = temp_expression; ValueObjectSP child_valobj_sp = root->GetChildMemberWithName(child_name); @@ -2220,8 +2201,7 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl( } else // other layers do expand { llvm::StringRef next_separator = temp_expression.substr(next_sep_pos); - - child_name.SetString(temp_expression.slice(0, next_sep_pos)); + llvm::StringRef child_name = temp_expression.slice(0, next_sep_pos); ValueObjectSP child_valobj_sp = root->GetChildMemberWithName(child_name); @@ -2614,34 +2594,30 @@ ValueObjectSP ValueObject::CreateConstantValue(ConstString name) { ValueObjectSP ValueObject::GetQualifiedRepresentationIfAvailable( lldb::DynamicValueType dynValue, bool synthValue) { - ValueObjectSP result_sp(GetSP()); - + ValueObjectSP result_sp; switch (dynValue) { case lldb::eDynamicCanRunTarget: case lldb::eDynamicDontRunTarget: { - if (!result_sp->IsDynamic()) { - if (result_sp->GetDynamicValue(dynValue)) - result_sp = result_sp->GetDynamicValue(dynValue); - } + if (!IsDynamic()) + result_sp = GetDynamicValue(dynValue); } break; case lldb::eNoDynamicValues: { - if (result_sp->IsDynamic()) { - if (result_sp->GetStaticValue()) - result_sp = result_sp->GetStaticValue(); - } + if (IsDynamic()) + result_sp = GetStaticValue(); } break; } + if (!result_sp) + result_sp = GetSP(); + assert(result_sp); - if (synthValue) { - if (!result_sp->IsSynthetic()) { - if (result_sp->GetSyntheticValue()) - result_sp = result_sp->GetSyntheticValue(); - } - } else { - if (result_sp->IsSynthetic()) { - if (result_sp->GetNonSyntheticValue()) - result_sp = result_sp->GetNonSyntheticValue(); - } + bool is_synthetic = result_sp->IsSynthetic(); + if (synthValue && !is_synthetic) { + if (auto synth_sp = result_sp->GetSyntheticValue()) + return synth_sp; + } + if (!synthValue && is_synthetic) { + if (auto non_synth_sp = result_sp->GetNonSyntheticValue()) + return non_synth_sp; } return result_sp; @@ -2785,15 +2761,15 @@ ValueObjectSP ValueObject::DoCast(const CompilerType &compiler_type) { ValueObjectSP ValueObject::Cast(const CompilerType &compiler_type) { // Only allow casts if the original type is equal or larger than the cast - // type. We don't know how to fetch more data for all the ConstResult types, + // type. We don't know how to fetch more data for all the ConstResult types, // so we can't guarantee this will work: Status error; CompilerType my_type = GetCompilerType(); - ExecutionContextScope *exe_scope + ExecutionContextScope *exe_scope = ExecutionContext(GetExecutionContextRef()) .GetBestExecutionContextScope(); - if (compiler_type.GetByteSize(exe_scope) + if (compiler_type.GetByteSize(exe_scope) <= GetCompilerType().GetByteSize(exe_scope)) { return DoCast(compiler_type); } @@ -3176,3 +3152,7 @@ ValueObjectSP ValueObject::Persist() { return persistent_var_sp->GetValueObject(); } + +lldb::ValueObjectSP ValueObject::GetVTable() { + return ValueObjectVTable::Create(*this); +} diff --git a/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/lldb/source/Core/ValueObjectSyntheticFilter.cpp index ad29d36ae08a..43bc532c4a04 100644 --- a/lldb/source/Core/ValueObjectSyntheticFilter.cpp +++ b/lldb/source/Core/ValueObjectSyntheticFilter.cpp @@ -41,7 +41,7 @@ public: return m_backend.GetIndexOfChildWithName(name); } - bool MightHaveChildren() override { return true; } + bool MightHaveChildren() override { return m_backend.MightHaveChildren(); } bool Update() override { return false; } }; @@ -163,8 +163,8 @@ bool ValueObjectSynthetic::UpdateValue() { return false; } - // regenerate the synthetic filter if our typename changes - // <rdar://problem/12424824> + // Regenerate the synthetic filter if our typename changes. When the (dynamic) + // type of an object changes, so does their synthetic filter of choice. ConstString new_parent_type_name = m_parent->GetTypeName(); if (new_parent_type_name != m_parent_type_name) { LLDB_LOGF(log, @@ -311,7 +311,7 @@ ValueObjectSynthetic::GetChildMemberWithName(llvm::StringRef name, bool can_create) { UpdateValueIfNeeded(); - uint32_t index = GetIndexOfChildWithName(ConstString(name)); + uint32_t index = GetIndexOfChildWithName(name); if (index == UINT32_MAX) return lldb::ValueObjectSP(); diff --git a/lldb/source/Core/ValueObjectVTable.cpp b/lldb/source/Core/ValueObjectVTable.cpp new file mode 100644 index 000000000000..177ae4167a1d --- /dev/null +++ b/lldb/source/Core/ValueObjectVTable.cpp @@ -0,0 +1,274 @@ +//===-- ValueObjectVTable.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/ValueObjectVTable.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ValueObjectChild.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Target/Language.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private-enumerations.h" + +using namespace lldb; +using namespace lldb_private; + +class ValueObjectVTableChild : public ValueObject { +public: + ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx, + uint64_t addr_size) + : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) { + SetFormat(eFormatPointer); + SetName(ConstString(llvm::formatv("[{0}]", func_idx).str())); + } + + ~ValueObjectVTableChild() override = default; + + std::optional<uint64_t> GetByteSize() override { return m_addr_size; }; + + size_t CalculateNumChildren(uint32_t max) override { return 0; }; + + ValueType GetValueType() const override { return eValueTypeVTableEntry; }; + + bool IsInScope() override { + if (ValueObject *parent = GetParent()) + return parent->IsInScope(); + return false; + }; + +protected: + bool UpdateValue() override { + SetValueIsValid(false); + m_value.Clear(); + ValueObject *parent = GetParent(); + if (!parent) { + m_error.SetErrorString("owning vtable object not valid"); + return false; + } + + addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + if (parent_addr == LLDB_INVALID_ADDRESS) { + m_error.SetErrorString("invalid vtable address"); + return false; + } + + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) { + m_error.SetErrorString("no process"); + return false; + } + + TargetSP target_sp = GetTargetSP(); + if (!target_sp) { + m_error.SetErrorString("no target"); + return false; + } + + // Each `vtable_entry_addr` points to the function pointer. + addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size; + addr_t vfunc_ptr = + process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error); + if (m_error.Fail()) { + m_error.SetErrorStringWithFormat( + "failed to read virtual function entry 0x%16.16" PRIx64, + vtable_entry_addr); + return false; + } + + + // Set our value to be the load address of the function pointer in memory + // and our type to be the function pointer type. + m_value.SetValueType(Value::ValueType::LoadAddress); + m_value.GetScalar() = vtable_entry_addr; + + // See if our resolved address points to a function in the debug info. If + // it does, then we can report the type as a function prototype for this + // function. + Function *function = nullptr; + Address resolved_vfunc_ptr_address; + target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address); + if (resolved_vfunc_ptr_address.IsValid()) + function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction(); + if (function) { + m_value.SetCompilerType(function->GetCompilerType().GetPointerType()); + } else { + // Set our value's compiler type to a generic function protoype so that + // it displays as a hex function pointer for the value and the summary + // will display the address description. + + // Get the original type that this vtable is based off of so we can get + // the language from it correctly. + ValueObject *val = parent->GetParent(); + auto type_system = target_sp->GetScratchTypeSystemForLanguage( + val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus); + if (type_system) { + m_value.SetCompilerType( + (*type_system)->CreateGenericFunctionPrototype().GetPointerType()); + } else { + consumeError(type_system.takeError()); + } + } + + // Now read our value into m_data so that our we can use the default + // summary provider for C++ for function pointers which will get the + // address description for our function pointer. + if (m_error.Success()) { + const bool thread_and_frame_only_if_stopped = true; + ExecutionContext exe_ctx( + GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped)); + m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); + } + SetValueDidChange(true); + SetValueIsValid(true); + return true; + }; + + CompilerType GetCompilerTypeImpl() override { + return m_value.GetCompilerType(); + }; + + const uint32_t m_func_idx; + const uint64_t m_addr_size; + +private: + // For ValueObject only + ValueObjectVTableChild(const ValueObjectVTableChild &) = delete; + const ValueObjectVTableChild & + operator=(const ValueObjectVTableChild &) = delete; +}; + +ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) { + return (new ValueObjectVTable(parent))->GetSP(); +} + +ValueObjectVTable::ValueObjectVTable(ValueObject &parent) + : ValueObject(parent) { + SetFormat(eFormatPointer); +} + +std::optional<uint64_t> ValueObjectVTable::GetByteSize() { + if (m_vtable_symbol) + return m_vtable_symbol->GetByteSize(); + return std::nullopt; +} + +size_t ValueObjectVTable::CalculateNumChildren(uint32_t max) { + if (UpdateValueIfNeeded(false)) + return m_num_vtable_entries <= max ? m_num_vtable_entries : max; + return 0; +} + +ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; } + +ConstString ValueObjectVTable::GetTypeName() { + if (m_vtable_symbol) + return m_vtable_symbol->GetName(); + return ConstString(); +} + +ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); } + +ConstString ValueObjectVTable::GetDisplayTypeName() { + if (m_vtable_symbol) + return m_vtable_symbol->GetDisplayName(); + return ConstString(); +} + +bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); } + +ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx, + bool synthetic_array_member, + int32_t synthetic_index) { + if (synthetic_array_member) + return nullptr; + return new ValueObjectVTableChild(*this, idx, m_addr_size); +} + +bool ValueObjectVTable::UpdateValue() { + m_error.Clear(); + m_flags.m_children_count_valid = false; + SetValueIsValid(false); + m_num_vtable_entries = 0; + ValueObject *parent = GetParent(); + if (!parent) { + m_error.SetErrorString("no parent object"); + return false; + } + + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) { + m_error.SetErrorString("no process"); + return false; + } + + const LanguageType language = parent->GetObjectRuntimeLanguage(); + LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(language); + + if (language_runtime == nullptr) { + m_error.SetErrorStringWithFormat( + "no language runtime support for the language \"%s\"", + Language::GetNameForLanguageType(language)); + return false; + } + + // Get the vtable information from the language runtime. + llvm::Expected<LanguageRuntime::VTableInfo> vtable_info_or_err = + language_runtime->GetVTableInfo(*parent, /*check_type=*/true); + if (!vtable_info_or_err) { + m_error = vtable_info_or_err.takeError(); + return false; + } + + TargetSP target_sp = GetTargetSP(); + const addr_t vtable_start_addr = + vtable_info_or_err->addr.GetLoadAddress(target_sp.get()); + + m_vtable_symbol = vtable_info_or_err->symbol; + if (!m_vtable_symbol) { + m_error.SetErrorStringWithFormat( + "no vtable symbol found containing 0x%" PRIx64, vtable_start_addr); + return false; + } + + // Now that we know it's a vtable, we update the object's state. + SetName(GetTypeName()); + + // Calculate the number of entries + if (!m_vtable_symbol->GetByteSizeIsValid()) { + m_error.SetErrorStringWithFormat( + "vtable symbol \"%s\" doesn't have a valid size", + m_vtable_symbol->GetMangled().GetDemangledName().GetCString()); + return false; + } + + m_addr_size = process_sp->GetAddressByteSize(); + const addr_t vtable_end_addr = + m_vtable_symbol->GetLoadAddress(target_sp.get()) + + m_vtable_symbol->GetByteSize(); + m_num_vtable_entries = (vtable_end_addr - vtable_start_addr) / m_addr_size; + + m_value.SetValueType(Value::ValueType::LoadAddress); + m_value.GetScalar() = parent->GetAddressOf(); + auto type_system_or_err = + target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus); + if (type_system_or_err) { + m_value.SetCompilerType( + (*type_system_or_err)->GetBasicTypeFromAST(eBasicTypeUnsignedLong)); + } else { + consumeError(type_system_or_err.takeError()); + } + SetValueDidChange(true); + SetValueIsValid(true); + return true; +} + +CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); } + +ValueObjectVTable::~ValueObjectVTable() = default; |
