diff options
Diffstat (limited to 'lldb/source/Target')
| -rw-r--r-- | lldb/source/Target/BorrowedStackFrame.cpp | 187 | ||||
| -rw-r--r-- | lldb/source/Target/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lldb/source/Target/ExecutionContext.cpp | 17 | ||||
| -rw-r--r-- | lldb/source/Target/Language.cpp | 42 | ||||
| -rw-r--r-- | lldb/source/Target/Process.cpp | 22 | ||||
| -rw-r--r-- | lldb/source/Target/StackFrame.cpp | 14 | ||||
| -rw-r--r-- | lldb/source/Target/StackFrameList.cpp | 49 | ||||
| -rw-r--r-- | lldb/source/Target/SyntheticFrameProvider.cpp | 25 | ||||
| -rw-r--r-- | lldb/source/Target/Target.cpp | 98 | ||||
| -rw-r--r-- | lldb/source/Target/TargetList.cpp | 5 | ||||
| -rw-r--r-- | lldb/source/Target/Thread.cpp | 72 | ||||
| -rw-r--r-- | lldb/source/Target/ThreadPlanStepOut.cpp | 11 | ||||
| -rw-r--r-- | lldb/source/Target/ThreadPlanStepRange.cpp | 4 | ||||
| -rw-r--r-- | lldb/source/Target/ThreadSpec.cpp | 4 | ||||
| -rw-r--r-- | lldb/source/Target/UnixSignals.cpp | 7 |
15 files changed, 520 insertions, 38 deletions
diff --git a/lldb/source/Target/BorrowedStackFrame.cpp b/lldb/source/Target/BorrowedStackFrame.cpp new file mode 100644 index 0000000..5afadf2 --- /dev/null +++ b/lldb/source/Target/BorrowedStackFrame.cpp @@ -0,0 +1,187 @@ +//===----------------------------------------------------------------------===// +// +// 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/Target/BorrowedStackFrame.h" + +using namespace lldb; +using namespace lldb_private; + +char BorrowedStackFrame::ID; + +BorrowedStackFrame::BorrowedStackFrame( + StackFrameSP borrowed_frame_sp, uint32_t new_frame_index, + std::optional<uint32_t> new_concrete_frame_index) + : StackFrame( + borrowed_frame_sp->GetThread(), new_frame_index, + borrowed_frame_sp->GetConcreteFrameIndex(), + borrowed_frame_sp->GetRegisterContextSP(), + borrowed_frame_sp->GetStackID().GetPC(), + borrowed_frame_sp->GetStackID().GetCallFrameAddressWithoutMetadata(), + borrowed_frame_sp->m_behaves_like_zeroth_frame, + &borrowed_frame_sp->GetSymbolContext(eSymbolContextEverything)), + m_borrowed_frame_sp(borrowed_frame_sp), + m_new_frame_index(new_frame_index) { + if (new_concrete_frame_index) + m_new_concrete_frame_index = *new_concrete_frame_index; + else + m_new_concrete_frame_index = + IsInlined() ? LLDB_INVALID_FRAME_ID : new_frame_index; +} + +uint32_t BorrowedStackFrame::GetFrameIndex() const { return m_new_frame_index; } + +void BorrowedStackFrame::SetFrameIndex(uint32_t index) { + m_new_frame_index = index; +} + +uint32_t BorrowedStackFrame::GetConcreteFrameIndex() { + // FIXME: We need to find where the concrete frame into which this frame was + // inlined landed in the new stack frame list as that is the correct concrete + // frame index in this + // stack frame. + return m_new_concrete_frame_index; +} + +StackID &BorrowedStackFrame::GetStackID() { + return m_borrowed_frame_sp->GetStackID(); +} + +const Address &BorrowedStackFrame::GetFrameCodeAddress() { + return m_borrowed_frame_sp->GetFrameCodeAddress(); +} + +Address BorrowedStackFrame::GetFrameCodeAddressForSymbolication() { + return m_borrowed_frame_sp->GetFrameCodeAddressForSymbolication(); +} + +bool BorrowedStackFrame::ChangePC(addr_t pc) { + return m_borrowed_frame_sp->ChangePC(pc); +} + +const SymbolContext & +BorrowedStackFrame::GetSymbolContext(SymbolContextItem resolve_scope) { + return m_borrowed_frame_sp->GetSymbolContext(resolve_scope); +} + +llvm::Error BorrowedStackFrame::GetFrameBaseValue(Scalar &value) { + return m_borrowed_frame_sp->GetFrameBaseValue(value); +} + +DWARFExpressionList * +BorrowedStackFrame::GetFrameBaseExpression(Status *error_ptr) { + return m_borrowed_frame_sp->GetFrameBaseExpression(error_ptr); +} + +Block *BorrowedStackFrame::GetFrameBlock() { + return m_borrowed_frame_sp->GetFrameBlock(); +} + +RegisterContextSP BorrowedStackFrame::GetRegisterContext() { + return m_borrowed_frame_sp->GetRegisterContext(); +} + +VariableList *BorrowedStackFrame::GetVariableList(bool get_file_globals, + Status *error_ptr) { + return m_borrowed_frame_sp->GetVariableList(get_file_globals, error_ptr); +} + +VariableListSP +BorrowedStackFrame::GetInScopeVariableList(bool get_file_globals, + bool must_have_valid_location) { + return m_borrowed_frame_sp->GetInScopeVariableList(get_file_globals, + must_have_valid_location); +} + +ValueObjectSP BorrowedStackFrame::GetValueForVariableExpressionPath( + llvm::StringRef var_expr, DynamicValueType use_dynamic, uint32_t options, + VariableSP &var_sp, Status &error) { + return m_borrowed_frame_sp->GetValueForVariableExpressionPath( + var_expr, use_dynamic, options, var_sp, error); +} + +bool BorrowedStackFrame::HasDebugInformation() { + return m_borrowed_frame_sp->HasDebugInformation(); +} + +const char *BorrowedStackFrame::Disassemble() { + return m_borrowed_frame_sp->Disassemble(); +} + +ValueObjectSP BorrowedStackFrame::GetValueObjectForFrameVariable( + const VariableSP &variable_sp, DynamicValueType use_dynamic) { + return m_borrowed_frame_sp->GetValueObjectForFrameVariable(variable_sp, + use_dynamic); +} + +bool BorrowedStackFrame::IsInlined() { + return m_borrowed_frame_sp->IsInlined(); +} + +bool BorrowedStackFrame::IsSynthetic() const { + return m_borrowed_frame_sp->IsSynthetic(); +} + +bool BorrowedStackFrame::IsHistorical() const { + return m_borrowed_frame_sp->IsHistorical(); +} + +bool BorrowedStackFrame::IsArtificial() const { + return m_borrowed_frame_sp->IsArtificial(); +} + +bool BorrowedStackFrame::IsHidden() { return m_borrowed_frame_sp->IsHidden(); } + +const char *BorrowedStackFrame::GetFunctionName() { + return m_borrowed_frame_sp->GetFunctionName(); +} + +const char *BorrowedStackFrame::GetDisplayFunctionName() { + return m_borrowed_frame_sp->GetDisplayFunctionName(); +} + +ValueObjectSP BorrowedStackFrame::FindVariable(ConstString name) { + return m_borrowed_frame_sp->FindVariable(name); +} + +SourceLanguage BorrowedStackFrame::GetLanguage() { + return m_borrowed_frame_sp->GetLanguage(); +} + +SourceLanguage BorrowedStackFrame::GuessLanguage() { + return m_borrowed_frame_sp->GuessLanguage(); +} + +ValueObjectSP BorrowedStackFrame::GuessValueForAddress(addr_t addr) { + return m_borrowed_frame_sp->GuessValueForAddress(addr); +} + +ValueObjectSP +BorrowedStackFrame::GuessValueForRegisterAndOffset(ConstString reg, + int64_t offset) { + return m_borrowed_frame_sp->GuessValueForRegisterAndOffset(reg, offset); +} + +StructuredData::ObjectSP BorrowedStackFrame::GetLanguageSpecificData() { + return m_borrowed_frame_sp->GetLanguageSpecificData(); +} + +RecognizedStackFrameSP BorrowedStackFrame::GetRecognizedFrame() { + return m_borrowed_frame_sp->GetRecognizedFrame(); +} + +StackFrameSP BorrowedStackFrame::GetBorrowedFrame() const { + return m_borrowed_frame_sp; +} + +bool BorrowedStackFrame::isA(const void *ClassID) const { + return ClassID == &ID || StackFrame::isA(ClassID); +} + +bool BorrowedStackFrame::classof(const StackFrame *obj) { + return obj->isA(&ID); +} diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index cff5904..df2ee03 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -41,6 +41,7 @@ add_lldb_library(lldbTarget SyntheticFrameProvider.cpp SectionLoadHistory.cpp SectionLoadList.cpp + BorrowedStackFrame.cpp StackFrame.cpp StackFrameList.cpp StackFrameRecognizer.cpp diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp index a795913..b16ff26 100644 --- a/lldb/source/Target/ExecutionContext.cpp +++ b/lldb/source/Target/ExecutionContext.cpp @@ -466,10 +466,13 @@ operator=(const ExecutionContext &exe_ctx) { else m_tid = LLDB_INVALID_THREAD_ID; lldb::StackFrameSP frame_sp(exe_ctx.GetFrameSP()); - if (frame_sp) + if (frame_sp) { m_stack_id = frame_sp->GetStackID(); - else + m_frame_list_wp = frame_sp->GetContainingStackFrameList(); + } else { m_stack_id.Clear(); + m_frame_list_wp.reset(); + } return *this; } @@ -511,6 +514,7 @@ void ExecutionContextRef::SetThreadSP(const lldb::ThreadSP &thread_sp) { void ExecutionContextRef::SetFrameSP(const lldb::StackFrameSP &frame_sp) { if (frame_sp) { m_stack_id = frame_sp->GetStackID(); + m_frame_list_wp = frame_sp->GetContainingStackFrameList(); SetThreadSP(frame_sp->GetThread()); } else { ClearFrame(); @@ -638,6 +642,15 @@ lldb::ThreadSP ExecutionContextRef::GetThreadSP() const { lldb::StackFrameSP ExecutionContextRef::GetFrameSP() const { if (m_stack_id.IsValid()) { + // Try the remembered frame list first to avoid circular dependencies + // during frame provider initialization. + if (auto frame_list_sp = m_frame_list_wp.lock()) { + if (auto frame_sp = frame_list_sp->GetFrameWithStackID(m_stack_id)) + return frame_sp; + } + + // Fallback: ask the thread, which might re-trigger the frame provider + // initialization. lldb::ThreadSP thread_sp(GetThreadSP()); if (thread_sp) return thread_sp->GetFrameWithStackID(m_stack_id); diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp index 8268d4a..c8b09c3 100644 --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -159,6 +159,48 @@ void Language::ForEach( } } +llvm::Expected<LanguageType> +Language::GetExceptionLanguageForLanguage(llvm::StringRef lang_name) { + LanguageType language = Language::GetLanguageTypeFromString(lang_name); + LanguageType exception_language = eLanguageTypeUnknown; + + llvm::StringRef error_context; + switch (language) { + case eLanguageTypeC89: + case eLanguageTypeC: + case eLanguageTypeC99: + case eLanguageTypeC11: + exception_language = eLanguageTypeC; + break; + case eLanguageTypeC_plus_plus: + case eLanguageTypeC_plus_plus_03: + case eLanguageTypeC_plus_plus_11: + case eLanguageTypeC_plus_plus_14: + exception_language = eLanguageTypeC_plus_plus; + break; + case eLanguageTypeObjC_plus_plus: + error_context = + "Set exception breakpoints separately for c++ and objective-c"; + break; + case eLanguageTypeUnknown: + error_context = "Unknown language type for exception breakpoint"; + break; + default: + if (Language *languagePlugin = Language::FindPlugin(language)) { + if (languagePlugin->SupportsExceptionBreakpointsOnThrow() || + languagePlugin->SupportsExceptionBreakpointsOnCatch()) { + exception_language = language; + break; + } + } + error_context = "Unsupported language type for exception breakpoint"; + } + if (!error_context.empty()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + error_context); + return exception_language; +} + bool Language::IsTopLevelFunction(Function &function) { return false; } lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; } diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 42ce198..9c8e8fa7 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2452,8 +2452,10 @@ size_t Process::ReadScalarIntegerFromMemory(addr_t addr, uint32_t byte_size, scalar = data.GetMaxU32(&offset, byte_size); else scalar = data.GetMaxU64(&offset, byte_size); - if (is_signed) + if (is_signed) { + scalar.MakeSigned(); scalar.SignExtend(byte_size * 8); + } return bytes_read; } } else { @@ -3256,6 +3258,7 @@ Status Process::ConnectRemote(llvm::StringRef remote_url) { if (state == eStateStopped || state == eStateCrashed) { // If we attached and actually have a process on the other end, then // this ended up being the equivalent of an attach. + SetShouldDetach(true); CompleteAttach(); // This delays passing the stopped event to listeners till @@ -6544,7 +6547,7 @@ Status Process::WriteMemoryTags(lldb::addr_t addr, size_t len, // Create a CoreFileMemoryRange from a MemoryRegionInfo static CoreFileMemoryRange -CreateCoreFileMemoryRange(const MemoryRegionInfo ®ion) { +CreateCoreFileMemoryRange(const lldb_private::MemoryRegionInfo ®ion) { const addr_t addr = region.GetRange().GetRangeBase(); llvm::AddressRange range(addr, addr + region.GetRange().GetByteSize()); return {range, region.GetLLDBPermissions()}; @@ -6553,7 +6556,7 @@ CreateCoreFileMemoryRange(const MemoryRegionInfo ®ion) { // Add dirty pages to the core file ranges and return true if dirty pages // were added. Return false if the dirty page information is not valid or in // the region. -static bool AddDirtyPages(const MemoryRegionInfo ®ion, +static bool AddDirtyPages(const lldb_private::MemoryRegionInfo ®ion, CoreFileMemoryRanges &ranges) { const auto &dirty_page_list = region.GetDirtyPageList(); if (!dirty_page_list) @@ -6592,8 +6595,8 @@ static bool AddDirtyPages(const MemoryRegionInfo ®ion, // given region. If the region has dirty page information, only dirty pages // will be added to \a ranges, else the entire range will be added to \a // ranges. -static void AddRegion(const MemoryRegionInfo ®ion, bool try_dirty_pages, - CoreFileMemoryRanges &ranges) { +static void AddRegion(const lldb_private::MemoryRegionInfo ®ion, + bool try_dirty_pages, CoreFileMemoryRanges &ranges) { // Don't add empty ranges. if (region.GetRange().GetByteSize() == 0) return; @@ -6616,7 +6619,7 @@ static void SaveDynamicLoaderSections(Process &process, if (!dyld) return; - std::vector<MemoryRegionInfo> dynamic_loader_mem_regions; + std::vector<lldb_private::MemoryRegionInfo> dynamic_loader_mem_regions; std::function<bool(const lldb_private::Thread &)> save_thread_predicate = [&](const lldb_private::Thread &t) -> bool { return options.ShouldThreadBeSaved(t.GetID()); @@ -6741,10 +6744,11 @@ static void GetCoreFileSaveRangesStackOnly(Process &process, // TODO: We should refactor CoreFileMemoryRanges to use the lldb range type, and // then add an intersect method on it, or MemoryRegionInfo. -static MemoryRegionInfo Intersect(const MemoryRegionInfo &lhs, - const MemoryRegionInfo::RangeType &rhs) { +static lldb_private::MemoryRegionInfo +Intersect(const lldb_private::MemoryRegionInfo &lhs, + const lldb_private::MemoryRegionInfo::RangeType &rhs) { - MemoryRegionInfo region_info; + lldb_private::MemoryRegionInfo region_info; region_info.SetLLDBPermissions(lhs.GetLLDBPermissions()); region_info.GetRange() = lhs.GetRange().Intersect(rhs); diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 95b5154..3bbb851 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -45,6 +45,9 @@ using namespace lldb; using namespace lldb_private; +// LLVM RTTI support. +char StackFrame::ID; + // The first bits in the flags are reserved for the SymbolContext::Scope bits // so we know if we have tried to look up information in our internal symbol // context (m_sc) already. @@ -328,6 +331,13 @@ StackFrame::GetSymbolContext(SymbolContextItem resolve_scope) { // following the function call instruction... Address lookup_addr(GetFrameCodeAddressForSymbolication()); + // For PC-less frames (e.g., scripted frames), skip PC-based symbol + // resolution and preserve any already-populated SymbolContext fields. + if (!lookup_addr.IsValid()) { + m_flags.Set(resolve_scope | resolved); + return m_sc; + } + if (m_sc.module_sp) { // We have something in our stack frame symbol context, lets check if we // haven't already tried to lookup one of those things. If we haven't @@ -2054,10 +2064,10 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, disasm_display = debugger.GetStopDisassemblyDisplay(); GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry); - if (m_sc.comp_unit && m_sc.line_entry.IsValid()) { + if (m_sc.comp_unit || m_sc.line_entry.IsValid()) { have_debuginfo = true; if (source_lines_before > 0 || source_lines_after > 0) { - SupportFileSP source_file_sp = m_sc.line_entry.file_sp; + SupportFileNSP source_file_sp = m_sc.line_entry.file_sp; uint32_t start_line = m_sc.line_entry.line; if (!start_line && m_sc.function) { m_sc.function->GetStartLineSourceInfo(source_file_sp, start_line); diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index ccf874f..896a760 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -20,6 +20,7 @@ #include "lldb/Target/StackFrame.h" #include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/StopInfo.h" +#include "lldb/Target/SyntheticFrameProvider.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Unwind.h" @@ -55,6 +56,49 @@ StackFrameList::~StackFrameList() { Clear(); } +SyntheticStackFrameList::SyntheticStackFrameList( + Thread &thread, lldb::StackFrameListSP input_frames, + const lldb::StackFrameListSP &prev_frames_sp, bool show_inline_frames) + : StackFrameList(thread, prev_frames_sp, show_inline_frames), + m_input_frames(std::move(input_frames)) {} + +bool SyntheticStackFrameList::FetchFramesUpTo( + uint32_t end_idx, InterruptionControl allow_interrupt) { + + size_t num_synthetic_frames = 0; + // Check if the thread has a synthetic frame provider. + if (auto provider_sp = m_thread.GetFrameProvider()) { + // Use the synthetic frame provider to generate frames lazily. + // Keep fetching until we reach end_idx or the provider returns an error. + for (uint32_t idx = m_frames.size(); idx <= end_idx; idx++) { + if (allow_interrupt && + m_thread.GetProcess()->GetTarget().GetDebugger().InterruptRequested()) + return true; + auto frame_or_err = provider_sp->GetFrameAtIndex(idx); + if (!frame_or_err) { + // Provider returned error - we've reached the end. + LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), frame_or_err.takeError(), + "Frame provider reached end at index {0}: {1}", idx); + SetAllFramesFetched(); + break; + } + StackFrameSP frame_sp = *frame_or_err; + if (frame_sp->IsSynthetic()) + frame_sp->GetStackID().SetCFA(num_synthetic_frames++, + GetThread().GetProcess().get()); + // Set the frame list weak pointer so ExecutionContextRef can resolve + // the frame without calling Thread::GetStackFrameList(). + frame_sp->m_frame_list_wp = shared_from_this(); + m_frames.push_back(frame_sp); + } + + return false; // Not interrupted. + } + + // If no provider, fall back to the base implementation. + return StackFrameList::FetchFramesUpTo(end_idx, allow_interrupt); +} + void StackFrameList::CalculateCurrentInlinedDepth() { uint32_t cur_inlined_depth = GetCurrentInlinedDepth(); if (cur_inlined_depth == UINT32_MAX) { @@ -330,6 +374,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa, cfa_is_valid, pc, StackFrame::Kind::Regular, artificial, behaves_like_zeroth_frame, &sc); + synth_frame->m_frame_list_wp = shared_from_this(); m_frames.push_back(synth_frame); LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc); } @@ -445,6 +490,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx, unwind_frame_sp = std::make_shared<StackFrame>( m_thread.shared_from_this(), m_frames.size(), idx, reg_ctx_sp, cfa, pc, behaves_like_zeroth_frame, nullptr); + unwind_frame_sp->m_frame_list_wp = shared_from_this(); m_frames.push_back(unwind_frame_sp); } } else { @@ -479,6 +525,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx, // although its concrete index will stay the same. SynthesizeTailCallFrames(*unwind_frame_sp.get()); + unwind_frame_sp->m_frame_list_wp = shared_from_this(); m_frames.push_back(unwind_frame_sp); } @@ -503,6 +550,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx, unwind_frame_sp->GetRegisterContextSP(), cfa, next_frame_address, behaves_like_zeroth_frame, &next_frame_sc)); + frame_sp->m_frame_list_wp = shared_from_this(); m_frames.push_back(frame_sp); unwind_sc = next_frame_sc; curr_frame_address = next_frame_address; @@ -559,6 +607,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx, prev_frame->UpdatePreviousFrameFromCurrentFrame(*curr_frame); // Now copy the fixed up previous frame into the current frames so the // pointer doesn't change. + prev_frame_sp->m_frame_list_wp = shared_from_this(); m_frames[curr_frame_idx] = prev_frame_sp; #if defined(DEBUG_STACK_FRAMES) diff --git a/lldb/source/Target/SyntheticFrameProvider.cpp b/lldb/source/Target/SyntheticFrameProvider.cpp index 241ce82..97ff42d 100644 --- a/lldb/source/Target/SyntheticFrameProvider.cpp +++ b/lldb/source/Target/SyntheticFrameProvider.cpp @@ -8,10 +8,12 @@ #include "lldb/Target/SyntheticFrameProvider.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; @@ -21,12 +23,17 @@ SyntheticFrameProvider::SyntheticFrameProvider(StackFrameListSP input_frames) SyntheticFrameProvider::~SyntheticFrameProvider() = default; -void SyntheticFrameProviderDescriptor::Dump(Stream *s) const { +void ScriptedFrameProviderDescriptor::Dump(Stream *s) const { if (!s) return; + s->Format(" ID: {0:x}\n", GetID()); s->Printf(" Name: %s\n", GetName().str().c_str()); + std::string description = GetDescription(); + if (!description.empty()) + s->Printf(" Description: %s\n", description.c_str()); + // Show thread filter information. if (thread_specs.empty()) { s->PutCString(" Thread Filter: (applies to all threads)\n"); @@ -41,9 +48,23 @@ void SyntheticFrameProviderDescriptor::Dump(Stream *s) const { } } +uint32_t ScriptedFrameProviderDescriptor::GetID() const { + if (!scripted_metadata_sp) + return 0; + + return scripted_metadata_sp->GetID(); +} + +std::string ScriptedFrameProviderDescriptor::GetDescription() const { + // If we have an interface, call get_description() to fetch it. + if (interface_sp && scripted_metadata_sp) + return interface_sp->GetDescription(scripted_metadata_sp->GetClassName()); + return {}; +} + llvm::Expected<SyntheticFrameProviderSP> SyntheticFrameProvider::CreateInstance( StackFrameListSP input_frames, - const SyntheticFrameProviderDescriptor &descriptor) { + const ScriptedFrameProviderDescriptor &descriptor) { if (!input_frames) return llvm::createStringError( "cannot create synthetic frame provider: invalid input frames"); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index ae6c4f7..2305f10 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -156,8 +156,6 @@ static Status installExecutable(const Installer &installer) { return Status(); } -constexpr std::chrono::milliseconds EvaluateExpressionOptions::default_timeout; - Target::Arch::Arch(const ArchSpec &spec) : m_spec(spec), m_plugin_up(PluginManager::CreateArchitectureInstance(spec)) {} @@ -187,6 +185,8 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, m_internal_stop_hooks(), m_latest_stop_hook_id(0), m_valid(true), m_suppress_stop_hooks(false), m_is_dummy_target(is_dummy_target), m_target_unique_id(g_target_unique_id++), + m_target_session_name( + llvm::formatv("Session {0}", m_target_unique_id).str()), m_frame_recognizer_manager_up( std::make_unique<StackFrameRecognizerManager>()) { SetEventName(eBroadcastBitBreakpointChanged, "breakpoint-changed"); @@ -194,6 +194,7 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, SetEventName(eBroadcastBitModulesUnloaded, "modules-unloaded"); SetEventName(eBroadcastBitWatchpointChanged, "watchpoint-changed"); SetEventName(eBroadcastBitSymbolsLoaded, "symbols-loaded"); + SetEventName(eBroadcastBitNewTargetCreated, "new-target-created"); CheckInWithManager(); @@ -1855,6 +1856,9 @@ void Target::NotifyModulesRemoved(lldb_private::ModuleList &module_list) { } void Target::ModulesDidLoad(ModuleList &module_list) { + if (GetPreloadSymbols()) + module_list.PreloadSymbols(GetParallelModuleLoad()); + const size_t num_images = module_list.GetSize(); if (m_valid && num_images) { for (size_t idx = 0; idx < num_images; ++idx) { @@ -2279,8 +2283,10 @@ size_t Target::ReadScalarIntegerFromMemory(const Address &addr, uint32_t byte_si else scalar = data.GetMaxU64(&offset, byte_size); - if (is_signed) + if (is_signed) { + scalar.MakeSigned(); scalar.SignExtend(byte_size * 8); + } return bytes_read; } } else { @@ -2295,7 +2301,7 @@ int64_t Target::ReadSignedIntegerFromMemory(const Address &addr, int64_t fail_value, Status &error, bool force_live_memory) { Scalar scalar; - if (ReadScalarIntegerFromMemory(addr, integer_byte_size, false, scalar, error, + if (ReadScalarIntegerFromMemory(addr, integer_byte_size, true, scalar, error, force_live_memory)) return scalar.SLongLong(fail_value); return fail_value; @@ -2509,10 +2515,6 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec, if (symbol_file_spec) module_sp->SetSymbolFileFileSpec(symbol_file_spec); - // Preload symbols outside of any lock, so hopefully we can do this for - // each library in parallel. - if (GetPreloadSymbols()) - module_sp->PreloadSymbols(); llvm::SmallVector<ModuleSP, 1> replaced_modules; for (ModuleSP &old_module_sp : old_modules) { if (m_images.GetIndexForModule(old_module_sp.get()) != @@ -3207,6 +3209,11 @@ bool Target::RunStopHooks(bool at_initial_stop) { bool should_stop = false; bool requested_continue = false; + // A stop hook might get deleted while running stop hooks. + // We have to decide what that means. We will follow the rule that deleting + // a stop hook while processing these stop hooks will delete it for FUTURE + // stops but not this stop. Fortunately, copying the m_stop_hooks to the + // active_hooks list before iterating over the hooks has this effect. for (auto cur_hook_sp : active_hooks) { bool any_thread_matched = false; for (auto exc_ctx : exc_ctx_with_reasons) { @@ -3713,6 +3720,61 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { return error; } +llvm::Expected<uint32_t> Target::AddScriptedFrameProviderDescriptor( + const ScriptedFrameProviderDescriptor &descriptor) { + if (!descriptor.IsValid()) + return llvm::createStringError("invalid frame provider descriptor"); + + llvm::StringRef name = descriptor.GetName(); + if (name.empty()) + return llvm::createStringError( + "frame provider descriptor has no class name"); + + std::lock_guard<std::recursive_mutex> guard( + m_frame_provider_descriptors_mutex); + + uint32_t descriptor_id = descriptor.GetID(); + m_frame_provider_descriptors[descriptor_id] = descriptor; + + // Clear frame providers on existing threads so they reload with new config. + if (ProcessSP process_sp = GetProcessSP()) + for (ThreadSP thread_sp : process_sp->Threads()) + thread_sp->ClearScriptedFrameProvider(); + + return descriptor_id; +} + +bool Target::RemoveScriptedFrameProviderDescriptor(uint32_t id) { + std::lock_guard<std::recursive_mutex> guard( + m_frame_provider_descriptors_mutex); + bool removed = m_frame_provider_descriptors.erase(id); + + if (removed) + if (ProcessSP process_sp = GetProcessSP()) + for (ThreadSP thread_sp : process_sp->Threads()) + thread_sp->ClearScriptedFrameProvider(); + + return removed; +} + +void Target::ClearScriptedFrameProviderDescriptors() { + std::lock_guard<std::recursive_mutex> guard( + m_frame_provider_descriptors_mutex); + + m_frame_provider_descriptors.clear(); + + if (ProcessSP process_sp = GetProcessSP()) + for (ThreadSP thread_sp : process_sp->Threads()) + thread_sp->ClearScriptedFrameProvider(); +} + +const llvm::DenseMap<uint32_t, ScriptedFrameProviderDescriptor> & +Target::GetScriptedFrameProviderDescriptors() const { + std::lock_guard<std::recursive_mutex> guard( + m_frame_provider_descriptors_mutex); + return m_frame_provider_descriptors; +} + void Target::FinalizeFileActions(ProcessLaunchInfo &info) { Log *log = GetLog(LLDBLog::Process); @@ -5083,17 +5145,17 @@ void TargetProperties::SetProcessLaunchInfo( const FileAction *input_file_action = launch_info.GetFileActionForFD(STDIN_FILENO); if (input_file_action) { - SetStandardInputPath(input_file_action->GetPath()); + SetStandardInputPath(input_file_action->GetFileSpec().GetPath()); } const FileAction *output_file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); if (output_file_action) { - SetStandardOutputPath(output_file_action->GetPath()); + SetStandardOutputPath(output_file_action->GetFileSpec().GetPath()); } const FileAction *error_file_action = launch_info.GetFileActionForFD(STDERR_FILENO); if (error_file_action) { - SetStandardErrorPath(error_file_action->GetPath()); + SetStandardErrorPath(error_file_action->GetFileSpec().GetPath()); } SetDetachOnError(launch_info.GetFlags().Test(lldb::eLaunchFlagDetachOnError)); SetDisableASLR(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)); @@ -5196,6 +5258,11 @@ Target::TargetEventData::TargetEventData(const lldb::TargetSP &target_sp, const ModuleList &module_list) : EventData(), m_target_sp(target_sp), m_module_list(module_list) {} +Target::TargetEventData::TargetEventData( + const lldb::TargetSP &target_sp, const lldb::TargetSP &created_target_sp) + : EventData(), m_target_sp(target_sp), + m_created_target_sp(created_target_sp), m_module_list() {} + Target::TargetEventData::~TargetEventData() = default; llvm::StringRef Target::TargetEventData::GetFlavorString() { @@ -5230,6 +5297,15 @@ TargetSP Target::TargetEventData::GetTargetFromEvent(const Event *event_ptr) { return target_sp; } +TargetSP +Target::TargetEventData::GetCreatedTargetFromEvent(const Event *event_ptr) { + TargetSP created_target_sp; + const TargetEventData *event_data = GetEventDataFromEvent(event_ptr); + if (event_data) + created_target_sp = event_data->m_created_target_sp; + return created_target_sp; +} + ModuleList Target::TargetEventData::GetModuleListFromEvent(const Event *event_ptr) { ModuleList module_list; diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp index 2e03bc1..ce04e9c 100644 --- a/lldb/source/Target/TargetList.cpp +++ b/lldb/source/Target/TargetList.cpp @@ -48,7 +48,7 @@ Status TargetList::CreateTarget(Debugger &debugger, LoadDependentFiles load_dependent_files, const OptionGroupPlatform *platform_options, TargetSP &target_sp) { - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + auto result = TargetList::CreateTargetInternal( debugger, user_exe_path, triple_str, load_dependent_files, platform_options, target_sp); @@ -63,7 +63,7 @@ Status TargetList::CreateTarget(Debugger &debugger, const ArchSpec &specified_arch, LoadDependentFiles load_dependent_files, PlatformSP &platform_sp, TargetSP &target_sp) { - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + auto result = TargetList::CreateTargetInternal( debugger, user_exe_path, specified_arch, load_dependent_files, platform_sp, target_sp); @@ -521,6 +521,7 @@ uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const { } void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); lldbassert(!llvm::is_contained(m_target_list, target_sp) && "target already exists it the list"); UnregisterInProcessTarget(target_sp); diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 8c3e197..b40e753 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -13,9 +13,12 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Host/Host.h" +#include "lldb/Interpreter/Interfaces/ScriptedFrameInterface.h" +#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Property.h" +#include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Symbol/Function.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" @@ -26,6 +29,7 @@ #include "lldb/Target/ScriptedThreadPlan.h" #include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/StopInfo.h" +#include "lldb/Target/SyntheticFrameProvider.h" #include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlan.h" @@ -45,6 +49,7 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/ScriptedMetadata.h" #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" @@ -257,6 +262,7 @@ void Thread::DestroyThread() { std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); m_curr_frames_sp.reset(); m_prev_frames_sp.reset(); + m_frame_provider_sp.reset(); m_prev_framezero_pc.reset(); } @@ -1439,13 +1445,76 @@ void Thread::CalculateExecutionContext(ExecutionContext &exe_ctx) { StackFrameListSP Thread::GetStackFrameList() { std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); - if (!m_curr_frames_sp) + if (m_curr_frames_sp) + return m_curr_frames_sp; + + // First, try to load a frame provider if we don't have one yet. + if (!m_frame_provider_sp) { + ProcessSP process_sp = GetProcess(); + if (process_sp) { + Target &target = process_sp->GetTarget(); + const auto &descriptors = target.GetScriptedFrameProviderDescriptors(); + + // Find first descriptor that applies to this thread. + for (const auto &entry : descriptors) { + const ScriptedFrameProviderDescriptor &descriptor = entry.second; + if (descriptor.IsValid() && descriptor.AppliesToThread(*this)) { + if (llvm::Error error = LoadScriptedFrameProvider(descriptor)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(error), + "Failed to load scripted frame provider: {0}"); + } + break; // Use first matching descriptor (success or failure). + } + } + } + } + + // Create the frame list based on whether we have a provider. + if (m_frame_provider_sp) { + // We have a provider - create synthetic frame list. + StackFrameListSP input_frames = m_frame_provider_sp->GetInputFrames(); + m_curr_frames_sp = std::make_shared<SyntheticStackFrameList>( + *this, input_frames, m_prev_frames_sp, true); + } else { + // No provider - use normal unwinder frames. m_curr_frames_sp = std::make_shared<StackFrameList>(*this, m_prev_frames_sp, true); + } return m_curr_frames_sp; } +llvm::Error Thread::LoadScriptedFrameProvider( + const ScriptedFrameProviderDescriptor &descriptor) { + std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); + + // Note: We don't create input_frames here - it will be created lazily + // by SyntheticStackFrameList when frames are first fetched. + // Creating them too early can cause crashes during thread initialization. + + // Create a temporary StackFrameList just to get the thread reference for the + // provider. The provider won't actually use this - it will get real input + // frames from SyntheticStackFrameList later. + StackFrameListSP temp_frames = + std::make_shared<StackFrameList>(*this, m_prev_frames_sp, true); + + auto provider_or_err = + SyntheticFrameProvider::CreateInstance(temp_frames, descriptor); + if (!provider_or_err) + return provider_or_err.takeError(); + + ClearScriptedFrameProvider(); + m_frame_provider_sp = *provider_or_err; + return llvm::Error::success(); +} + +void Thread::ClearScriptedFrameProvider() { + std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); + m_frame_provider_sp.reset(); + m_curr_frames_sp.reset(); + m_prev_frames_sp.reset(); +} + std::optional<addr_t> Thread::GetPreviousFrameZeroPC() { return m_prev_framezero_pc; } @@ -1466,6 +1535,7 @@ void Thread::ClearStackFrames() { m_prev_frames_sp.swap(m_curr_frames_sp); m_curr_frames_sp.reset(); + m_frame_provider_sp.reset(); m_extended_info.reset(); m_extended_info_fetched = false; } diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index d49a01b..0307b38 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -356,13 +356,10 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { } } - // If there was only one owner, then we're done. But if we also hit - // some user breakpoint on our way out, we should mark ourselves as - // done, but also not claim to explain the stop, since it is more - // important to report the user breakpoint than the step out - // completion. - - if (site_sp->GetNumberOfConstituents() == 1) + // If the thread also hit a user breakpoint on its way out, the plan is + // done but should not claim to explain the stop. It is more important + // to report the user breakpoint than the step out completion. + if (!site_sp->ContainsUserBreakpointForThread(GetThread())) return true; } return false; diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index dca96cc..3a9deb6 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -431,10 +431,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { top_most_line_entry.original_file_sp = std::make_shared<SupportFile>(call_site_file_spec); top_most_line_entry.range = range; - top_most_line_entry.file_sp.reset(); + top_most_line_entry.file_sp = std::make_shared<SupportFile>(); top_most_line_entry.ApplyFileMappings( GetThread().CalculateTarget()); - if (!top_most_line_entry.file_sp) + if (!top_most_line_entry.file_sp->GetSpecOnly()) top_most_line_entry.file_sp = top_most_line_entry.original_file_sp; } diff --git a/lldb/source/Target/ThreadSpec.cpp b/lldb/source/Target/ThreadSpec.cpp index ba4c3aa..624f64e 100644 --- a/lldb/source/Target/ThreadSpec.cpp +++ b/lldb/source/Target/ThreadSpec.cpp @@ -19,6 +19,10 @@ const char *ThreadSpec::g_option_names[static_cast<uint32_t>( ThreadSpec::ThreadSpec() : m_name(), m_queue_name() {} +ThreadSpec::ThreadSpec(Thread &thread) + : m_index(thread.GetIndexID()), m_tid(thread.GetID()), + m_name(thread.GetName()), m_queue_name(thread.GetQueueName()) {} + std::unique_ptr<ThreadSpec> ThreadSpec::CreateFromStructuredData( const StructuredData::Dictionary &spec_dict, Status &error) { uint32_t index = UINT32_MAX; diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index 6113c66..881431f 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -137,6 +137,13 @@ llvm::StringRef UnixSignals::GetSignalAsStringRef(int32_t signo) const { return pos->second.m_name; } +llvm::StringRef UnixSignals::GetSignalNumberDescription(int32_t signo) const { + const auto pos = m_signals.find(signo); + if (pos == m_signals.end()) + return {}; + return pos->second.m_description; +} + std::string UnixSignals::GetSignalDescription( int32_t signo, std::optional<int32_t> code, std::optional<lldb::addr_t> addr, std::optional<lldb::addr_t> lower, |
