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 | 3 | ||||
| -rw-r--r-- | lldb/source/Target/ExecutionContext.cpp | 17 | ||||
| -rw-r--r-- | lldb/source/Target/InstrumentationRuntime.cpp | 3 | ||||
| -rw-r--r-- | lldb/source/Target/Language.cpp | 42 | ||||
| -rw-r--r-- | lldb/source/Target/ModuleCache.cpp | 2 | ||||
| -rw-r--r-- | lldb/source/Target/Platform.cpp | 44 | ||||
| -rw-r--r-- | lldb/source/Target/Process.cpp | 24 | ||||
| -rw-r--r-- | lldb/source/Target/RemoteAwarePlatform.cpp | 11 | ||||
| -rw-r--r-- | lldb/source/Target/StackFrame.cpp | 20 | ||||
| -rw-r--r-- | lldb/source/Target/StackFrameList.cpp | 49 | ||||
| -rw-r--r-- | lldb/source/Target/SyntheticFrameProvider.cpp | 121 | ||||
| -rw-r--r-- | lldb/source/Target/Target.cpp | 154 | ||||
| -rw-r--r-- | lldb/source/Target/TargetList.cpp | 13 | ||||
| -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 | ||||
| -rw-r--r-- | lldb/source/Target/VerboseTrapFrameRecognizer.cpp | 156 |
20 files changed, 683 insertions, 261 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 b7788e8..df2ee03 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -38,8 +38,10 @@ add_lldb_library(lldbTarget RegisterNumber.cpp RemoteAwarePlatform.cpp ScriptedThreadPlan.cpp + SyntheticFrameProvider.cpp SectionLoadHistory.cpp SectionLoadList.cpp + BorrowedStackFrame.cpp StackFrame.cpp StackFrameList.cpp StackFrameRecognizer.cpp @@ -80,7 +82,6 @@ add_lldb_library(lldbTarget UnixSignals.cpp UnwindAssembly.cpp UnwindLLDB.cpp - VerboseTrapFrameRecognizer.cpp ADDITIONAL_HEADER_DIRS ${LLDB_INCLUDE_DIR}/lldb/Target 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/InstrumentationRuntime.cpp b/lldb/source/Target/InstrumentationRuntime.cpp index 7e58e8b..d9800a8 100644 --- a/lldb/source/Target/InstrumentationRuntime.cpp +++ b/lldb/source/Target/InstrumentationRuntime.cpp @@ -55,7 +55,8 @@ void InstrumentationRuntime::ModulesDidLoad( return IterationAction::Continue; const RegularExpression &runtime_regex = GetPatternForRuntimeLibrary(); - if (runtime_regex.Execute(file_spec.GetFilename().GetCString()) || + if (MatchAllModules() || + runtime_regex.Execute(file_spec.GetFilename().GetCString()) || module_sp->IsExecutable()) { if (CheckIfRuntimeIsValid(module_sp)) { SetRuntimeModuleSP(module_sp); 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/ModuleCache.cpp b/lldb/source/Target/ModuleCache.cpp index f737836..9978946 100644 --- a/lldb/source/Target/ModuleCache.cpp +++ b/lldb/source/Target/ModuleCache.cpp @@ -255,7 +255,7 @@ Status ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname, cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec(); error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp, - nullptr, nullptr, did_create_ptr, false); + nullptr, did_create_ptr, false); if (error.Fail()) return error; diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 8681ada..5b0930c 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -163,11 +163,12 @@ Platform::LocateExecutableScriptingResources(Target *target, Module &module, Status Platform::GetSharedModule( const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) { if (IsHost()) - return ModuleList::GetSharedModule(module_spec, module_sp, - module_search_paths_ptr, old_modules, + // Note: module_search_paths_ptr functionality is now handled internally + // by getting target from module_spec and calling + // target->GetExecutableSearchPaths() + return ModuleList::GetSharedModule(module_spec, module_sp, old_modules, did_create_ptr, false); // Module resolver lambda. @@ -180,16 +181,14 @@ Status Platform::GetSharedModule( resolved_spec = spec; resolved_spec.GetFileSpec().PrependPathComponent(m_sdk_sysroot); // Try to get shared module with resolved spec. - error = ModuleList::GetSharedModule(resolved_spec, module_sp, - module_search_paths_ptr, old_modules, + error = ModuleList::GetSharedModule(resolved_spec, module_sp, old_modules, did_create_ptr, false); } // If we don't have sysroot or it didn't work then // try original module spec. if (!error.Success()) { resolved_spec = spec; - error = ModuleList::GetSharedModule(resolved_spec, module_sp, - module_search_paths_ptr, old_modules, + error = ModuleList::GetSharedModule(resolved_spec, module_sp, old_modules, did_create_ptr, false); } if (error.Success() && module_sp) @@ -731,10 +730,8 @@ bool Platform::SetOSVersion(llvm::VersionTuple version) { return false; } -Status -Platform::ResolveExecutable(const ModuleSpec &module_spec, - lldb::ModuleSP &exe_module_sp, - const FileSpecList *module_search_paths_ptr) { +Status Platform::ResolveExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &exe_module_sp) { // We may connect to a process and use the provided executable (Don't use // local $PATH). @@ -750,9 +747,8 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec, if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid()) { - Status error = - ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, nullptr); + Status error = ModuleList::GetSharedModule(resolved_module_spec, + exe_module_sp, nullptr, nullptr); if (exe_module_sp && exe_module_sp->GetObjectFile()) return error; @@ -767,9 +763,9 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec, Status error; for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) { resolved_module_spec.GetArchitecture() = arch; - error = - ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, nullptr); + + error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, + nullptr, nullptr); if (error.Success()) { if (exe_module_sp && exe_module_sp->GetObjectFile()) break; @@ -1446,16 +1442,13 @@ const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() { return m_trap_handlers; } -Status -Platform::GetCachedExecutable(ModuleSpec &module_spec, - lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr) { +Status Platform::GetCachedExecutable(ModuleSpec &module_spec, + lldb::ModuleSP &module_sp) { FileSpec platform_spec = module_spec.GetFileSpec(); Status error = GetRemoteSharedModule( module_spec, nullptr, module_sp, [&](const ModuleSpec &spec) { - return Platform::ResolveExecutable(spec, module_sp, - module_search_paths_ptr); + return Platform::ResolveExecutable(spec, module_sp); }, nullptr); if (error.Success()) { @@ -1497,7 +1490,7 @@ Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec, for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) { arch_module_spec.GetArchitecture() = arch; error = ModuleList::GetSharedModule(arch_module_spec, module_sp, nullptr, - nullptr, nullptr); + nullptr); // Did we find an executable using one of the if (error.Success() && module_sp) break; @@ -1673,11 +1666,12 @@ void Platform::CallLocateModuleCallbackIfSet(const ModuleSpec &module_spec, cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5 // content hash instead of real UUID. cached_module_spec.GetFileSpec() = module_file_spec; + cached_module_spec.GetSymbolFileSpec() = symbol_file_spec; cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec(); cached_module_spec.SetObjectOffset(0); error = ModuleList::GetSharedModule(cached_module_spec, module_sp, nullptr, - nullptr, did_create_ptr, false); + did_create_ptr, false, false); if (error.Success() && module_sp) { // Succeeded to load the module file. LLDB_LOGF(log, "%s: locate module callback succeeded: module=%s symbol=%s", diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index fb9e7eb..9c8e8fa7 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -65,7 +65,6 @@ #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanStack.h" #include "lldb/Target/UnixSignals.h" -#include "lldb/Target/VerboseTrapFrameRecognizer.h" #include "lldb/Utility/AddressableBits.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/LLDBLog.h" @@ -513,7 +512,6 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, // We should have a plugin do the registration instead, for example, a // common C LanguageRuntime plugin. RegisterAssertFrameRecognizer(this); - RegisterVerboseTrapFrameRecognizer(*this); } Process::~Process() { @@ -2454,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 { @@ -3258,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 @@ -6546,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()}; @@ -6555,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) @@ -6594,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; @@ -6618,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()); @@ -6743,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/RemoteAwarePlatform.cpp b/lldb/source/Target/RemoteAwarePlatform.cpp index cac738e..89b946b 100644 --- a/lldb/source/Target/RemoteAwarePlatform.cpp +++ b/lldb/source/Target/RemoteAwarePlatform.cpp @@ -29,9 +29,8 @@ bool RemoteAwarePlatform::GetModuleSpec(const FileSpec &module_file_spec, return false; } -Status RemoteAwarePlatform::ResolveExecutable( - const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, - const FileSpecList *module_search_paths_ptr) { +Status RemoteAwarePlatform::ResolveExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &exe_module_sp) { ModuleSpec resolved_module_spec(module_spec); // The host platform can resolve the path more aggressively. @@ -47,12 +46,10 @@ Status RemoteAwarePlatform::ResolveExecutable( if (!FileSystem::Instance().Exists(resolved_file_spec)) FileSystem::Instance().ResolveExecutableLocation(resolved_file_spec); } else if (m_remote_platform_sp) { - return GetCachedExecutable(resolved_module_spec, exe_module_sp, - module_search_paths_ptr); + return GetCachedExecutable(resolved_module_spec, exe_module_sp); } - return Platform::ResolveExecutable(resolved_module_spec, exe_module_sp, - module_search_paths_ptr); + return Platform::ResolveExecutable(resolved_module_spec, exe_module_sp); } Status RemoteAwarePlatform::RunShellCommand( diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 2ed58c53..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 @@ -1344,18 +1354,18 @@ const char *StackFrame::GetDisplayFunctionName() { SourceLanguage StackFrame::GetLanguage() { CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit; if (cu) - return cu->GetLanguage(); + return SourceLanguage{cu->GetLanguage()}; return {}; } SourceLanguage StackFrame::GuessLanguage() { SourceLanguage lang_type = GetLanguage(); - if (lang_type == eLanguageTypeUnknown) { + if (!lang_type) { SymbolContext sc = GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol); if (sc.function) - lang_type = LanguageType(sc.function->GetMangled().GuessLanguage()); + lang_type = SourceLanguage(sc.function->GetMangled().GuessLanguage()); else if (sc.symbol) lang_type = SourceLanguage(sc.symbol->GetMangled().GuessLanguage()); } @@ -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 new file mode 100644 index 0000000..97ff42d --- /dev/null +++ b/lldb/source/Target/SyntheticFrameProvider.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// 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/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; + +SyntheticFrameProvider::SyntheticFrameProvider(StackFrameListSP input_frames) + : m_input_frames(std::move(input_frames)) {} + +SyntheticFrameProvider::~SyntheticFrameProvider() = default; + +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"); + } else { + s->Printf(" Thread Filter: %zu specification(s)\n", thread_specs.size()); + for (size_t i = 0; i < thread_specs.size(); ++i) { + const ThreadSpec &spec = thread_specs[i]; + s->Printf(" [%zu] ", i); + spec.GetDescription(s, lldb::eDescriptionLevelVerbose); + s->PutChar('\n'); + } + } +} + +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 ScriptedFrameProviderDescriptor &descriptor) { + if (!input_frames) + return llvm::createStringError( + "cannot create synthetic frame provider: invalid input frames"); + + // Iterate through all registered ScriptedFrameProvider plugins. + ScriptedFrameProviderCreateInstance create_callback = nullptr; + for (uint32_t idx = 0; + (create_callback = + PluginManager::GetScriptedFrameProviderCreateCallbackAtIndex( + idx)) != nullptr; + ++idx) { + auto provider_or_err = create_callback(input_frames, descriptor); + if (!provider_or_err) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Target), provider_or_err.takeError(), + "Failed to create synthetic frame provider: {0}"); + continue; + } + + if (auto frame_provider_up = std::move(*provider_or_err)) + return std::move(frame_provider_up); + } + + return llvm::createStringError( + "cannot create synthetic frame provider: no suitable plugin found"); +} + +llvm::Expected<SyntheticFrameProviderSP> SyntheticFrameProvider::CreateInstance( + StackFrameListSP input_frames, llvm::StringRef plugin_name, + const std::vector<ThreadSpec> &thread_specs) { + if (!input_frames) + return llvm::createStringError( + "cannot create synthetic frame provider: invalid input frames"); + + // Look up the specific C++ plugin by name. + SyntheticFrameProviderCreateInstance create_callback = + PluginManager::GetSyntheticFrameProviderCreateCallbackForPluginName( + plugin_name); + + if (!create_callback) + return llvm::createStringError( + "cannot create synthetic frame provider: C++ plugin '%s' not found", + plugin_name.str().c_str()); + + auto provider_or_err = create_callback(input_frames, thread_specs); + if (!provider_or_err) + return provider_or_err.takeError(); + + if (auto frame_provider_sp = std::move(*provider_or_err)) + return std::move(frame_provider_sp); + + return llvm::createStringError( + "cannot create synthetic frame provider: C++ plugin '%s' returned null", + plugin_name.str().c_str()); +} diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index d070c3d..2305f10 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Target/Target.h" +#include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointPrecondition.h" #include "lldb/Breakpoint/BreakpointResolver.h" @@ -155,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)) {} @@ -186,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"); @@ -193,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(); @@ -1778,9 +1780,9 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform, arch_spec.GetArchitectureName(), arch_spec.GetTriple().getTriple().c_str()); ModuleSpec module_spec(executable_sp->GetFileSpec(), other); - FileSpecList search_paths = GetExecutableSearchPaths(); + module_spec.SetTarget(shared_from_this()); Status error = ModuleList::GetSharedModule(module_spec, executable_sp, - &search_paths, nullptr, nullptr); + nullptr, nullptr); if (!error.Fail() && executable_sp) { SetExecutableModule(executable_sp, eLoadDependentsYes); @@ -1854,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) { @@ -2278,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 { @@ -2294,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; @@ -2349,6 +2356,7 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec, // Apply any remappings specified in target.object-map: ModuleSpec module_spec(orig_module_spec); + module_spec.SetTarget(shared_from_this()); PathMappingList &obj_mapping = GetObjectPathMap(); if (std::optional<FileSpec> remapped_obj_file = obj_mapping.RemapPath(orig_module_spec.GetFileSpec().GetPath(), @@ -2407,9 +2415,9 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec, transformed_spec.GetFileSpec().SetDirectory(transformed_dir); transformed_spec.GetFileSpec().SetFilename( module_spec.GetFileSpec().GetFilename()); + transformed_spec.SetTarget(shared_from_this()); error = ModuleList::GetSharedModule(transformed_spec, module_sp, - &search_paths, &old_modules, - &did_create_module); + &old_modules, &did_create_module); } } } @@ -2425,9 +2433,8 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec, // cache. if (module_spec.GetUUID().IsValid()) { // We have a UUID, it is OK to check the global module list... - error = - ModuleList::GetSharedModule(module_spec, module_sp, &search_paths, - &old_modules, &did_create_module); + error = ModuleList::GetSharedModule(module_spec, module_sp, + &old_modules, &did_create_module); } if (!module_sp) { @@ -2435,8 +2442,8 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec, // module in the shared module cache. if (m_platform_sp) { error = m_platform_sp->GetSharedModule( - module_spec, m_process_sp.get(), module_sp, &search_paths, - &old_modules, &did_create_module); + module_spec, m_process_sp.get(), module_sp, &old_modules, + &did_create_module); } else { error = Status::FromErrorString("no platform is currently set"); } @@ -2508,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()) != @@ -3206,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) { @@ -3712,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); @@ -3961,9 +4024,7 @@ void Target::StopHook::GetDescription(Stream &s, return; } - unsigned indent_level = s.GetIndentLevel(); - - s.SetIndentLevel(indent_level + 2); + auto indent_scope = s.MakeIndentScope(); s.Printf("Hook: %" PRIu64 "\n", GetID()); if (m_active) @@ -3977,19 +4038,17 @@ void Target::StopHook::GetDescription(Stream &s, if (m_specifier_sp) { s.Indent(); s.PutCString("Specifier:\n"); - s.SetIndentLevel(indent_level + 4); + auto indent_scope = s.MakeIndentScope(); m_specifier_sp->GetDescription(&s, level); - s.SetIndentLevel(indent_level + 2); } if (m_thread_spec_up) { StreamString tmp; s.Indent("Thread:\n"); m_thread_spec_up->GetDescription(&tmp, level); - s.SetIndentLevel(indent_level + 4); + auto indent_scope = s.MakeIndentScope(); s.Indent(tmp.GetString()); s.PutCString("\n"); - s.SetIndentLevel(indent_level + 2); } GetSubclassDescription(s, level); } @@ -4002,14 +4061,13 @@ void Target::StopHookCommandLine::GetSubclassDescription( s.PutCString(m_commands.GetStringAtIndex(0)); return; } - s.Indent("Commands: \n"); - s.SetIndentLevel(s.GetIndentLevel() + 4); + s.Indent("Commands:\n"); + auto indent_scope = s.MakeIndentScope(4); uint32_t num_commands = m_commands.GetSize(); for (uint32_t i = 0; i < num_commands; i++) { s.Indent(m_commands.GetStringAtIndex(i)); s.PutCString("\n"); } - s.SetIndentLevel(s.GetIndentLevel() - 4); } // Target::StopHookCommandLine @@ -4144,7 +4202,7 @@ void Target::StopHookScripted::GetSubclassDescription( return; s.Indent("Args:\n"); - s.SetIndentLevel(s.GetIndentLevel() + 4); + auto indent_scope = s.MakeIndentScope(4); auto print_one_element = [&s](llvm::StringRef key, StructuredData::Object *object) { @@ -4154,8 +4212,6 @@ void Target::StopHookScripted::GetSubclassDescription( }; as_dict->ForEach(print_one_element); - - s.SetIndentLevel(s.GetIndentLevel() - 4); } static constexpr OptionEnumValueElement g_dynamic_value_types[] = { @@ -4951,7 +5007,7 @@ void TargetProperties::SetStandardErrorPath(llvm::StringRef path) { SourceLanguage TargetProperties::GetLanguage() const { const uint32_t idx = ePropertyLanguage; - return {GetPropertyAtIndexAs<LanguageType>(idx, {})}; + return SourceLanguage{GetPropertyAtIndexAs<LanguageType>(idx, {})}; } llvm::StringRef TargetProperties::GetExpressionPrefixContents() { @@ -5089,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)); @@ -5202,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() { @@ -5236,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; @@ -5271,3 +5341,19 @@ void Target::ClearSectionLoadList() { GetSectionLoadList().Clear(); } void Target::DumpSectionLoadList(Stream &s) { GetSectionLoadList().Dump(s, this); } + +void Target::NotifyBreakpointChanged(Breakpoint &bp, + lldb::BreakpointEventType eventKind) { + if (EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) { + std::shared_ptr<Breakpoint::BreakpointEventData> data_sp = + std::make_shared<Breakpoint::BreakpointEventData>( + eventKind, bp.shared_from_this()); + BroadcastEvent(Target::eBroadcastBitBreakpointChanged, data_sp); + } +} + +void Target::NotifyBreakpointChanged( + Breakpoint &bp, const lldb::EventDataSP &breakpoint_data_sp) { + if (EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) + BroadcastEvent(Target::eBroadcastBitBreakpointChanged, breakpoint_data_sp); +} diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp index 188c250..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); @@ -304,13 +304,9 @@ Status TargetList::CreateTargetInternal(Debugger &debugger, ModuleSP exe_module_sp; if (platform_sp) { - FileSpecList executable_search_paths( - Target::GetDefaultExecutableSearchPaths()); ModuleSpec module_spec(file, arch); - error = platform_sp->ResolveExecutable(module_spec, exe_module_sp, - executable_search_paths.GetSize() - ? &executable_search_paths - : nullptr); + module_spec.SetTarget(target_sp); + error = platform_sp->ResolveExecutable(module_spec, exe_module_sp); } if (error.Success() && exe_module_sp) { @@ -525,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, diff --git a/lldb/source/Target/VerboseTrapFrameRecognizer.cpp b/lldb/source/Target/VerboseTrapFrameRecognizer.cpp deleted file mode 100644 index 03ab58b..0000000 --- a/lldb/source/Target/VerboseTrapFrameRecognizer.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "lldb/Target/VerboseTrapFrameRecognizer.h" - -#include "lldb/Core/Module.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/SymbolContext.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/StackFrameRecognizer.h" -#include "lldb/Target/Target.h" - -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" - -#include "clang/CodeGen/ModuleBuilder.h" - -using namespace llvm; -using namespace lldb; -using namespace lldb_private; - -/// The 0th frame is the artificial inline frame generated to store -/// the verbose_trap message. So, starting with the current parent frame, -/// find the first frame that's not inside of the STL. -static StackFrameSP FindMostRelevantFrame(Thread &selected_thread) { - // Defensive upper-bound of when we stop walking up the frames in - // case we somehow ended up looking at an infinite recursion. - const size_t max_stack_depth = 128; - - // Start at parent frame. - size_t stack_idx = 1; - StackFrameSP most_relevant_frame_sp = - selected_thread.GetStackFrameAtIndex(stack_idx); - - while (most_relevant_frame_sp && stack_idx <= max_stack_depth) { - auto const &sc = - most_relevant_frame_sp->GetSymbolContext(eSymbolContextEverything); - ConstString frame_name = sc.GetFunctionName(); - if (!frame_name) - return nullptr; - - // Found a frame outside of the `std` namespace. That's the - // first frame in user-code that ended up triggering the - // verbose_trap. Hence that's the one we want to display. - if (!frame_name.GetStringRef().starts_with("std::")) - return most_relevant_frame_sp; - - ++stack_idx; - most_relevant_frame_sp = selected_thread.GetStackFrameAtIndex(stack_idx); - } - - return nullptr; -} - -VerboseTrapRecognizedStackFrame::VerboseTrapRecognizedStackFrame( - StackFrameSP most_relevant_frame_sp, std::string stop_desc) - : m_most_relevant_frame(most_relevant_frame_sp) { - m_stop_desc = std::move(stop_desc); -} - -lldb::RecognizedStackFrameSP -VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { - if (frame_sp->GetFrameIndex()) - return {}; - - ThreadSP thread_sp = frame_sp->GetThread(); - ProcessSP process_sp = thread_sp->GetProcess(); - - StackFrameSP most_relevant_frame_sp = FindMostRelevantFrame(*thread_sp); - - if (!most_relevant_frame_sp) { - Log *log = GetLog(LLDBLog::Unwind); - LLDB_LOG( - log, - "Failed to find most relevant frame: Hit unwinding bound (1 frame)!"); - return {}; - } - - SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextEverything); - - if (!sc.block) - return {}; - - // The runtime error is set as the function name in the inlined function info - // of frame #0 by the compiler - const InlineFunctionInfo *inline_info = nullptr; - Block *inline_block = sc.block->GetContainingInlinedBlock(); - - if (!inline_block) - return {}; - - inline_info = sc.block->GetInlinedFunctionInfo(); - - if (!inline_info) - return {}; - - auto func_name = inline_info->GetName().GetStringRef(); - if (func_name.empty()) - return {}; - - static auto trap_regex = - llvm::Regex(llvm::formatv("^{0}\\$(.*)\\$(.*)$", ClangTrapPrefix).str()); - SmallVector<llvm::StringRef, 3> matches; - std::string regex_err_msg; - if (!trap_regex.match(func_name, &matches, ®ex_err_msg)) { - LLDB_LOGF(GetLog(LLDBLog::Unwind), - "Failed to parse match trap regex for '%s': %s", func_name.data(), - regex_err_msg.c_str()); - - return {}; - } - - // For `__clang_trap_msg$category$message$` we expect 3 matches: - // 1. entire string - // 2. category - // 3. message - if (matches.size() != 3) { - LLDB_LOGF(GetLog(LLDBLog::Unwind), - "Unexpected function name format. Expected '<trap prefix>$<trap " - "category>$<trap message>'$ but got: '%s'.", - func_name.data()); - - return {}; - } - - auto category = matches[1]; - auto message = matches[2]; - - std::string stop_reason = - category.empty() ? "<empty category>" : category.str(); - if (!message.empty()) { - stop_reason += ": "; - stop_reason += message.str(); - } - - return std::make_shared<VerboseTrapRecognizedStackFrame>( - most_relevant_frame_sp, std::move(stop_reason)); -} - -lldb::StackFrameSP VerboseTrapRecognizedStackFrame::GetMostRelevantFrame() { - return m_most_relevant_frame; -} - -namespace lldb_private { - -void RegisterVerboseTrapFrameRecognizer(Process &process) { - RegularExpressionSP module_regex_sp = nullptr; - auto symbol_regex_sp = std::make_shared<RegularExpression>( - llvm::formatv("^{0}", ClangTrapPrefix).str()); - - StackFrameRecognizerSP srf_recognizer_sp = - std::make_shared<VerboseTrapFrameRecognizer>(); - - process.GetTarget().GetFrameRecognizerManager().AddRecognizer( - srf_recognizer_sp, module_regex_sp, symbol_regex_sp, - Mangled::ePreferDemangled, false); -} - -} // namespace lldb_private |
