diff options
| author | Mingming Liu <mingmingl@google.com> | 2025-09-10 15:25:31 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-10 15:25:31 -0700 |
| commit | 1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch) | |
| tree | 57f4b1f313c8cf74eed8819870f39c36ea263c68 /lldb/source/Core | |
| parent | 898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff) | |
| parent | b8cefcb601ddaa18482555c4ff363c01a270c2fe (diff) | |
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'lldb/source/Core')
| -rw-r--r-- | lldb/source/Core/CoreProperties.td | 4 | ||||
| -rw-r--r-- | lldb/source/Core/Disassembler.cpp | 156 | ||||
| -rw-r--r-- | lldb/source/Core/FormatEntity.cpp | 16 | ||||
| -rw-r--r-- | lldb/source/Core/Mangled.cpp | 15 | ||||
| -rw-r--r-- | lldb/source/Core/ModuleList.cpp | 15 | ||||
| -rw-r--r-- | lldb/source/Core/ProtocolServer.cpp | 34 |
6 files changed, 214 insertions, 26 deletions
diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 53dd333f045c..fda34a8ad263 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -59,7 +59,7 @@ let Definition = "debugger" in { Desc<"The default disassembly format string to use when disassembling instruction sequences.">; def FrameFormat: Property<"frame-format", "FormatEntity">, Global, - DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">, + DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">, Desc<"The default frame format string to use when displaying stack frame information for threads.">; def NotiftVoid: Property<"notify-void", "Boolean">, Global, @@ -233,7 +233,7 @@ let Definition = "debugger" in { Desc<"If true, LLDB will automatically escape non-printable and escape characters when formatting strings.">; def FrameFormatUnique: Property<"frame-format-unique", "FormatEntity">, Global, - DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">, + DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">, Desc<"The default frame format string to use when displaying stack frame information for threads from thread backtrace unique.">; def ShowAutosuggestion: Property<"show-autosuggestion", "Boolean">, Global, diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp index e0a7d6934570..f2ed1f739534 100644 --- a/lldb/source/Core/Disassembler.cpp +++ b/lldb/source/Core/Disassembler.cpp @@ -26,7 +26,11 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" @@ -41,6 +45,8 @@ #include "lldb/lldb-private-enumerations.h" #include "lldb/lldb-private-interfaces.h" #include "lldb/lldb-private-types.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/TargetParser/Triple.h" @@ -280,6 +286,127 @@ bool Disassembler::ElideMixedSourceAndDisassemblyLine( return false; } +// For each instruction, this block attempts to resolve in-scope variables +// and determine if the current PC falls within their +// DWARF location entry. If so, it prints a simplified annotation using the +// variable name and its resolved location (e.g., "var = reg; " ). +// +// Annotations are only included if the variable has a valid DWARF location +// entry, and the location string is non-empty after filtering. Decoding +// errors and DWARF opcodes are intentionally omitted to keep the output +// concise and user-friendly. +// +// The goal is to give users helpful live variable hints alongside the +// disassembled instruction stream, similar to how debug information +// enhances source-level debugging. +std::vector<std::string> +VariableAnnotator::annotate(Instruction &inst, Target &target, + const lldb::ModuleSP &module_sp) { + std::vector<std::string> events; + + // If we lost module context, everything becomes <undef>. + if (!module_sp) { + for (const auto &KV : Live_) + events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str()); + Live_.clear(); + return events; + } + + // Resolve function/block at this *file* address. + SymbolContext sc; + const Address &iaddr = inst.GetAddress(); + const auto mask = eSymbolContextFunction | eSymbolContextBlock; + if (!module_sp->ResolveSymbolContextForAddress(iaddr, mask, sc) || + !sc.function) { + // No function context: everything dies here. + for (const auto &KV : Live_) + events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str()); + Live_.clear(); + return events; + } + + // Collect in-scope variables for this instruction into Current. + VariableList var_list; + // Innermost block containing iaddr. + if (Block *B = sc.block) { + auto filter = [](Variable *v) -> bool { return v && !v->IsArtificial(); }; + B->AppendVariables(/*can_create*/ true, + /*get_parent_variables*/ true, + /*stop_if_block_is_inlined_function*/ false, + /*filter*/ filter, + /*variable_list*/ &var_list); + } + + const lldb::addr_t pc_file = iaddr.GetFileAddress(); + const lldb::addr_t func_file = sc.function->GetAddress().GetFileAddress(); + + // ABI from Target (pretty reg names if plugin exists). Safe to be null. + lldb::ABISP abi_sp = ABI::FindPlugin(nullptr, target.GetArchitecture()); + ABI *abi = abi_sp.get(); + + llvm::DIDumpOptions opts; + opts.ShowAddresses = false; + // Prefer "register-only" output when we have an ABI. + opts.PrintRegisterOnly = static_cast<bool>(abi_sp); + + llvm::DenseMap<lldb::user_id_t, VarState> Current; + + for (size_t i = 0, e = var_list.GetSize(); i != e; ++i) { + lldb::VariableSP v = var_list.GetVariableAtIndex(i); + if (!v || v->IsArtificial()) + continue; + + const char *nm = v->GetName().AsCString(); + llvm::StringRef name = nm ? nm : "<anon>"; + + DWARFExpressionList &exprs = v->LocationExpressionList(); + if (!exprs.IsValid()) + continue; + + auto entry_or_err = exprs.GetExpressionEntryAtAddress(func_file, pc_file); + if (!entry_or_err) + continue; + + auto entry = *entry_or_err; + + StreamString loc_ss; + entry.expr->DumpLocation(&loc_ss, eDescriptionLevelBrief, abi, opts); + + llvm::StringRef loc = llvm::StringRef(loc_ss.GetString()).trim(); + if (loc.empty()) + continue; + + Current.try_emplace(v->GetID(), + VarState{std::string(name), std::string(loc)}); + } + + // Diff Live_ → Current. + + // 1) Starts/changes: iterate Current and compare with Live_. + for (const auto &KV : Current) { + auto it = Live_.find(KV.first); + if (it == Live_.end()) { + // Newly live. + events.emplace_back( + llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str()); + } else if (it->second.last_loc != KV.second.last_loc) { + // Location changed. + events.emplace_back( + llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str()); + } + } + + // 2) Ends: anything that was live but is not in Current becomes <undef>. + for (const auto &KV : Live_) { + if (!Current.count(KV.first)) + events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str()); + } + + // Commit new state. + Live_ = std::move(Current); + return events; +} + void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, const ExecutionContext &exe_ctx, bool mixed_source_and_assembly, @@ -376,6 +503,7 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, } } + VariableAnnotator annot; previous_symbol = nullptr; SourceLine previous_line; for (size_t i = 0; i < num_instructions_found; ++i) { @@ -540,10 +668,26 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, const bool show_bytes = (options & eOptionShowBytes) != 0; const bool show_control_flow_kind = (options & eOptionShowControlFlowKind) != 0; - inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, + + StreamString inst_line; + + inst->Dump(&inst_line, max_opcode_byte_size, true, show_bytes, show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr, address_text_size); + + if ((options & eOptionVariableAnnotations) && target_sp) { + auto annotations = annot.annotate(*inst, *target_sp, module_sp); + if (!annotations.empty()) { + const size_t annotation_column = 100; + inst_line.FillLastLineToColumn(annotation_column, ' '); + inst_line.PutCString("; "); + inst_line.PutCString(llvm::join(annotations, ", ")); + } + } + + strm.PutCString(inst_line.GetString()); strm.EOL(); + } else { break; } @@ -724,9 +868,7 @@ bool Instruction::DumpEmulation(const ArchSpec &arch) { return false; } -bool Instruction::CanSetBreakpoint () { - return !HasDelaySlot(); -} +bool Instruction::CanSetBreakpoint() { return !HasDelaySlot(); } bool Instruction::HasDelaySlot() { // Default is false. @@ -1073,10 +1215,8 @@ void InstructionList::Append(lldb::InstructionSP &inst_sp) { m_instructions.push_back(inst_sp); } -uint32_t -InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, - bool ignore_calls, - bool *found_calls) const { +uint32_t InstructionList::GetIndexOfNextBranchInstruction( + uint32_t start, bool ignore_calls, bool *found_calls) const { size_t num_instructions = m_instructions.size(); uint32_t next_branch = UINT32_MAX; diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp index 5d3c8b421d5d..491f5c6320d9 100644 --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -108,6 +108,7 @@ constexpr Definition g_frame_child_entries[] = { Entry::DefinitionWithChildren("reg", EntryType::FrameRegisterByName, g_string_entry), Definition("is-artificial", EntryType::FrameIsArtificial), + Definition("kind", EntryType::FrameKind), }; constexpr Definition g_function_child_entries[] = { @@ -380,6 +381,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) { ENUM_TO_CSTR(FrameRegisterFlags); ENUM_TO_CSTR(FrameRegisterByName); ENUM_TO_CSTR(FrameIsArtificial); + ENUM_TO_CSTR(FrameKind); ENUM_TO_CSTR(ScriptFrame); ENUM_TO_CSTR(FunctionID); ENUM_TO_CSTR(FunctionDidChange); @@ -1679,7 +1681,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, StackFrame *frame = exe_ctx->GetFramePtr(); if (frame) { const Address &pc_addr = frame->GetFrameCodeAddress(); - if (pc_addr.IsValid()) { + if (pc_addr.IsValid() || frame->IsSynthetic()) { if (DumpAddressAndContent(s, sc, exe_ctx, pc_addr, false)) return true; } @@ -1747,6 +1749,18 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, return false; } + case Entry::Type::FrameKind: { + if (exe_ctx) + if (StackFrame *frame = exe_ctx->GetFramePtr()) { + if (frame->IsSynthetic()) + s.PutCString(" [synthetic]"); + else if (frame->IsHistorical()) + s.PutCString(" [history]"); + return true; + } + return false; + } + case Entry::Type::ScriptFrame: if (exe_ctx) { StackFrame *frame = exe_ctx->GetFramePtr(); diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index ce4db4e0daa8..91b9c0007617 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -556,3 +556,18 @@ void Mangled::Encode(DataEncoder &file, ConstStringTable &strtab) const { break; } } + +ConstString Mangled::GetBaseName() const { + const auto &demangled_info = GetDemangledInfo(); + if (!demangled_info.has_value()) + return {}; + + ConstString demangled_name = GetDemangledName(); + if (!demangled_name) + return {}; + + const char *name_str = demangled_name.AsCString(); + const auto &range = demangled_info->BasenameRange; + return ConstString( + llvm::StringRef(name_str + range.first, range.second - range.first)); +} diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 060732f421f8..bc63a41c90d1 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -844,8 +844,6 @@ public: } bool RemoveIfOrphaned(const Module *module_ptr) { - if (!module_ptr) - return false; std::lock_guard<std::recursive_mutex> guard(GetMutex()); RemoveFromMap(*module_ptr, /*if_orphaned=*/true); return m_list.RemoveIfOrphaned(module_ptr); @@ -982,7 +980,7 @@ private: }; struct SharedModuleListInfo { - SharedModuleList module_list; + ModuleList module_list; ModuleListProperties module_list_properties; }; } @@ -1000,7 +998,7 @@ static SharedModuleListInfo &GetSharedModuleListInfo() return *g_shared_module_list_info; } -static SharedModuleList &GetSharedModuleList() { +static ModuleList &GetSharedModuleList() { return GetSharedModuleListInfo().module_list; } @@ -1010,8 +1008,8 @@ ModuleListProperties &ModuleList::GetGlobalModuleListProperties() { bool ModuleList::ModuleIsInCache(const Module *module_ptr) { if (module_ptr) { - SharedModuleList &shared_module_list = GetSharedModuleList(); - return shared_module_list.FindModule(*module_ptr).get() != nullptr; + ModuleList &shared_module_list = GetSharedModuleList(); + return shared_module_list.FindModule(module_ptr).get() != nullptr; } return false; } @@ -1034,8 +1032,9 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr, bool always_create) { - SharedModuleList &shared_module_list = GetSharedModuleList(); - std::lock_guard<std::recursive_mutex> guard(shared_module_list.GetMutex()); + ModuleList &shared_module_list = GetSharedModuleList(); + std::lock_guard<std::recursive_mutex> guard( + shared_module_list.m_modules_mutex); char path[PATH_MAX]; Status error; diff --git a/lldb/source/Core/ProtocolServer.cpp b/lldb/source/Core/ProtocolServer.cpp index 41636cdacdec..38668f39795a 100644 --- a/lldb/source/Core/ProtocolServer.cpp +++ b/lldb/source/Core/ProtocolServer.cpp @@ -8,24 +8,29 @@ #include "lldb/Core/ProtocolServer.h" #include "lldb/Core/PluginManager.h" +#include "llvm/Support/Error.h" using namespace lldb_private; using namespace lldb; -ProtocolServer *ProtocolServer::GetOrCreate(llvm::StringRef name) { - static std::mutex g_mutex; +static std::pair<llvm::StringMap<ProtocolServerUP> &, std::mutex &> Servers() { static llvm::StringMap<ProtocolServerUP> g_protocol_server_instances; + static std::mutex g_mutex; + return {g_protocol_server_instances, g_mutex}; +} + +ProtocolServer *ProtocolServer::GetOrCreate(llvm::StringRef name) { + auto [protocol_server_instances, mutex] = Servers(); - std::lock_guard<std::mutex> guard(g_mutex); + std::lock_guard<std::mutex> guard(mutex); - auto it = g_protocol_server_instances.find(name); - if (it != g_protocol_server_instances.end()) + auto it = protocol_server_instances.find(name); + if (it != protocol_server_instances.end()) return it->second.get(); if (ProtocolServerCreateInstance create_callback = PluginManager::GetProtocolCreateCallbackForPluginName(name)) { - auto pair = - g_protocol_server_instances.try_emplace(name, create_callback()); + auto pair = protocol_server_instances.try_emplace(name, create_callback()); return pair.first->second.get(); } @@ -45,3 +50,18 @@ std::vector<llvm::StringRef> ProtocolServer::GetSupportedProtocols() { return supported_protocols; } + +llvm::Error ProtocolServer::Terminate() { + llvm::Error error = llvm::Error::success(); + + auto [protocol_server_instances, mutex] = Servers(); + std::lock_guard<std::mutex> guard(mutex); + for (auto &instance : protocol_server_instances) { + if (llvm::Error instance_error = instance.second->Stop()) + error = llvm::joinErrors(std::move(error), std::move(instance_error)); + } + + protocol_server_instances.clear(); + + return error; +} |
