summaryrefslogtreecommitdiff
path: root/lldb/source/Target
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Target')
-rw-r--r--lldb/source/Target/ABI.cpp63
-rw-r--r--lldb/source/Target/AssertFrameRecognizer.cpp168
-rw-r--r--lldb/source/Target/ExecutionContext.cpp2
-rw-r--r--lldb/source/Target/InstrumentationRuntime.cpp2
-rw-r--r--lldb/source/Target/InstrumentationRuntimeStopInfo.cpp2
-rw-r--r--lldb/source/Target/JITLoader.cpp2
-rw-r--r--lldb/source/Target/JITLoaderList.cpp2
-rw-r--r--lldb/source/Target/Language.cpp10
-rw-r--r--lldb/source/Target/LanguageRuntime.cpp17
-rw-r--r--lldb/source/Target/Memory.cpp11
-rw-r--r--lldb/source/Target/MemoryHistory.cpp2
-rw-r--r--lldb/source/Target/MemoryRegionInfo.cpp2
-rw-r--r--lldb/source/Target/ModuleCache.cpp4
-rw-r--r--lldb/source/Target/OperatingSystem.cpp2
-rw-r--r--lldb/source/Target/PathMappingList.cpp2
-rw-r--r--lldb/source/Target/Platform.cpp91
-rw-r--r--lldb/source/Target/Process.cpp523
-rw-r--r--lldb/source/Target/Queue.cpp2
-rw-r--r--lldb/source/Target/QueueItem.cpp2
-rw-r--r--lldb/source/Target/QueueList.cpp2
-rw-r--r--lldb/source/Target/RegisterContext.cpp31
-rw-r--r--lldb/source/Target/RegisterContextUnwind.cpp2215
-rw-r--r--lldb/source/Target/RegisterNumber.cpp2
-rw-r--r--lldb/source/Target/RemoteAwarePlatform.cpp150
-rw-r--r--lldb/source/Target/SectionLoadHistory.cpp2
-rw-r--r--lldb/source/Target/SectionLoadList.cpp4
-rw-r--r--lldb/source/Target/StackFrame.cpp68
-rw-r--r--lldb/source/Target/StackFrameList.cpp126
-rw-r--r--lldb/source/Target/StackFrameRecognizer.cpp63
-rw-r--r--lldb/source/Target/StackID.cpp2
-rw-r--r--lldb/source/Target/StopInfo.cpp14
-rw-r--r--lldb/source/Target/StructuredDataPlugin.cpp2
-rw-r--r--lldb/source/Target/SystemRuntime.cpp2
-rw-r--r--lldb/source/Target/Target.cpp207
-rw-r--r--lldb/source/Target/TargetList.cpp4
-rw-r--r--lldb/source/Target/TargetProperties.td29
-rw-r--r--lldb/source/Target/Thread.cpp551
-rw-r--r--lldb/source/Target/ThreadCollection.cpp2
-rw-r--r--lldb/source/Target/ThreadList.cpp10
-rw-r--r--lldb/source/Target/ThreadPlan.cpp62
-rw-r--r--lldb/source/Target/ThreadPlanBase.cpp28
-rw-r--r--lldb/source/Target/ThreadPlanCallFunction.cpp41
-rw-r--r--lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp10
-rw-r--r--lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp2
-rw-r--r--lldb/source/Target/ThreadPlanCallUserExpression.cpp5
-rw-r--r--lldb/source/Target/ThreadPlanPython.cpp31
-rw-r--r--lldb/source/Target/ThreadPlanRunToAddress.cpp21
-rw-r--r--lldb/source/Target/ThreadPlanShouldStopHere.cpp2
-rw-r--r--lldb/source/Target/ThreadPlanStack.cpp508
-rw-r--r--lldb/source/Target/ThreadPlanStepInRange.cpp48
-rw-r--r--lldb/source/Target/ThreadPlanStepInstruction.cpp44
-rw-r--r--lldb/source/Target/ThreadPlanStepOut.cpp86
-rw-r--r--lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp22
-rw-r--r--lldb/source/Target/ThreadPlanStepOverRange.cpp51
-rw-r--r--lldb/source/Target/ThreadPlanStepRange.cpp64
-rw-r--r--lldb/source/Target/ThreadPlanStepThrough.cpp32
-rw-r--r--lldb/source/Target/ThreadPlanStepUntil.cpp84
-rw-r--r--lldb/source/Target/ThreadPlanTracer.cpp54
-rw-r--r--lldb/source/Target/ThreadSpec.cpp2
-rw-r--r--lldb/source/Target/UnixSignals.cpp8
-rw-r--r--lldb/source/Target/UnwindAssembly.cpp2
-rw-r--r--lldb/source/Target/UnwindLLDB.cpp518
62 files changed, 4875 insertions, 1245 deletions
diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp
index 58396ba70586..4320eb93adfc 100644
--- a/lldb/source/Target/ABI.cpp
+++ b/lldb/source/Target/ABI.cpp
@@ -1,4 +1,4 @@
-//===-- ABI.cpp -------------------------------------------------*- C++ -*-===//
+//===-- ABI.cpp -----------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -17,6 +17,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Utility/Log.h"
#include "llvm/Support/TargetRegistry.h"
+#include <cctype>
using namespace lldb;
using namespace lldb_private;
@@ -41,20 +42,27 @@ ABI::FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch) {
ABI::~ABI() = default;
-bool ABI::GetRegisterInfoByName(ConstString name, RegisterInfo &info) {
+bool RegInfoBasedABI::GetRegisterInfoByName(ConstString name, RegisterInfo &info) {
uint32_t count = 0;
const RegisterInfo *register_info_array = GetRegisterInfoArray(count);
if (register_info_array) {
const char *unique_name_cstr = name.GetCString();
uint32_t i;
for (i = 0; i < count; ++i) {
- if (register_info_array[i].name == unique_name_cstr) {
+ const char *reg_name = register_info_array[i].name;
+ assert(ConstString(reg_name).GetCString() == reg_name &&
+ "register_info_array[i].name not from a ConstString?");
+ if (reg_name == unique_name_cstr) {
info = register_info_array[i];
return true;
}
}
for (i = 0; i < count; ++i) {
- if (register_info_array[i].alt_name == unique_name_cstr) {
+ const char *reg_alt_name = register_info_array[i].alt_name;
+ assert((reg_alt_name == nullptr ||
+ ConstString(reg_alt_name).GetCString() == reg_alt_name) &&
+ "register_info_array[i].alt_name not from a ConstString?");
+ if (reg_alt_name == unique_name_cstr) {
info = register_info_array[i];
return true;
}
@@ -89,10 +97,8 @@ ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type,
if (!persistent_expression_state)
return {};
- auto prefix = persistent_expression_state->GetPersistentVariablePrefix();
ConstString persistent_variable_name =
- persistent_expression_state->GetNextPersistentVariableName(target,
- prefix);
+ persistent_expression_state->GetNextPersistentVariableName();
lldb::ValueObjectSP const_valobj_sp;
@@ -212,7 +218,7 @@ std::unique_ptr<llvm::MCRegisterInfo> ABI::MakeMCRegisterInfo(const ArchSpec &ar
return info_up;
}
-void ABI::AugmentRegisterInfo(RegisterInfo &info) {
+void RegInfoBasedABI::AugmentRegisterInfo(RegisterInfo &info) {
if (info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM &&
info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
return;
@@ -228,3 +234,44 @@ void ABI::AugmentRegisterInfo(RegisterInfo &info) {
if (info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM)
info.kinds[eRegisterKindGeneric] = abi_info.kinds[eRegisterKindGeneric];
}
+
+void MCBasedABI::AugmentRegisterInfo(RegisterInfo &info) {
+ uint32_t eh, dwarf;
+ std::tie(eh, dwarf) = GetEHAndDWARFNums(info.name);
+
+ if (info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM)
+ info.kinds[eRegisterKindEHFrame] = eh;
+ if (info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM)
+ info.kinds[eRegisterKindDWARF] = dwarf;
+ if (info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM)
+ info.kinds[eRegisterKindGeneric] = GetGenericNum(info.name);
+}
+
+std::pair<uint32_t, uint32_t>
+MCBasedABI::GetEHAndDWARFNums(llvm::StringRef name) {
+ std::string mc_name = GetMCName(name.str());
+ for (char &c : mc_name)
+ c = std::toupper(c);
+ int eh = -1;
+ int dwarf = -1;
+ for (unsigned reg = 0; reg < m_mc_register_info_up->getNumRegs(); ++reg) {
+ if (m_mc_register_info_up->getName(reg) == mc_name) {
+ eh = m_mc_register_info_up->getDwarfRegNum(reg, /*isEH=*/true);
+ dwarf = m_mc_register_info_up->getDwarfRegNum(reg, /*isEH=*/false);
+ break;
+ }
+ }
+ return std::pair<uint32_t, uint32_t>(eh == -1 ? LLDB_INVALID_REGNUM : eh,
+ dwarf == -1 ? LLDB_INVALID_REGNUM
+ : dwarf);
+}
+
+void MCBasedABI::MapRegisterName(std::string &name, llvm::StringRef from_prefix,
+ llvm::StringRef to_prefix) {
+ llvm::StringRef name_ref = name;
+ if (!name_ref.consume_front(from_prefix))
+ return;
+ uint64_t _;
+ if (name_ref.empty() || to_integer(name_ref, _, 10))
+ name = (to_prefix + name_ref).str();
+}
diff --git a/lldb/source/Target/AssertFrameRecognizer.cpp b/lldb/source/Target/AssertFrameRecognizer.cpp
new file mode 100644
index 000000000000..d87459ac2fdd
--- /dev/null
+++ b/lldb/source/Target/AssertFrameRecognizer.cpp
@@ -0,0 +1,168 @@
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrameList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+
+#include "lldb/Target/AssertFrameRecognizer.h"
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+namespace lldb_private {
+
+/// Stores a function module spec, symbol name and possibly an alternate symbol
+/// name.
+struct SymbolLocation {
+ FileSpec module_spec;
+ std::vector<ConstString> symbols;
+};
+
+/// Fetches the abort frame location depending on the current platform.
+///
+/// \param[in] os
+/// The target's os type.
+/// \param[in,out] location
+/// The struct that will contain the abort module spec and symbol names.
+/// \return
+/// \b true, if the platform is supported
+/// \b false, otherwise.
+bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) {
+ switch (os) {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ location.module_spec = FileSpec("libsystem_kernel.dylib");
+ location.symbols.push_back(ConstString("__pthread_kill"));
+ break;
+ case llvm::Triple::Linux:
+ location.module_spec = FileSpec("libc.so.6");
+ location.symbols.push_back(ConstString("raise"));
+ location.symbols.push_back(ConstString("__GI_raise"));
+ location.symbols.push_back(ConstString("gsignal"));
+ break;
+ default:
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS");
+ return false;
+ }
+
+ return true;
+}
+
+/// Fetches the assert frame location depending on the current platform.
+///
+/// \param[in] os
+/// The target's os type.
+/// \param[in,out] location
+/// The struct that will contain the assert module spec and symbol names.
+/// \return
+/// \b true, if the platform is supported
+/// \b false, otherwise.
+bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) {
+ switch (os) {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ location.module_spec = FileSpec("libsystem_c.dylib");
+ location.symbols.push_back(ConstString("__assert_rtn"));
+ break;
+ case llvm::Triple::Linux:
+ location.module_spec = FileSpec("libc.so.6");
+ location.symbols.push_back(ConstString("__assert_fail"));
+ location.symbols.push_back(ConstString("__GI___assert_fail"));
+ break;
+ default:
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ LLDB_LOG(log, "AssertFrameRecognizer::GetAssertLocation Unsupported OS");
+ return false;
+ }
+
+ return true;
+}
+
+void RegisterAssertFrameRecognizer(Process *process) {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, [process]() {
+ Target &target = process->GetTarget();
+ llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS();
+ SymbolLocation location;
+
+ if (!GetAbortLocation(os, location))
+ return;
+
+ StackFrameRecognizerManager::AddRecognizer(
+ StackFrameRecognizerSP(new AssertFrameRecognizer()),
+ location.module_spec.GetFilename(), location.symbols,
+ /*first_instruction_only*/ false);
+ });
+}
+
+} // namespace lldb_private
+
+lldb::RecognizedStackFrameSP
+AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
+ ThreadSP thread_sp = frame_sp->GetThread();
+ ProcessSP process_sp = thread_sp->GetProcess();
+ Target &target = process_sp->GetTarget();
+ llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS();
+ SymbolLocation location;
+
+ if (!GetAssertLocation(os, location))
+ return RecognizedStackFrameSP();
+
+ const uint32_t frames_to_fetch = 5;
+ const uint32_t last_frame_index = frames_to_fetch - 1;
+ StackFrameSP prev_frame_sp = nullptr;
+
+ // Fetch most relevant frame
+ for (uint32_t frame_index = 0; frame_index < frames_to_fetch; frame_index++) {
+ prev_frame_sp = thread_sp->GetStackFrameAtIndex(frame_index);
+
+ if (!prev_frame_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ LLDB_LOG(log, "Abort Recognizer: Hit unwinding bound ({1} frames)!",
+ frames_to_fetch);
+ break;
+ }
+
+ SymbolContext sym_ctx =
+ prev_frame_sp->GetSymbolContext(eSymbolContextEverything);
+
+ if (!sym_ctx.module_sp->GetFileSpec().FileEquals(location.module_spec))
+ continue;
+
+ ConstString func_name = sym_ctx.GetFunctionName();
+
+ if (llvm::is_contained(location.symbols, func_name)) {
+ // We go a frame beyond the assert location because the most relevant
+ // frame for the user is the one in which the assert function was called.
+ // If the assert location is the last frame fetched, then it is set as
+ // the most relevant frame.
+
+ StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(
+ std::min(frame_index + 1, last_frame_index));
+
+ // Pass assert location to AbortRecognizedStackFrame to set as most
+ // relevant frame.
+ return lldb::RecognizedStackFrameSP(
+ new AssertRecognizedStackFrame(most_relevant_frame_sp));
+ }
+ }
+
+ return RecognizedStackFrameSP();
+}
+
+AssertRecognizedStackFrame::AssertRecognizedStackFrame(
+ StackFrameSP most_relevant_frame_sp)
+ : m_most_relevant_frame(most_relevant_frame_sp) {
+ m_stop_desc = "hit program assert";
+}
+
+lldb::StackFrameSP AssertRecognizedStackFrame::GetMostRelevantFrame() {
+ return m_most_relevant_frame;
+}
diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp
index a24a098eb300..20932ee63dce 100644
--- a/lldb/source/Target/ExecutionContext.cpp
+++ b/lldb/source/Target/ExecutionContext.cpp
@@ -1,4 +1,4 @@
-//===-- ExecutionContext.cpp ------------------------------------*- C++ -*-===//
+//===-- ExecutionContext.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/InstrumentationRuntime.cpp b/lldb/source/Target/InstrumentationRuntime.cpp
index 4c2eb064fbb0..9f22a1be20cc 100644
--- a/lldb/source/Target/InstrumentationRuntime.cpp
+++ b/lldb/source/Target/InstrumentationRuntime.cpp
@@ -1,4 +1,4 @@
-//===-- InstrumentationRuntime.cpp ------------------------------*- C++ -*-===//
+//===-- InstrumentationRuntime.cpp ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
index f2767ffbff0d..7f82581cc601 100644
--- a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
+++ b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
@@ -1,4 +1,4 @@
-//===-- InstrumentationRuntimeStopInfo.cpp ----------------------*- C++ -*-===//
+//===-- InstrumentationRuntimeStopInfo.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/JITLoader.cpp b/lldb/source/Target/JITLoader.cpp
index e7c13bddcb36..8ff349e063b6 100644
--- a/lldb/source/Target/JITLoader.cpp
+++ b/lldb/source/Target/JITLoader.cpp
@@ -1,4 +1,4 @@
-//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===//
+//===-- JITLoader.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/JITLoaderList.cpp b/lldb/source/Target/JITLoaderList.cpp
index 4d1f06d0843e..f5a90d58d588 100644
--- a/lldb/source/Target/JITLoaderList.cpp
+++ b/lldb/source/Target/JITLoaderList.cpp
@@ -1,4 +1,4 @@
-//===-- JITLoaderList.cpp ---------------------------------------*- C++ -*-===//
+//===-- JITLoaderList.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp
index 10a9ddd56c44..b1a8a9517f3f 100644
--- a/lldb/source/Target/Language.cpp
+++ b/lldb/source/Target/Language.cpp
@@ -1,5 +1,4 @@
-//===-- Language.cpp -------------------------------------------------*- C++
-//-*-===//
+//===-- Language.cpp ------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -140,13 +139,6 @@ Language::GetPossibleFormattersMatches(ValueObject &valobj,
return {};
}
-lldb_private::formatters::StringPrinter::EscapingHelper
-Language::GetStringPrinterEscapingHelper(
- lldb_private::formatters::StringPrinter::GetPrintableElementType
- elem_type) {
- return StringPrinter::GetDefaultEscapingHelper(elem_type);
-}
-
struct language_name_pair {
const char *name;
LanguageType type;
diff --git a/lldb/source/Target/LanguageRuntime.cpp b/lldb/source/Target/LanguageRuntime.cpp
index 32dd805a00b1..58ad70c2b902 100644
--- a/lldb/source/Target/LanguageRuntime.cpp
+++ b/lldb/source/Target/LanguageRuntime.cpp
@@ -1,4 +1,4 @@
-//===-- LanguageRuntime.cpp -------------------------------------*- C++ -*-===//
+//===-- LanguageRuntime.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -78,8 +78,7 @@ void ExceptionSearchFilter::UpdateModuleListIfNeeded() {
}
}
-SearchFilterSP
-ExceptionSearchFilter::DoCopyForBreakpoint(Breakpoint &breakpoint) {
+SearchFilterSP ExceptionSearchFilter::DoCreateCopy() {
return SearchFilterSP(
new ExceptionSearchFilter(TargetSP(), m_language, false));
}
@@ -154,17 +153,17 @@ public:
}
protected:
- BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override {
+ BreakpointResolverSP CopyForBreakpoint(BreakpointSP &breakpoint) override {
BreakpointResolverSP ret_sp(
new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp));
- ret_sp->SetBreakpoint(&breakpoint);
+ ret_sp->SetBreakpoint(breakpoint);
return ret_sp;
}
bool SetActualResolver() {
- ProcessSP process_sp;
- if (m_breakpoint) {
- process_sp = m_breakpoint->GetTarget().GetProcessSP();
+ BreakpointSP breakpoint_sp = GetBreakpoint();
+ if (breakpoint_sp) {
+ ProcessSP process_sp = breakpoint_sp->GetTarget().GetProcessSP();
if (process_sp) {
bool refreash_resolver = !m_actual_resolver_sp;
if (m_language_runtime == nullptr) {
@@ -181,7 +180,7 @@ protected:
if (refreash_resolver && m_language_runtime) {
m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver(
- m_breakpoint, m_catch_bp, m_throw_bp);
+ breakpoint_sp, m_catch_bp, m_throw_bp);
}
} else {
m_actual_resolver_sp.reset();
diff --git a/lldb/source/Target/Memory.cpp b/lldb/source/Target/Memory.cpp
index 7c77cc06eb03..a7ed1a3d97b7 100644
--- a/lldb/source/Target/Memory.cpp
+++ b/lldb/source/Target/Memory.cpp
@@ -1,4 +1,4 @@
-//===-- Memory.cpp ----------------------------------------------*- C++ -*-===//
+//===-- Memory.cpp --------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -116,7 +116,7 @@ bool MemoryCache::RemoveInvalidRange(lldb::addr_t base_addr,
const InvalidRanges::Entry *entry = m_invalid_ranges.GetEntryAtIndex(idx);
if (entry->GetRangeBase() == base_addr &&
entry->GetByteSize() == byte_size)
- return m_invalid_ranges.RemoveEntrtAtIndex(idx);
+ return m_invalid_ranges.RemoveEntryAtIndex(idx);
}
}
return false;
@@ -232,8 +232,13 @@ size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len,
if (process_bytes_read == 0)
return dst_len - bytes_left;
- if (process_bytes_read != cache_line_byte_size)
+ if (process_bytes_read != cache_line_byte_size) {
+ if (process_bytes_read < data_buffer_heap_up->GetByteSize()) {
+ dst_len -= data_buffer_heap_up->GetByteSize() - process_bytes_read;
+ bytes_left = process_bytes_read;
+ }
data_buffer_heap_up->SetByteSize(process_bytes_read);
+ }
m_L2_cache[curr_addr] = DataBufferSP(data_buffer_heap_up.release());
// We have read data and put it into the cache, continue through the
// loop again to get the data out of the cache...
diff --git a/lldb/source/Target/MemoryHistory.cpp b/lldb/source/Target/MemoryHistory.cpp
index 37148e1e72e9..0ebf796a56bb 100644
--- a/lldb/source/Target/MemoryHistory.cpp
+++ b/lldb/source/Target/MemoryHistory.cpp
@@ -1,4 +1,4 @@
-//===-- MemoryHistory.cpp ---------------------------------------*- C++ -*-===//
+//===-- MemoryHistory.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/MemoryRegionInfo.cpp b/lldb/source/Target/MemoryRegionInfo.cpp
index 2c31563786aa..c7fb349ee1cc 100644
--- a/lldb/source/Target/MemoryRegionInfo.cpp
+++ b/lldb/source/Target/MemoryRegionInfo.cpp
@@ -1,4 +1,4 @@
-//===-- MemoryRegionInfo.cpp ------------------------------------*- C++ -*-===//
+//===-- MemoryRegionInfo.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/ModuleCache.cpp b/lldb/source/Target/ModuleCache.cpp
index 124cdacfb4d2..20661a7b7a25 100644
--- a/lldb/source/Target/ModuleCache.cpp
+++ b/lldb/source/Target/ModuleCache.cpp
@@ -1,4 +1,4 @@
-//===--------------------- ModuleCache.cpp ----------------------*- C++ -*-===//
+//===-- ModuleCache.cpp ---------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -169,7 +169,7 @@ ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
return;
}
- m_lock.reset(new lldb_private::LockFile(m_file_up->GetDescriptor()));
+ m_lock = std::make_unique<lldb_private::LockFile>(m_file_up->GetDescriptor());
error = m_lock->WriteLock(0, 1);
if (error.Fail())
error.SetErrorStringWithFormat("Failed to lock file: %s",
diff --git a/lldb/source/Target/OperatingSystem.cpp b/lldb/source/Target/OperatingSystem.cpp
index c78c197db5be..ddffab4553cc 100644
--- a/lldb/source/Target/OperatingSystem.cpp
+++ b/lldb/source/Target/OperatingSystem.cpp
@@ -1,4 +1,4 @@
-//===-- OperatingSystem.cpp -------------------------------------*- C++ -*-===//
+//===-- OperatingSystem.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp
index 58c2c43c9368..b22673f55471 100644
--- a/lldb/source/Target/PathMappingList.cpp
+++ b/lldb/source/Target/PathMappingList.cpp
@@ -1,4 +1,4 @@
-//===-- PathMappingList.cpp -------------------------------------*- C++ -*-===//
+//===-- PathMappingList.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index aaf48f35f921..16787141bee0 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -1,4 +1,4 @@
-//===-- Platform.cpp --------------------------------------------*- C++ -*-===//
+//===-- Platform.cpp ------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -12,9 +12,6 @@
#include <memory>
#include <vector>
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-
#include "lldb/Breakpoint/BreakpointIDList.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
@@ -26,6 +23,7 @@
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/OptionValueFileSpec.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/Property.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -39,8 +37,8 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StructuredData.h"
-
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
// Define these constants from POSIX mman.h rather than include the file so
// that they will be correct even when compiled on Linux.
@@ -93,6 +91,7 @@ PlatformProperties::PlatformProperties() {
module_cache_dir = FileSpec(user_home_dir.c_str());
module_cache_dir.AppendPathComponent(".lldb");
module_cache_dir.AppendPathComponent("module_cache");
+ SetDefaultModuleCacheDirectory(module_cache_dir);
SetModuleCacheDirectory(module_cache_dir);
}
@@ -117,6 +116,14 @@ bool PlatformProperties::SetModuleCacheDirectory(const FileSpec &dir_spec) {
nullptr, ePropertyModuleCacheDirectory, dir_spec);
}
+void PlatformProperties::SetDefaultModuleCacheDirectory(
+ const FileSpec &dir_spec) {
+ auto f_spec_opt = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec(
+ nullptr, false, ePropertyModuleCacheDirectory);
+ assert(f_spec_opt);
+ f_spec_opt->SetDefaultValue(dir_spec);
+}
+
/// Get the native host platform plug-in.
///
/// There should only be one of these for each host that LLDB runs
@@ -421,9 +428,6 @@ void Platform::GetStatus(Stream &strm) {
strm.EOL();
}
- if (GetOSKernelDescription(s))
- strm.Printf(" Kernel: %s\n", s.c_str());
-
if (IsHost()) {
strm.Printf(" Hostname: %s\n", GetHostname());
} else {
@@ -443,6 +447,9 @@ void Platform::GetStatus(Stream &strm) {
if (!specific_info.empty())
strm.Printf("Platform-specific connection: %s\n", specific_info.c_str());
+
+ if (GetOSKernelDescription(s))
+ strm.Printf(" Kernel: %s\n", s.c_str());
}
llvm::VersionTuple Platform::GetOSVersion(Process *process) {
@@ -1144,10 +1151,10 @@ Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
process_sp->SetShouldDetach(false);
// If we didn't have any file actions, the pseudo terminal might have
- // been used where the slave side was given as the file to open for
+ // been used where the secondary side was given as the file to open for
// stdin/out/err after we have already opened the master so we can
// read/write stdin/out/err.
- int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
+ int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor();
if (pty_fd != PseudoTerminal::invalid_fd) {
process_sp->SetSTDIOFileDescriptor(pty_fd);
}
@@ -1400,11 +1407,11 @@ OptionGroupPlatformRSync::SetOptionValue(uint32_t option_idx,
break;
case 'R':
- m_rsync_opts.assign(option_arg);
+ m_rsync_opts.assign(std::string(option_arg));
break;
case 'P':
- m_rsync_prefix.assign(option_arg);
+ m_rsync_prefix.assign(std::string(option_arg));
break;
case 'i':
@@ -1446,7 +1453,7 @@ OptionGroupPlatformSSH::SetOptionValue(uint32_t option_idx,
break;
case 'S':
- m_ssh_opts.assign(option_arg);
+ m_ssh_opts.assign(std::string(option_arg));
break;
default:
@@ -1473,7 +1480,7 @@ lldb_private::Status OptionGroupPlatformCaching::SetOptionValue(
char short_option = (char)GetDefinitions()[option_idx].short_option;
switch (short_option) {
case 'c':
- m_cache_dir.assign(option_arg);
+ m_cache_dir.assign(std::string(option_arg));
break;
default:
@@ -1764,9 +1771,23 @@ Status Platform::UnloadImage(lldb_private::Process *process,
lldb::ProcessSP Platform::ConnectProcess(llvm::StringRef connect_url,
llvm::StringRef plugin_name,
- lldb_private::Debugger &debugger,
- lldb_private::Target *target,
- lldb_private::Status &error) {
+ Debugger &debugger, Target *target,
+ Status &error) {
+ return DoConnectProcess(connect_url, plugin_name, debugger, nullptr, target,
+ error);
+}
+
+lldb::ProcessSP Platform::ConnectProcessSynchronous(
+ llvm::StringRef connect_url, llvm::StringRef plugin_name,
+ Debugger &debugger, Stream &stream, Target *target, Status &error) {
+ return DoConnectProcess(connect_url, plugin_name, debugger, &stream, target,
+ error);
+}
+
+lldb::ProcessSP Platform::DoConnectProcess(llvm::StringRef connect_url,
+ llvm::StringRef plugin_name,
+ Debugger &debugger, Stream *stream,
+ Target *target, Status &error) {
error.Clear();
if (!target) {
@@ -1793,12 +1814,34 @@ lldb::ProcessSP Platform::ConnectProcess(llvm::StringRef connect_url,
lldb::ProcessSP process_sp =
target->CreateProcess(debugger.GetListener(), plugin_name, nullptr);
+
if (!process_sp)
return nullptr;
- error = process_sp->ConnectRemote(&debugger.GetOutputStream(), connect_url);
- if (error.Fail())
+ // If this private method is called with a stream we are synchronous.
+ const bool synchronous = stream != nullptr;
+
+ ListenerSP listener_sp(
+ Listener::MakeListener("lldb.Process.ConnectProcess.hijack"));
+ if (synchronous)
+ process_sp->HijackProcessEvents(listener_sp);
+
+ error = process_sp->ConnectRemote(connect_url);
+ if (error.Fail()) {
+ if (synchronous)
+ process_sp->RestoreProcessEvents();
return nullptr;
+ }
+
+ if (synchronous) {
+ EventSP event_sp;
+ process_sp->WaitForProcessToStop(llvm::None, &event_sp, true, listener_sp,
+ nullptr);
+ process_sp->RestoreProcessEvents();
+ bool pop_process_io_handler = false;
+ Process::HandleProcessStateChangedEvent(event_sp, stream,
+ pop_process_io_handler);
+ }
return process_sp;
}
@@ -1812,6 +1855,7 @@ size_t Platform::ConnectToWaitingProcesses(lldb_private::Debugger &debugger,
size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
BreakpointSite *bp_site) {
ArchSpec arch = target.GetArchitecture();
+ assert(arch.IsValid());
const uint8_t *trap_opcode = nullptr;
size_t trap_opcode_size = 0;
@@ -1855,6 +1899,12 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
}
} break;
+ case llvm::Triple::avr: {
+ static const uint8_t g_hex_opcode[] = {0x98, 0x95};
+ trap_opcode = g_hex_opcode;
+ trap_opcode_size = sizeof(g_hex_opcode);
+ } break;
+
case llvm::Triple::mips:
case llvm::Triple::mips64: {
static const uint8_t g_hex_opcode[] = {0x00, 0x00, 0x00, 0x0d};
@@ -1902,8 +1952,7 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
} break;
default:
- llvm_unreachable(
- "Unhandled architecture in Platform::GetSoftwareBreakpointTrapOpcode");
+ return 0;
}
assert(bp_site);
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 6711dc37eca6..d777a2713911 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -1,4 +1,4 @@
-//===-- Process.cpp ---------------------------------------------*- C++ -*-===//
+//===-- Process.cpp -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -38,6 +38,7 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ABI.h"
+#include "lldb/Target/AssertFrameRecognizer.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/Target/JITLoader.h"
@@ -59,6 +60,7 @@
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanBase.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Target/ThreadPlanStack.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/Log.h"
@@ -118,8 +120,30 @@ public:
enum {
#define LLDB_PROPERTIES_process
#include "TargetPropertiesEnum.inc"
+ ePropertyExperimental,
};
+#define LLDB_PROPERTIES_process_experimental
+#include "TargetProperties.inc"
+
+enum {
+#define LLDB_PROPERTIES_process_experimental
+#include "TargetPropertiesEnum.inc"
+};
+
+class ProcessExperimentalOptionValueProperties : public OptionValueProperties {
+public:
+ ProcessExperimentalOptionValueProperties()
+ : OptionValueProperties(
+ ConstString(Properties::GetExperimentalSettingsName())) {}
+};
+
+ProcessExperimentalProperties::ProcessExperimentalProperties()
+ : Properties(OptionValuePropertiesSP(
+ new ProcessExperimentalOptionValueProperties())) {
+ m_collection_sp->Initialize(g_process_experimental_properties);
+}
+
ProcessProperties::ProcessProperties(lldb_private::Process *process)
: Properties(),
m_process(process) // Can be nullptr for global ProcessProperties
@@ -139,6 +163,14 @@ ProcessProperties::ProcessProperties(lldb_private::Process *process)
ePropertyPythonOSPluginPath,
[this] { m_process->LoadOperatingSystemPlugin(true); });
}
+
+ m_experimental_properties_up =
+ std::make_unique<ProcessExperimentalProperties>();
+ m_collection_sp->AppendProperty(
+ ConstString(Properties::GetExperimentalSettingsName()),
+ ConstString("Experimental settings - setting these won't produce "
+ "errors if the setting is not present."),
+ true, m_experimental_properties_up->GetValueProperties());
}
ProcessProperties::~ProcessProperties() = default;
@@ -227,6 +259,12 @@ bool ProcessProperties::GetWarningsOptimization() const {
nullptr, idx, g_process_properties[idx].default_uint_value != 0);
}
+bool ProcessProperties::GetWarningsUnsupportedLanguage() const {
+ const uint32_t idx = ePropertyWarningUnsupportedLanguage;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_process_properties[idx].default_uint_value != 0);
+}
+
bool ProcessProperties::GetStopOnExec() const {
const uint32_t idx = ePropertyStopOnExec;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
@@ -240,6 +278,29 @@ std::chrono::seconds ProcessProperties::GetUtilityExpressionTimeout() const {
return std::chrono::seconds(value);
}
+bool ProcessProperties::GetOSPluginReportsAllThreads() const {
+ const bool fail_value = true;
+ const Property *exp_property =
+ m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyExperimental);
+ OptionValueProperties *exp_values =
+ exp_property->GetValue()->GetAsProperties();
+ if (!exp_values)
+ return fail_value;
+
+ return exp_values->GetPropertyAtIndexAsBoolean(
+ nullptr, ePropertyOSPluginReportsAllThreads, fail_value);
+}
+
+void ProcessProperties::SetOSPluginReportsAllThreads(bool does_report) {
+ const Property *exp_property =
+ m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyExperimental);
+ OptionValueProperties *exp_values =
+ exp_property->GetValue()->GetAsProperties();
+ if (exp_values)
+ exp_values->SetPropertyAtIndexAsBoolean(
+ nullptr, ePropertyOSPluginReportsAllThreads, does_report);
+}
+
Status ProcessLaunchCommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
@@ -476,7 +537,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
m_mod_id(), m_process_unique_id(0), m_thread_index_id(0),
m_thread_id_to_index_id_map(), m_exit_status(-1), m_exit_string(),
m_exit_status_mutex(), m_thread_mutex(), m_thread_list_real(this),
- m_thread_list(this), m_extended_thread_list(this),
+ m_thread_list(this), m_thread_plans(*this), m_extended_thread_list(this),
m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0),
m_notifications(), m_image_tokens(), m_listener_sp(listener_sp),
m_breakpoint_site_list(), m_dynamic_checkers_up(),
@@ -538,6 +599,8 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
target_sp->GetPlatform()->GetDefaultMemoryCacheLineSize();
if (!value_sp->OptionWasSet() && platform_cache_line_size != 0)
value_sp->SetUInt64Value(platform_cache_line_size);
+
+ RegisterAssertFrameRecognizer(this);
}
Process::~Process() {
@@ -597,6 +660,7 @@ void Process::Finalize() {
m_system_runtime_up.reset();
m_dyld_up.reset();
m_jit_loaders_up.reset();
+ m_thread_plans.Clear();
m_thread_list_real.Destroy();
m_thread_list.Destroy();
m_extended_thread_list.Destroy();
@@ -934,11 +998,17 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp,
Debugger &debugger = process_sp->GetTarget().GetDebugger();
if (debugger.GetTargetList().GetSelectedTarget().get() ==
&process_sp->GetTarget()) {
+ ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread();
+
+ if (!thread_sp || !thread_sp->IsValid())
+ return false;
+
const bool only_threads_with_stop_reason = true;
- const uint32_t start_frame = 0;
+ const uint32_t start_frame = thread_sp->GetSelectedFrameIndex();
const uint32_t num_frames = 1;
const uint32_t num_frames_with_source = 1;
const bool stop_format = true;
+
process_sp->GetStatus(*stream);
process_sp->GetThreadStatus(*stream, only_threads_with_stop_reason,
start_frame, num_frames,
@@ -949,14 +1019,11 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp,
ValueObjectSP valobj_sp = StopInfo::GetCrashingDereference(
curr_thread_stop_info_sp, &crashing_address);
if (valobj_sp) {
- const bool qualify_cxx_base_classes = false;
-
const ValueObject::GetExpressionPathFormat format =
ValueObject::GetExpressionPathFormat::
eGetExpressionPathFormatHonorPointers;
stream->PutCString("Likely cause: ");
- valobj_sp->GetExpressionPath(*stream, qualify_cxx_base_classes,
- format);
+ valobj_sp->GetExpressionPath(*stream, format);
stream->Printf(" accessed 0x%" PRIx64 "\n", crashing_address);
}
}
@@ -1176,9 +1243,12 @@ void Process::UpdateThreadListIfNeeded() {
const uint32_t stop_id = GetStopID();
if (m_thread_list.GetSize(false) == 0 ||
stop_id != m_thread_list.GetStopID()) {
+ bool clear_unused_threads = true;
const StateType state = GetPrivateState();
if (StateIsStoppedState(state, true)) {
std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex());
+ m_thread_list.SetStopID(stop_id);
+
// m_thread_list does have its own mutex, but we need to hold onto the
// mutex between the call to UpdateThreadList(...) and the
// os->UpdateThreadList(...) so it doesn't change on us
@@ -1199,6 +1269,10 @@ void Process::UpdateThreadListIfNeeded() {
size_t num_old_threads = old_thread_list.GetSize(false);
for (size_t i = 0; i < num_old_threads; ++i)
old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread();
+ // See if the OS plugin reports all threads. If it does, then
+ // it is safe to clear unseen thread's plans here. Otherwise we
+ // should preserve them in case they show up again:
+ clear_unused_threads = GetOSPluginReportsAllThreads();
// Turn off dynamic types to ensure we don't run any expressions.
// Objective-C can run an expression to determine if a SBValue is a
@@ -1225,7 +1299,7 @@ void Process::UpdateThreadListIfNeeded() {
target.SetPreferDynamicValue(saved_prefer_dynamic);
} else {
// No OS plug-in, the new thread list is the same as the real thread
- // list
+ // list.
new_thread_list = real_thread_list;
}
@@ -1242,10 +1316,42 @@ void Process::UpdateThreadListIfNeeded() {
m_queue_list_stop_id = GetLastNaturalStopID();
}
}
+ // Now update the plan stack map.
+ // If we do have an OS plugin, any absent real threads in the
+ // m_thread_list have already been removed from the ThreadPlanStackMap.
+ // So any remaining threads are OS Plugin threads, and those we want to
+ // preserve in case they show up again.
+ m_thread_plans.Update(m_thread_list, clear_unused_threads);
}
}
}
+ThreadPlanStack *Process::FindThreadPlans(lldb::tid_t tid) {
+ return m_thread_plans.Find(tid);
+}
+
+bool Process::PruneThreadPlansForTID(lldb::tid_t tid) {
+ return m_thread_plans.PrunePlansForTID(tid);
+}
+
+void Process::PruneThreadPlans() {
+ m_thread_plans.Update(GetThreadList(), true, false);
+}
+
+bool Process::DumpThreadPlansForTID(Stream &strm, lldb::tid_t tid,
+ lldb::DescriptionLevel desc_level,
+ bool internal, bool condense_trivial,
+ bool skip_unreported_plans) {
+ return m_thread_plans.DumpPlansForTID(
+ strm, tid, desc_level, internal, condense_trivial, skip_unreported_plans);
+}
+void Process::DumpThreadPlans(Stream &strm, lldb::DescriptionLevel desc_level,
+ bool internal, bool condense_trivial,
+ bool skip_unreported_plans) {
+ m_thread_plans.DumpPlans(strm, desc_level, internal, condense_trivial,
+ skip_unreported_plans);
+}
+
void Process::UpdateQueueListIfNeeded() {
if (m_system_runtime_up) {
if (m_queue_list.GetSize() == 0 ||
@@ -2643,7 +2749,7 @@ DataExtractor Process::GetAuxvData() { return DataExtractor(); }
JITLoaderList &Process::GetJITLoaders() {
if (!m_jit_loaders_up) {
- m_jit_loaders_up.reset(new JITLoaderList());
+ m_jit_loaders_up = std::make_unique<JITLoaderList>();
JITLoader::LoadPlugins(this, *m_jit_loaders_up);
}
return *m_jit_loaders_up;
@@ -2793,9 +2899,9 @@ Status Process::Attach(ProcessAttachInfo &attach_info) {
match_info.GetProcessInfo() = attach_info;
match_info.SetNameMatchType(NameMatch::Equals);
platform_sp->FindProcesses(match_info, process_infos);
- const uint32_t num_matches = process_infos.GetSize();
+ const uint32_t num_matches = process_infos.size();
if (num_matches == 1) {
- attach_pid = process_infos.GetProcessIDAtIndex(0);
+ attach_pid = process_infos[0].GetProcessID();
// Fall through and attach using the above process ID
} else {
match_info.GetProcessInfo().GetExecutableFile().GetPath(
@@ -2804,7 +2910,7 @@ Status Process::Attach(ProcessAttachInfo &attach_info) {
StreamString s;
ProcessInstanceInfo::DumpTableHeader(s, true, false);
for (size_t i = 0; i < num_matches; i++) {
- process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(
+ process_infos[i].DumpAsTableRow(
s, platform_sp->GetUserIDResolver(), true, false);
}
error.SetErrorStringWithFormat(
@@ -2990,14 +3096,14 @@ void Process::CompleteAttach() {
}
}
-Status Process::ConnectRemote(Stream *strm, llvm::StringRef remote_url) {
+Status Process::ConnectRemote(llvm::StringRef remote_url) {
m_abi_sp.reset();
m_process_input_reader.reset();
// Find the process and its architecture. Make sure it matches the
// architecture of the current Target, and if not adjust it.
- Status error(DoConnectRemote(strm, remote_url));
+ Status error(DoConnectRemote(remote_url));
if (error.Success()) {
if (GetID() != LLDB_INVALID_PROCESS_ID) {
EventSP event_sp;
@@ -3225,6 +3331,10 @@ Status Process::Detach(bool keep_stopped) {
}
Status Process::Destroy(bool force_kill) {
+ // If we've already called Process::Finalize then there's nothing useful to
+ // be done here. Finalize has actually called Destroy already.
+ if (m_finalize_called)
+ return {};
// Tell ourselves we are in the process of destroying the process, so that we
// don't do any unnecessary work that might hinder the destruction. Remember
@@ -3265,8 +3375,8 @@ Status Process::Destroy(bool force_kill) {
DidDestroy();
StopPrivateStateThread();
}
- m_stdio_communication.Disconnect();
m_stdio_communication.StopReadThread();
+ m_stdio_communication.Disconnect();
m_stdin_forward = false;
if (m_process_input_reader) {
@@ -3335,8 +3445,8 @@ bool Process::ShouldBroadcastEvent(Event *event_ptr) {
case eStateExited:
case eStateUnloaded:
m_stdio_communication.SynchronizeWithReadThread();
- m_stdio_communication.Disconnect();
m_stdio_communication.StopReadThread();
+ m_stdio_communication.Disconnect();
m_stdin_forward = false;
LLVM_FALLTHROUGH;
@@ -3889,6 +3999,114 @@ ConstString Process::ProcessEventData::GetFlavor() const {
return ProcessEventData::GetFlavorString();
}
+bool Process::ProcessEventData::ShouldStop(Event *event_ptr,
+ bool &found_valid_stopinfo) {
+ found_valid_stopinfo = false;
+
+ ProcessSP process_sp(m_process_wp.lock());
+ if (!process_sp)
+ return false;
+
+ ThreadList &curr_thread_list = process_sp->GetThreadList();
+ uint32_t num_threads = curr_thread_list.GetSize();
+ uint32_t idx;
+
+ // The actions might change one of the thread's stop_info's opinions about
+ // whether we should stop the process, so we need to query that as we go.
+
+ // One other complication here, is that we try to catch any case where the
+ // target has run (except for expressions) and immediately exit, but if we
+ // get that wrong (which is possible) then the thread list might have
+ // changed, and that would cause our iteration here to crash. We could
+ // make a copy of the thread list, but we'd really like to also know if it
+ // has changed at all, so we make up a vector of the thread ID's and check
+ // what we get back against this list & bag out if anything differs.
+ ThreadList not_suspended_thread_list(process_sp.get());
+ std::vector<uint32_t> thread_index_array(num_threads);
+ uint32_t not_suspended_idx = 0;
+ for (idx = 0; idx < num_threads; ++idx) {
+ lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx);
+
+ /*
+ Filter out all suspended threads, they could not be the reason
+ of stop and no need to perform any actions on them.
+ */
+ if (thread_sp->GetResumeState() != eStateSuspended) {
+ not_suspended_thread_list.AddThread(thread_sp);
+ thread_index_array[not_suspended_idx] = thread_sp->GetIndexID();
+ not_suspended_idx++;
+ }
+ }
+
+ // Use this to track whether we should continue from here. We will only
+ // continue the target running if no thread says we should stop. Of course
+ // if some thread's PerformAction actually sets the target running, then it
+ // doesn't matter what the other threads say...
+
+ bool still_should_stop = false;
+
+ // Sometimes - for instance if we have a bug in the stub we are talking to,
+ // we stop but no thread has a valid stop reason. In that case we should
+ // just stop, because we have no way of telling what the right thing to do
+ // is, and it's better to let the user decide than continue behind their
+ // backs.
+
+ for (idx = 0; idx < not_suspended_thread_list.GetSize(); ++idx) {
+ curr_thread_list = process_sp->GetThreadList();
+ if (curr_thread_list.GetSize() != num_threads) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP |
+ LIBLLDB_LOG_PROCESS));
+ LLDB_LOGF(
+ log,
+ "Number of threads changed from %u to %u while processing event.",
+ num_threads, curr_thread_list.GetSize());
+ break;
+ }
+
+ lldb::ThreadSP thread_sp = not_suspended_thread_list.GetThreadAtIndex(idx);
+
+ if (thread_sp->GetIndexID() != thread_index_array[idx]) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP |
+ LIBLLDB_LOG_PROCESS));
+ LLDB_LOGF(log,
+ "The thread at position %u changed from %u to %u while "
+ "processing event.",
+ idx, thread_index_array[idx], thread_sp->GetIndexID());
+ break;
+ }
+
+ StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
+ if (stop_info_sp && stop_info_sp->IsValid()) {
+ found_valid_stopinfo = true;
+ bool this_thread_wants_to_stop;
+ if (stop_info_sp->GetOverrideShouldStop()) {
+ this_thread_wants_to_stop =
+ stop_info_sp->GetOverriddenShouldStopValue();
+ } else {
+ stop_info_sp->PerformAction(event_ptr);
+ // The stop action might restart the target. If it does, then we
+ // want to mark that in the event so that whoever is receiving it
+ // will know to wait for the running event and reflect that state
+ // appropriately. We also need to stop processing actions, since they
+ // aren't expecting the target to be running.
+
+ // FIXME: we might have run.
+ if (stop_info_sp->HasTargetRunSinceMe()) {
+ SetRestarted(true);
+ break;
+ }
+
+ this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr);
+ }
+
+ if (!still_should_stop)
+ still_should_stop = this_thread_wants_to_stop;
+ }
+ }
+
+ return still_should_stop;
+}
+
void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) {
ProcessSP process_sp(m_process_wp.lock());
@@ -3923,121 +4141,40 @@ void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) {
if (m_interrupted)
return;
- // If we're stopped and haven't restarted, then do the StopInfo actions here:
- if (m_state == eStateStopped && !m_restarted) {
- ThreadList &curr_thread_list = process_sp->GetThreadList();
- uint32_t num_threads = curr_thread_list.GetSize();
- uint32_t idx;
-
- // The actions might change one of the thread's stop_info's opinions about
- // whether we should stop the process, so we need to query that as we go.
-
- // One other complication here, is that we try to catch any case where the
- // target has run (except for expressions) and immediately exit, but if we
- // get that wrong (which is possible) then the thread list might have
- // changed, and that would cause our iteration here to crash. We could
- // make a copy of the thread list, but we'd really like to also know if it
- // has changed at all, so we make up a vector of the thread ID's and check
- // what we get back against this list & bag out if anything differs.
- std::vector<uint32_t> thread_index_array(num_threads);
- for (idx = 0; idx < num_threads; ++idx)
- thread_index_array[idx] =
- curr_thread_list.GetThreadAtIndex(idx)->GetIndexID();
-
- // Use this to track whether we should continue from here. We will only
- // continue the target running if no thread says we should stop. Of course
- // if some thread's PerformAction actually sets the target running, then it
- // doesn't matter what the other threads say...
-
- bool still_should_stop = false;
-
- // Sometimes - for instance if we have a bug in the stub we are talking to,
- // we stop but no thread has a valid stop reason. In that case we should
- // just stop, because we have no way of telling what the right thing to do
- // is, and it's better to let the user decide than continue behind their
- // backs.
-
- bool does_anybody_have_an_opinion = false;
-
- for (idx = 0; idx < num_threads; ++idx) {
- curr_thread_list = process_sp->GetThreadList();
- if (curr_thread_list.GetSize() != num_threads) {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP |
- LIBLLDB_LOG_PROCESS));
- LLDB_LOGF(
- log,
- "Number of threads changed from %u to %u while processing event.",
- num_threads, curr_thread_list.GetSize());
- break;
- }
-
- lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx);
-
- if (thread_sp->GetIndexID() != thread_index_array[idx]) {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP |
- LIBLLDB_LOG_PROCESS));
- LLDB_LOGF(log,
- "The thread at position %u changed from %u to %u while "
- "processing event.",
- idx, thread_index_array[idx], thread_sp->GetIndexID());
- break;
- }
-
- StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
- if (stop_info_sp && stop_info_sp->IsValid()) {
- does_anybody_have_an_opinion = true;
- bool this_thread_wants_to_stop;
- if (stop_info_sp->GetOverrideShouldStop()) {
- this_thread_wants_to_stop =
- stop_info_sp->GetOverriddenShouldStopValue();
- } else {
- stop_info_sp->PerformAction(event_ptr);
- // The stop action might restart the target. If it does, then we
- // want to mark that in the event so that whoever is receiving it
- // will know to wait for the running event and reflect that state
- // appropriately. We also need to stop processing actions, since they
- // aren't expecting the target to be running.
-
- // FIXME: we might have run.
- if (stop_info_sp->HasTargetRunSinceMe()) {
- SetRestarted(true);
- break;
- }
+ // If we're not stopped or have restarted, then skip the StopInfo actions:
+ if (m_state != eStateStopped || m_restarted) {
+ return;
+ }
- this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr);
- }
+ bool does_anybody_have_an_opinion = false;
+ bool still_should_stop = ShouldStop(event_ptr, does_anybody_have_an_opinion);
- if (!still_should_stop)
- still_should_stop = this_thread_wants_to_stop;
- }
- }
+ if (GetRestarted()) {
+ return;
+ }
- if (!GetRestarted()) {
- if (!still_should_stop && does_anybody_have_an_opinion) {
- // We've been asked to continue, so do that here.
+ if (!still_should_stop && does_anybody_have_an_opinion) {
+ // We've been asked to continue, so do that here.
+ SetRestarted(true);
+ // Use the public resume method here, since this is just extending a
+ // public resume.
+ process_sp->PrivateResume();
+ } else {
+ bool hijacked = process_sp->IsHijackedForEvent(eBroadcastBitStateChanged) &&
+ !process_sp->StateChangedIsHijackedForSynchronousResume();
+
+ if (!hijacked) {
+ // If we didn't restart, run the Stop Hooks here.
+ // Don't do that if state changed events aren't hooked up to the
+ // public (or SyncResume) broadcasters. StopHooks are just for
+ // real public stops. They might also restart the target,
+ // so watch for that.
+ process_sp->GetTarget().RunStopHooks();
+ if (process_sp->GetPrivateState() == eStateRunning)
SetRestarted(true);
- // Use the public resume method here, since this is just extending a
- // public resume.
- process_sp->PrivateResume();
- } else {
- bool hijacked =
- process_sp->IsHijackedForEvent(eBroadcastBitStateChanged) &&
- !process_sp->StateChangedIsHijackedForSynchronousResume();
-
- if (!hijacked) {
- // If we didn't restart, run the Stop Hooks here.
- // Don't do that if state changed events aren't hooked up to the
- // public (or SyncResume) broadcasters. StopHooks are just for
- // real public stops. They might also restart the target,
- // so watch for that.
- process_sp->GetTarget().RunStopHooks();
- if (process_sp->GetPrivateState() == eStateRunning)
- SetRestarted(true);
- }
}
}
}
-}
void Process::ProcessEventData::Dump(Stream *s) const {
ProcessSP process_sp(m_process_wp.lock());
@@ -4422,23 +4559,18 @@ protected:
void Process::SetSTDIOFileDescriptor(int fd) {
// First set up the Read Thread for reading/handling process I/O
+ m_stdio_communication.SetConnection(
+ std::make_unique<ConnectionFileDescriptor>(fd, true));
+ if (m_stdio_communication.IsConnected()) {
+ m_stdio_communication.SetReadThreadBytesReceivedCallback(
+ STDIOReadThreadBytesReceived, this);
+ m_stdio_communication.StartReadThread();
- std::unique_ptr<ConnectionFileDescriptor> conn_up(
- new ConnectionFileDescriptor(fd, true));
-
- if (conn_up) {
- m_stdio_communication.SetConnection(conn_up.release());
- if (m_stdio_communication.IsConnected()) {
- m_stdio_communication.SetReadThreadBytesReceivedCallback(
- STDIOReadThreadBytesReceived, this);
- m_stdio_communication.StartReadThread();
+ // Now read thread is set up, set up input reader.
- // Now read thread is set up, set up input reader.
-
- if (!m_process_input_reader)
- m_process_input_reader =
- std::make_shared<IOHandlerProcessSTDIO>(this, fd);
- }
+ if (!m_process_input_reader)
+ m_process_input_reader =
+ std::make_shared<IOHandlerProcessSTDIO>(this, fd);
}
}
@@ -4460,7 +4592,8 @@ bool Process::PushProcessIOHandler() {
// existing IOHandler that potentially provides the user interface (e.g.
// the IOHandler for Editline).
bool cancel_top_handler = !m_mod_id.IsRunningUtilityFunction();
- GetTarget().GetDebugger().PushIOHandler(io_handler_sp, cancel_top_handler);
+ GetTarget().GetDebugger().RunIOHandlerAsync(io_handler_sp,
+ cancel_top_handler);
return true;
}
return false;
@@ -4469,7 +4602,7 @@ bool Process::PushProcessIOHandler() {
bool Process::PopProcessIOHandler() {
IOHandlerSP io_handler_sp(m_process_input_reader);
if (io_handler_sp)
- return GetTarget().GetDebugger().PopIOHandler(io_handler_sp);
+ return GetTarget().GetDebugger().RemoveIOHandler(io_handler_sp);
return false;
}
@@ -4553,13 +4686,27 @@ GetExpressionTimeout(const EvaluateExpressionOptions &options,
}
static llvm::Optional<ExpressionResults>
-HandleStoppedEvent(Thread &thread, const ThreadPlanSP &thread_plan_sp,
+HandleStoppedEvent(lldb::tid_t thread_id, const ThreadPlanSP &thread_plan_sp,
RestorePlanState &restorer, const EventSP &event_sp,
EventSP &event_to_broadcast_sp,
- const EvaluateExpressionOptions &options, bool handle_interrupts) {
+ const EvaluateExpressionOptions &options,
+ bool handle_interrupts) {
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS);
- ThreadPlanSP plan = thread.GetCompletedPlan();
+ ThreadSP thread_sp = thread_plan_sp->GetTarget()
+ .GetProcessSP()
+ ->GetThreadList()
+ .FindThreadByID(thread_id);
+ if (!thread_sp) {
+ LLDB_LOG(log,
+ "The thread on which we were running the "
+ "expression: tid = {0}, exited while "
+ "the expression was running.",
+ thread_id);
+ return eExpressionThreadVanished;
+ }
+
+ ThreadPlanSP plan = thread_sp->GetCompletedPlan();
if (plan == thread_plan_sp && plan->PlanSucceeded()) {
LLDB_LOG(log, "execution completed successfully");
@@ -4569,7 +4716,7 @@ HandleStoppedEvent(Thread &thread, const ThreadPlanSP &thread_plan_sp,
return eExpressionCompleted;
}
- StopInfoSP stop_info_sp = thread.GetStopInfo();
+ StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint &&
stop_info_sp->ShouldNotify(event_sp.get())) {
LLDB_LOG(log, "stopped for breakpoint: {0}.", stop_info_sp->GetDescription());
@@ -4631,6 +4778,10 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
return eExpressionSetupError;
}
+ // Record the thread's id so we can tell when a thread we were using
+ // to run the expression exits during the expression evaluation.
+ lldb::tid_t expr_thread_id = thread->GetID();
+
// We need to change some of the thread plan attributes for the thread plan
// runner. This will restore them when we are done:
@@ -4775,7 +4926,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
LLDB_LOGF(log,
"Process::RunThreadPlan(): Resuming thread %u - 0x%4.4" PRIx64
" to run thread plan \"%s\".",
- thread->GetIndexID(), thread->GetID(), s.GetData());
+ thread_idx_id, expr_thread_id, s.GetData());
}
bool got_event;
@@ -4975,33 +5126,23 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
switch (stop_state) {
case lldb::eStateStopped: {
- // We stopped, figure out what we are going to do now.
- ThreadSP thread_sp =
- GetThreadList().FindThreadByIndexID(thread_idx_id);
- if (!thread_sp) {
- // Ooh, our thread has vanished. Unlikely that this was
- // successful execution...
- LLDB_LOGF(log,
- "Process::RunThreadPlan(): execution completed "
- "but our thread (index-id=%u) has vanished.",
- thread_idx_id);
- return_value = eExpressionInterrupted;
- } else if (Process::ProcessEventData::GetRestartedFromEvent(
- event_sp.get())) {
+ if (Process::ProcessEventData::GetRestartedFromEvent(
+ event_sp.get())) {
// If we were restarted, we just need to go back up to fetch
// another event.
- if (log) {
- LLDB_LOGF(log, "Process::RunThreadPlan(): Got a stop and "
- "restart, so we'll continue waiting.");
- }
+ LLDB_LOGF(log, "Process::RunThreadPlan(): Got a stop and "
+ "restart, so we'll continue waiting.");
keep_going = true;
do_resume = false;
handle_running_event = true;
} else {
const bool handle_interrupts = true;
return_value = *HandleStoppedEvent(
- *thread, thread_plan_sp, thread_plan_restorer, event_sp,
- event_to_broadcast_sp, options, handle_interrupts);
+ expr_thread_id, thread_plan_sp, thread_plan_restorer,
+ event_sp, event_to_broadcast_sp, options,
+ handle_interrupts);
+ if (return_value == eExpressionThreadVanished)
+ keep_going = false;
}
} break;
@@ -5123,8 +5264,9 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
// job. Check that here:
const bool handle_interrupts = false;
if (auto result = HandleStoppedEvent(
- *thread, thread_plan_sp, thread_plan_restorer, event_sp,
- event_to_broadcast_sp, options, handle_interrupts)) {
+ expr_thread_id, thread_plan_sp, thread_plan_restorer,
+ event_sp, event_to_broadcast_sp, options,
+ handle_interrupts)) {
return_value = *result;
back_to_top = false;
break;
@@ -5196,6 +5338,13 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
m_public_state.SetValueNoLock(old_state);
}
+ // If our thread went away on us, we need to get out of here without
+ // doing any more work. We don't have to clean up the thread plan, that
+ // will have happened when the Thread was destroyed.
+ if (return_value == eExpressionThreadVanished) {
+ return return_value;
+ }
+
if (return_value != eExpressionCompleted && log) {
// Print a backtrace into the log so we can figure out where we are:
StreamString s;
@@ -5384,7 +5533,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
}
const char *Process::ExecutionResultAsCString(ExpressionResults result) {
- const char *result_name;
+ const char *result_name = "<unknown>";
switch (result) {
case eExpressionCompleted:
@@ -5414,6 +5563,8 @@ const char *Process::ExecutionResultAsCString(ExpressionResults result) {
case eExpressionStoppedForDebug:
result_name = "eExpressionStoppedForDebug";
break;
+ case eExpressionThreadVanished:
+ result_name = "eExpressionThreadVanished";
}
return result_name;
}
@@ -5662,9 +5813,6 @@ void Process::PrintWarning(uint64_t warning_type, const void *repeat_key,
StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream();
if (!stream_sp)
return;
- if (warning_type == eWarningsOptimization && !GetWarningsOptimization()) {
- return;
- }
if (repeat_key != nullptr) {
WarningsCollection::iterator it = m_warnings_issued.find(warning_type);
@@ -5689,8 +5837,11 @@ void Process::PrintWarning(uint64_t warning_type, const void *repeat_key,
}
void Process::PrintWarningOptimization(const SymbolContext &sc) {
- if (GetWarningsOptimization() && sc.module_sp &&
- !sc.module_sp->GetFileSpec().GetFilename().IsEmpty() && sc.function &&
+ if (!GetWarningsOptimization())
+ return;
+ if (!sc.module_sp)
+ return;
+ if (!sc.module_sp->GetFileSpec().GetFilename().IsEmpty() && sc.function &&
sc.function->GetIsOptimized()) {
PrintWarning(Process::Warnings::eWarningsOptimization, sc.module_sp.get(),
"%s was compiled with optimization - stepping may behave "
@@ -5699,6 +5850,25 @@ void Process::PrintWarningOptimization(const SymbolContext &sc) {
}
}
+void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) {
+ if (!GetWarningsUnsupportedLanguage())
+ return;
+ if (!sc.module_sp)
+ return;
+ LanguageType language = sc.GetLanguage();
+ if (language == eLanguageTypeUnknown)
+ return;
+ auto type_system_or_err = sc.module_sp->GetTypeSystemForLanguage(language);
+ if (auto err = type_system_or_err.takeError()) {
+ llvm::consumeError(std::move(err));
+ PrintWarning(Process::Warnings::eWarningsUnsupportedLanguage,
+ sc.module_sp.get(),
+ "This version of LLDB has no plugin for the %s language. "
+ "Inspection of frame variables will be limited.\n",
+ Language::GetNameForLanguageType(language));
+ }
+}
+
bool Process::GetProcessInfo(ProcessInstanceInfo &info) {
info.Clear();
@@ -5749,12 +5919,12 @@ size_t Process::AddImageToken(lldb::addr_t image_ptr) {
lldb::addr_t Process::GetImagePtrFromToken(size_t token) const {
if (token < m_image_tokens.size())
return m_image_tokens[token];
- return LLDB_INVALID_IMAGE_TOKEN;
+ return LLDB_INVALID_ADDRESS;
}
void Process::ResetImageToken(size_t token) {
if (token < m_image_tokens.size())
- m_image_tokens[token] = LLDB_INVALID_IMAGE_TOKEN;
+ m_image_tokens[token] = LLDB_INVALID_ADDRESS;
}
Address
@@ -5771,12 +5941,11 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr,
if (!default_stop_addr.IsValid())
return retval;
- ExecutionContext exe_ctx(this);
const char *plugin_name = nullptr;
const char *flavor = nullptr;
const bool prefer_file_cache = true;
disassembler_sp = Disassembler::DisassembleRange(
- target.GetArchitecture(), plugin_name, flavor, exe_ctx, range_bounds,
+ target.GetArchitecture(), plugin_name, flavor, GetTarget(), range_bounds,
prefer_file_cache);
if (disassembler_sp)
insn_list = &disassembler_sp->GetInstructionList();
diff --git a/lldb/source/Target/Queue.cpp b/lldb/source/Target/Queue.cpp
index fc2a93dbe899..67eae6327673 100644
--- a/lldb/source/Target/Queue.cpp
+++ b/lldb/source/Target/Queue.cpp
@@ -1,4 +1,4 @@
-//===-- Queue.cpp -----------------------------------------------*- C++ -*-===//
+//===-- Queue.cpp ---------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/QueueItem.cpp b/lldb/source/Target/QueueItem.cpp
index 47ff9e028fcb..740b2a6771a2 100644
--- a/lldb/source/Target/QueueItem.cpp
+++ b/lldb/source/Target/QueueItem.cpp
@@ -1,4 +1,4 @@
-//===-- QueueItem.cpp -------------------------------------------*- C++ -*-===//
+//===-- QueueItem.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/QueueList.cpp b/lldb/source/Target/QueueList.cpp
index 796825135187..84ec24f03f51 100644
--- a/lldb/source/Target/QueueList.cpp
+++ b/lldb/source/Target/QueueList.cpp
@@ -1,4 +1,4 @@
-//===-- QueueList.cpp -------------------------------------------*- C++ -*-===//
+//===-- QueueList.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp
index f29cf435d028..cdc7653cea6d 100644
--- a/lldb/source/Target/RegisterContext.cpp
+++ b/lldb/source/Target/RegisterContext.cpp
@@ -1,4 +1,4 @@
-//===-- RegisterContext.cpp -------------------------------------*- C++ -*-===//
+//===-- RegisterContext.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -274,6 +274,24 @@ uint32_t RegisterContext::SetHardwareBreakpoint(lldb::addr_t addr,
return LLDB_INVALID_INDEX32;
}
+// Used when parsing DWARF and EH frame information and any other object file
+// sections that contain register numbers in them.
+uint32_t
+RegisterContext::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) {
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert(kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
bool RegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) { return false; }
uint32_t RegisterContext::NumSupportedHardwareWatchpoints() { return 0; }
@@ -397,6 +415,17 @@ Status RegisterContext::WriteRegisterValueToMemory(
return error;
}
+lldb::ByteOrder RegisterContext::GetByteOrder() {
+ // Get the target process whose privileged thread was used for the register
+ // read.
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
+ lldb_private::Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
bool RegisterContext::ReadAllRegisterValues(
lldb_private::RegisterCheckpoint &reg_checkpoint) {
return ReadAllRegisterValues(reg_checkpoint.GetData());
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
new file mode 100644
index 000000000000..f33f4180be23
--- /dev/null
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -0,0 +1,2215 @@
+//===-- RegisterContextUnwind.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/RegisterContextUnwind.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/ArmUnwindInfo.h"
+#include "lldb/Symbol/CallFrameInfo.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/lldb-private.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static ConstString GetSymbolOrFunctionName(const SymbolContext &sym_ctx) {
+ if (sym_ctx.symbol)
+ return sym_ctx.symbol->GetName();
+ else if (sym_ctx.function)
+ return sym_ctx.function->GetName();
+ return ConstString();
+}
+
+RegisterContextUnwind::RegisterContextUnwind(Thread &thread,
+ const SharedPtr &next_frame,
+ SymbolContext &sym_ctx,
+ uint32_t frame_number,
+ UnwindLLDB &unwind_lldb)
+ : RegisterContext(thread, frame_number), m_thread(thread),
+ m_fast_unwind_plan_sp(), m_full_unwind_plan_sp(),
+ m_fallback_unwind_plan_sp(), m_all_registers_available(false),
+ m_frame_type(-1), m_cfa(LLDB_INVALID_ADDRESS),
+ m_afa(LLDB_INVALID_ADDRESS), m_start_pc(),
+ m_current_pc(), m_current_offset(0), m_current_offset_backed_up_one(0),
+ m_sym_ctx(sym_ctx), m_sym_ctx_valid(false), m_frame_number(frame_number),
+ m_registers(), m_parent_unwind(unwind_lldb) {
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+
+ if (IsFrameZero()) {
+ InitializeZerothFrame();
+ } else {
+ InitializeNonZerothFrame();
+ }
+
+ // This same code exists over in the GetFullUnwindPlanForFrame() but it may
+ // not have been executed yet
+ if (IsFrameZero() || next_frame->m_frame_type == eTrapHandlerFrame ||
+ next_frame->m_frame_type == eDebuggerFrame) {
+ m_all_registers_available = true;
+ }
+}
+
+bool RegisterContextUnwind::IsUnwindPlanValidForCurrentPC(
+ lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset) {
+ if (!unwind_plan_sp)
+ return false;
+
+ // check if m_current_pc is valid
+ if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) {
+ // yes - current offset can be used as is
+ valid_pc_offset = m_current_offset;
+ return true;
+ }
+
+ // if m_current_offset <= 0, we've got nothing else to try
+ if (m_current_offset <= 0)
+ return false;
+
+ // check pc - 1 to see if it's valid
+ Address pc_minus_one(m_current_pc);
+ pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1);
+ if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one)) {
+ // *valid_pc_offset = m_current_offset - 1;
+ valid_pc_offset = m_current_pc.GetOffset() - 1;
+ return true;
+ }
+
+ return false;
+}
+
+// Initialize a RegisterContextUnwind which is the first frame of a stack -- the
+// zeroth frame or currently executing frame.
+
+void RegisterContextUnwind::InitializeZerothFrame() {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext();
+
+ if (reg_ctx_sp.get() == nullptr) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("frame does not have a register context");
+ return;
+ }
+
+ addr_t current_pc = reg_ctx_sp->GetPC();
+
+ if (current_pc == LLDB_INVALID_ADDRESS) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("frame does not have a pc");
+ return;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ // (which would be a no-op in frame 0 where we get it from the register set,
+ // but still a good idea to make the call here for other ABIs that may
+ // exist.)
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ current_pc = abi->FixCodeAddress(current_pc);
+
+ // Initialize m_current_pc, an Address object, based on current_pc, an
+ // addr_t.
+ m_current_pc.SetLoadAddress(current_pc, &process->GetTarget());
+
+ // If we don't have a Module for some reason, we're not going to find
+ // symbol/function information - just stick in some reasonable defaults and
+ // hope we can unwind past this frame.
+ ModuleSP pc_module_sp(m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp) {
+ UnwindLogMsg("using architectural default unwind method");
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
+
+ if (m_sym_ctx.symbol) {
+ UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
+ current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ } else if (m_sym_ctx.function) {
+ UnwindLogMsg("with pc value of 0x%" PRIx64 ", function name is '%s'",
+ current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ } else {
+ UnwindLogMsg("with pc value of 0x%" PRIx64
+ ", no symbol/function name is known.",
+ current_pc);
+ }
+
+ if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
+ m_frame_type = eTrapHandlerFrame;
+ } else {
+ // FIXME: Detect eDebuggerFrame here.
+ m_frame_type = eNormalFrame;
+ }
+
+ // If we were able to find a symbol/function, set addr_range to the bounds of
+ // that symbol/function. else treat the current pc value as the start_pc and
+ // record no offset.
+ if (addr_range.GetBaseAddress().IsValid()) {
+ m_start_pc = addr_range.GetBaseAddress();
+ if (m_current_pc.GetSection() == m_start_pc.GetSection()) {
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ } else if (m_current_pc.GetModule() == m_start_pc.GetModule()) {
+ // This means that whatever symbol we kicked up isn't really correct ---
+ // we should not cross section boundaries ... We really should NULL out
+ // the function/symbol in this case unless there is a bad assumption here
+ // due to inlined functions?
+ m_current_offset =
+ m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
+ }
+ m_current_offset_backed_up_one = m_current_offset;
+ } else {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ // We've set m_frame_type and m_sym_ctx before these calls.
+
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame();
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame();
+
+ UnwindPlan::RowSP active_row;
+ lldb::RegisterKind row_register_kind = eRegisterKindGeneric;
+ if (m_full_unwind_plan_sp &&
+ m_full_unwind_plan_sp->PlanValidAtAddress(m_current_pc)) {
+ active_row =
+ m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind();
+ if (active_row.get() && log) {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread,
+ m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg("%s", active_row_strm.GetData());
+ }
+ }
+
+ if (!active_row.get()) {
+ UnwindLogMsg("could not find an unwindplan row for this frame's pc");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) {
+ // Try the fall back unwind plan since the
+ // full unwind plan failed.
+ FuncUnwindersSP func_unwinders_sp;
+ UnwindPlanSP call_site_unwind_plan;
+ bool cfa_status = false;
+
+ if (m_sym_ctx_valid) {
+ func_unwinders_sp =
+ pc_module_sp->GetUnwindTable().GetFuncUnwindersContainingAddress(
+ m_current_pc, m_sym_ctx);
+ }
+
+ if (func_unwinders_sp.get() != nullptr)
+ call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(
+ process->GetTarget(), m_thread);
+
+ if (call_site_unwind_plan.get() != nullptr) {
+ m_fallback_unwind_plan_sp = call_site_unwind_plan;
+ if (TryFallbackUnwindPlan())
+ cfa_status = true;
+ }
+ if (!cfa_status) {
+ UnwindLogMsg("could not read CFA value for first frame.");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ } else
+ ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa);
+
+ UnwindLogMsg("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64
+ " afa is 0x%" PRIx64 " using %s UnwindPlan",
+ (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()),
+ (uint64_t)m_cfa,
+ (uint64_t)m_afa,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+}
+
+// Initialize a RegisterContextUnwind for the non-zeroth frame -- rely on the
+// RegisterContextUnwind "below" it to provide things like its current pc value.
+
+void RegisterContextUnwind::InitializeNonZerothFrame() {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ if (IsFrameZero()) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("non-zeroth frame tests positive for IsFrameZero -- that "
+ "shouldn't happen.");
+ return;
+ }
+
+ if (!GetNextFrame().get() || !GetNextFrame()->IsValid()) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("Could not get next frame, marking this frame as invalid.");
+ return;
+ }
+ if (!m_thread.GetRegisterContext()) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("Could not get register context for this thread, marking this "
+ "frame as invalid.");
+ return;
+ }
+
+ addr_t pc;
+ if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) {
+ UnwindLogMsg("could not get pc value");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+
+ if (log) {
+ UnwindLogMsg("pc = 0x%" PRIx64, pc);
+ addr_t reg_val;
+ if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
+ UnwindLogMsg("fp = 0x%" PRIx64, reg_val);
+ if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
+ UnwindLogMsg("sp = 0x%" PRIx64, reg_val);
+ }
+
+ // A pc of 0x0 means it's the end of the stack crawl unless we're above a trap
+ // handler function
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() &&
+ GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
+ if (pc == 0 || pc == 0x1) {
+ if (!above_trap_handler) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("this frame has a pc of 0x0");
+ return;
+ }
+ }
+
+ const bool allow_section_end = true;
+ m_current_pc.SetLoadAddress(pc, &process->GetTarget(), allow_section_end);
+
+ // If we don't have a Module for some reason, we're not going to find
+ // symbol/function information - just stick in some reasonable defaults and
+ // hope we can unwind past this frame. If we're above a trap handler,
+ // we may be at a bogus address because we jumped through a bogus function
+ // pointer and trapped, so don't force the arch default unwind plan in that
+ // case.
+ ModuleSP pc_module_sp(m_current_pc.GetModule());
+ if ((!m_current_pc.IsValid() || !pc_module_sp) &&
+ above_trap_handler == false) {
+ UnwindLogMsg("using architectural default unwind method");
+
+ // Test the pc value to see if we know it's in an unmapped/non-executable
+ // region of memory.
+ uint32_t permissions;
+ if (process->GetLoadAddressPermissions(pc, permissions) &&
+ (permissions & ePermissionsExecutable) == 0) {
+ // If this is the second frame off the stack, we may have unwound the
+ // first frame incorrectly. But using the architecture default unwind
+ // plan may get us back on track -- albeit possibly skipping a real
+ // frame. Give this frame a clearly-invalid pc and see if we can get any
+ // further.
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() &&
+ GetNextFrame()->IsFrameZero()) {
+ UnwindLogMsg("had a pc of 0x%" PRIx64 " which is not in executable "
+ "memory but on frame 1 -- "
+ "allowing it once.",
+ (uint64_t)pc);
+ m_frame_type = eSkipFrame;
+ } else {
+ // anywhere other than the second frame, a non-executable pc means
+ // we're off in the weeds -- stop now.
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("pc is in a non-executable section of memory and this "
+ "isn't the 2nd frame in the stack walk.");
+ return;
+ }
+ }
+
+ if (abi) {
+ m_fast_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp =
+ std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp);
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ m_all_registers_available = false;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind();
+ UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
+ if (row.get()) {
+ if (!ReadFrameAddress(row_register_kind, row->GetCFAValue(), m_cfa)) {
+ UnwindLogMsg("failed to get cfa value");
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNotAValidFrame;
+ }
+ return;
+ }
+
+ ReadFrameAddress(row_register_kind, row->GetAFAValue(), m_afa);
+
+ // A couple of sanity checks..
+ if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == 0 || m_cfa == 1) {
+ UnwindLogMsg("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // m_cfa should point into the stack memory; if we can query memory
+ // region permissions, see if the memory is allocated & readable.
+ if (process->GetLoadAddressPermissions(m_cfa, permissions) &&
+ (permissions & ePermissionsReadable) == 0) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg(
+ "the CFA points to a region of memory that is not readable");
+ return;
+ }
+ } else {
+ UnwindLogMsg("could not find a row for function offset zero");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (CheckIfLoopingStack()) {
+ TryFallbackUnwindPlan();
+ if (CheckIfLoopingStack()) {
+ UnwindLogMsg("same CFA address as next frame, assuming the unwind is "
+ "looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ UnwindLogMsg("initialized frame cfa is 0x%" PRIx64 " afa is 0x%" PRIx64,
+ (uint64_t)m_cfa, (uint64_t)m_afa);
+ return;
+ }
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("could not find any symbol for this pc, or a default unwind "
+ "plan, to continue unwind.");
+ return;
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
+
+ if (m_sym_ctx.symbol) {
+ UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'", pc,
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ } else if (m_sym_ctx.function) {
+ UnwindLogMsg("with pc value of 0x%" PRIx64 ", function name is '%s'", pc,
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ } else {
+ UnwindLogMsg("with pc value of 0x%" PRIx64
+ ", no symbol/function name is known.",
+ pc);
+ }
+
+ bool decr_pc_and_recompute_addr_range;
+
+ if (!m_sym_ctx_valid) {
+ // Always decrement and recompute if the symbol lookup failed
+ decr_pc_and_recompute_addr_range = true;
+ } else if (GetNextFrame()->m_frame_type == eTrapHandlerFrame ||
+ GetNextFrame()->m_frame_type == eDebuggerFrame) {
+ // Don't decrement if we're "above" an asynchronous event like
+ // sigtramp.
+ decr_pc_and_recompute_addr_range = false;
+ } else if (!addr_range.GetBaseAddress().IsValid() ||
+ addr_range.GetBaseAddress().GetSection() != m_current_pc.GetSection() ||
+ addr_range.GetBaseAddress().GetOffset() != m_current_pc.GetOffset()) {
+ // If our "current" pc isn't the start of a function, no need
+ // to decrement and recompute.
+ decr_pc_and_recompute_addr_range = false;
+ } else if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
+ // Signal dispatch may set the return address of the handler it calls to
+ // point to the first byte of a return trampoline (like __kernel_rt_sigreturn),
+ // so do not decrement and recompute if the symbol we already found is a trap
+ // handler.
+ decr_pc_and_recompute_addr_range = false;
+ } else {
+ // Decrement to find the function containing the call.
+ decr_pc_and_recompute_addr_range = true;
+ }
+
+ // We need to back up the pc by 1 byte and re-search for the Symbol to handle
+ // the case where the "saved pc" value is pointing to the next function, e.g.
+ // if a function ends with a CALL instruction.
+ // FIXME this may need to be an architectural-dependent behavior; if so we'll
+ // need to add a member function
+ // to the ABI plugin and consult that.
+ if (decr_pc_and_recompute_addr_range) {
+ UnwindLogMsg("Backing up the pc value of 0x%" PRIx64
+ " by 1 and re-doing symbol lookup; old symbol was %s",
+ pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ Address temporary_pc;
+ temporary_pc.SetLoadAddress(pc - 1, &process->GetTarget());
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = temporary_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
+
+ UnwindLogMsg("Symbol is now %s",
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ }
+
+ // If we were able to find a symbol/function, set addr_range_ptr to the
+ // bounds of that symbol/function. else treat the current pc value as the
+ // start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid()) {
+ m_start_pc = addr_range.GetBaseAddress();
+ m_current_offset = pc - m_start_pc.GetLoadAddress(&process->GetTarget());
+ m_current_offset_backed_up_one = m_current_offset;
+ if (decr_pc_and_recompute_addr_range &&
+ m_current_offset_backed_up_one > 0) {
+ m_current_offset_backed_up_one--;
+ if (m_sym_ctx_valid) {
+ m_current_pc.SetLoadAddress(pc - 1, &process->GetTarget());
+ }
+ }
+ } else {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
+ m_frame_type = eTrapHandlerFrame;
+ } else {
+ // FIXME: Detect eDebuggerFrame here.
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ }
+
+ // We've set m_frame_type and m_sym_ctx before this call.
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame();
+
+ UnwindPlan::RowSP active_row;
+ RegisterKind row_register_kind = eRegisterKindGeneric;
+
+ // Try to get by with just the fast UnwindPlan if possible - the full
+ // UnwindPlan may be expensive to get (e.g. if we have to parse the entire
+ // eh_frame section of an ObjectFile for the first time.)
+
+ if (m_fast_unwind_plan_sp &&
+ m_fast_unwind_plan_sp->PlanValidAtAddress(m_current_pc)) {
+ active_row =
+ m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+ row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind();
+ PropagateTrapHandlerFlagFromUnwindPlan(m_fast_unwind_plan_sp);
+ if (active_row.get() && log) {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread,
+ m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg("active row: %s", active_row_strm.GetData());
+ }
+ } else {
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame();
+ int valid_offset = -1;
+ if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset(valid_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind();
+ PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
+ if (active_row.get() && log) {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(),
+ &m_thread,
+ m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg("active row: %s", active_row_strm.GetData());
+ }
+ }
+ }
+
+ if (!active_row.get()) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("could not find unwind row for this pc");
+ return;
+ }
+
+ if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) {
+ UnwindLogMsg("failed to get cfa");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa);
+
+ UnwindLogMsg("m_cfa = 0x%" PRIx64 " m_afa = 0x%" PRIx64, m_cfa, m_afa);
+
+ if (CheckIfLoopingStack()) {
+ TryFallbackUnwindPlan();
+ if (CheckIfLoopingStack()) {
+ UnwindLogMsg("same CFA address as next frame, assuming the unwind is "
+ "looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ UnwindLogMsg("initialized frame current pc is 0x%" PRIx64
+ " cfa is 0x%" PRIx64 " afa is 0x%" PRIx64,
+ (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()),
+ (uint64_t)m_cfa,
+ (uint64_t)m_afa);
+}
+
+bool RegisterContextUnwind::CheckIfLoopingStack() {
+ // If we have a bad stack setup, we can get the same CFA value multiple times
+ // -- or even more devious, we can actually oscillate between two CFA values.
+ // Detect that here and break out to avoid a possible infinite loop in lldb
+ // trying to unwind the stack. To detect when we have the same CFA value
+ // multiple times, we compare the
+ // CFA of the current
+ // frame with the 2nd next frame because in some specail case (e.g. signal
+ // hanlders, hand written assembly without ABI compliance) we can have 2
+ // frames with the same
+ // CFA (in theory we
+ // can have arbitrary number of frames with the same CFA, but more then 2 is
+ // very very unlikely)
+
+ RegisterContextUnwind::SharedPtr next_frame = GetNextFrame();
+ if (next_frame) {
+ RegisterContextUnwind::SharedPtr next_next_frame =
+ next_frame->GetNextFrame();
+ addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
+ if (next_next_frame && next_next_frame->GetCFA(next_next_frame_cfa)) {
+ if (next_next_frame_cfa == m_cfa) {
+ // We have a loop in the stack unwind
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool RegisterContextUnwind::IsFrameZero() const { return m_frame_number == 0; }
+
+// Find a fast unwind plan for this frame, if possible.
+//
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame
+// if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into
+// the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP RegisterContextUnwind::GetFastUnwindPlanForFrame() {
+ UnwindPlanSP unwind_plan_sp;
+ ModuleSP pc_module_sp(m_current_pc.GetModule());
+
+ if (!m_current_pc.IsValid() || !pc_module_sp ||
+ pc_module_sp->GetObjectFile() == nullptr)
+ return unwind_plan_sp;
+
+ if (IsFrameZero())
+ return unwind_plan_sp;
+
+ FuncUnwindersSP func_unwinders_sp(
+ pc_module_sp->GetUnwindTable().GetFuncUnwindersContainingAddress(
+ m_current_pc, m_sym_ctx));
+ if (!func_unwinders_sp)
+ return unwind_plan_sp;
+
+ // If we're in _sigtramp(), unwinding past this frame requires special
+ // knowledge.
+ if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame)
+ return unwind_plan_sp;
+
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind(
+ *m_thread.CalculateTarget(), m_thread);
+ if (unwind_plan_sp) {
+ if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose()) {
+ if (m_fast_unwind_plan_sp)
+ UnwindLogMsgVerbose("frame, and has a fast UnwindPlan");
+ else
+ UnwindLogMsgVerbose("frame");
+ }
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ } else {
+ unwind_plan_sp.reset();
+ }
+ }
+ return unwind_plan_sp;
+}
+
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame
+// if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into
+// the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() {
+ UnwindPlanSP unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : nullptr;
+ if (abi) {
+ arch_default_unwind_plan_sp =
+ std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ } else {
+ UnwindLogMsg(
+ "unable to get architectural default UnwindPlan from ABI plugin");
+ }
+
+ bool behaves_like_zeroth_frame = false;
+ if (IsFrameZero() || GetNextFrame()->m_frame_type == eTrapHandlerFrame ||
+ GetNextFrame()->m_frame_type == eDebuggerFrame) {
+ behaves_like_zeroth_frame = true;
+ // If this frame behaves like a 0th frame (currently executing or
+ // interrupted asynchronously), all registers can be retrieved.
+ m_all_registers_available = true;
+ }
+
+ // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer)
+ // so the pc is 0x0 in the zeroth frame, we need to use the "unwind at first
+ // instruction" arch default UnwindPlan Also, if this Process can report on
+ // memory region attributes, any non-executable region means we jumped
+ // through a bad function pointer - handle the same way as 0x0. Note, if we
+ // have a symbol context & a symbol, we don't want to follow this code path.
+ // This is for jumping to memory regions without any information available.
+
+ if ((!m_sym_ctx_valid ||
+ (m_sym_ctx.function == nullptr && m_sym_ctx.symbol == nullptr)) &&
+ behaves_like_zeroth_frame && m_current_pc.IsValid()) {
+ uint32_t permissions;
+ addr_t current_pc_addr =
+ m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr());
+ if (current_pc_addr == 0 ||
+ (process &&
+ process->GetLoadAddressPermissions(current_pc_addr, permissions) &&
+ (permissions & ePermissionsExecutable) == 0)) {
+ if (abi) {
+ unwind_plan_sp =
+ std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ }
+ }
+
+ // No Module for the current pc, try using the architecture default unwind.
+ ModuleSP pc_module_sp(m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp ||
+ pc_module_sp->GetObjectFile() == nullptr) {
+ m_frame_type = eNormalFrame;
+ return arch_default_unwind_plan_sp;
+ }
+
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid) {
+ func_unwinders_sp =
+ pc_module_sp->GetUnwindTable().GetFuncUnwindersContainingAddress(
+ m_current_pc, m_sym_ctx);
+ }
+
+ // No FuncUnwinders available for this pc (stripped function symbols, lldb
+ // could not augment its function table with another source, like
+ // LC_FUNCTION_STARTS or eh_frame in ObjectFileMachO). See if eh_frame or the
+ // .ARM.exidx tables have unwind information for this address, else fall back
+ // to the architectural default unwind.
+ if (!func_unwinders_sp) {
+ m_frame_type = eNormalFrame;
+
+ if (!pc_module_sp || !pc_module_sp->GetObjectFile() ||
+ !m_current_pc.IsValid())
+ return arch_default_unwind_plan_sp;
+
+ // Even with -fomit-frame-pointer, we can try eh_frame to get back on
+ // track.
+ DWARFCallFrameInfo *eh_frame =
+ pc_module_sp->GetUnwindTable().GetEHFrameInfo();
+ if (eh_frame) {
+ unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ if (eh_frame->GetUnwindPlan(m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+
+ ArmUnwindInfo *arm_exidx =
+ pc_module_sp->GetUnwindTable().GetArmUnwindInfo();
+ if (arm_exidx) {
+ unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ if (arm_exidx->GetUnwindPlan(exe_ctx.GetTargetRef(), m_current_pc,
+ *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+
+ CallFrameInfo *object_file_unwind =
+ pc_module_sp->GetUnwindTable().GetObjectFileUnwindInfo();
+ if (object_file_unwind) {
+ unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ if (object_file_unwind->GetUnwindPlan(m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+
+ return arch_default_unwind_plan_sp;
+ }
+
+ // If we're in _sigtramp(), unwinding past this frame requires special
+ // knowledge. On Mac OS X this knowledge is properly encoded in the eh_frame
+ // section, so prefer that if available. On other platforms we may need to
+ // provide a platform-specific UnwindPlan which encodes the details of how to
+ // unwind out of sigtramp.
+ if (m_frame_type == eTrapHandlerFrame && process) {
+ m_fast_unwind_plan_sp.reset();
+ unwind_plan_sp =
+ func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget());
+ if (!unwind_plan_sp)
+ unwind_plan_sp =
+ func_unwinders_sp->GetObjectFileUnwindPlan(process->GetTarget());
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc) &&
+ unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) {
+ return unwind_plan_sp;
+ }
+ }
+
+ // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame
+ // even when it's frame zero This comes up if we have hand-written functions
+ // in a Module and hand-written eh_frame. The assembly instruction
+ // inspection may fail and the eh_frame CFI were probably written with some
+ // care to do the right thing. It'd be nice if there was a way to ask the
+ // eh_frame directly if it is asynchronous (can be trusted at every
+ // instruction point) or synchronous (the normal case - only at call sites).
+ // But there is not.
+ if (process && process->GetDynamicLoader() &&
+ process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo(m_sym_ctx)) {
+ // We must specifically call the GetEHFrameUnwindPlan() method here --
+ // normally we would call GetUnwindPlanAtCallSite() -- because CallSite may
+ // return an unwind plan sourced from either eh_frame (that's what we
+ // intend) or compact unwind (this won't work)
+ unwind_plan_sp =
+ func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget());
+ if (!unwind_plan_sp)
+ unwind_plan_sp =
+ func_unwinders_sp->GetObjectFileUnwindPlan(process->GetTarget());
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) {
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because the "
+ "DynamicLoader suggested we prefer it",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically the NonCallSite UnwindPlan is the unwind created by inspecting
+ // the assembly language instructions
+ if (behaves_like_zeroth_frame && process) {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite(
+ process->GetTarget(), m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) {
+ if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) {
+ // We probably have an UnwindPlan created by inspecting assembly
+ // instructions. The assembly profilers work really well with compiler-
+ // generated functions but hand- written assembly can be problematic.
+ // We set the eh_frame based unwind plan as our fallback unwind plan if
+ // instruction emulation doesn't work out even for non call sites if it
+ // is available and use the architecture default unwind plan if it is
+ // not available. The eh_frame unwind plan is more reliable even on non
+ // call sites then the architecture default plan and for hand written
+ // assembly code it is often written in a way that it valid at all
+ // location what helps in the most common cases when the instruction
+ // emulation fails.
+ UnwindPlanSP call_site_unwind_plan =
+ func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(),
+ m_thread);
+ if (call_site_unwind_plan &&
+ call_site_unwind_plan.get() != unwind_plan_sp.get() &&
+ call_site_unwind_plan->GetSourceName() !=
+ unwind_plan_sp->GetSourceName()) {
+ m_fallback_unwind_plan_sp = call_site_unwind_plan;
+ } else {
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
+ }
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because this "
+ "is the non-call site unwind plan and this is a "
+ "zeroth frame",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If we're on the first instruction of a function, and we have an
+ // architectural default UnwindPlan for the initial instruction of a
+ // function, use that.
+ if (m_current_offset == 0) {
+ unwind_plan_sp =
+ func_unwinders_sp->GetUnwindPlanArchitectureDefaultAtFunctionEntry(
+ m_thread);
+ if (unwind_plan_sp) {
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because we are at "
+ "the first instruction of a function",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+ }
+
+ // Typically this is unwind info from an eh_frame section intended for
+ // exception handling; only valid at call sites
+ if (process) {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite(
+ process->GetTarget(), m_thread);
+ }
+ int valid_offset = -1;
+ if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) {
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because this "
+ "is the call-site unwind plan",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // We'd prefer to use an UnwindPlan intended for call sites when we're at a
+ // call site but if we've struck out on that, fall back to using the non-
+ // call-site assembly inspection UnwindPlan if possible.
+ if (process) {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite(
+ process->GetTarget(), m_thread);
+ }
+ if (unwind_plan_sp &&
+ unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) {
+ // We probably have an UnwindPlan created by inspecting assembly
+ // instructions. The assembly profilers work really well with compiler-
+ // generated functions but hand- written assembly can be problematic. We
+ // set the eh_frame based unwind plan as our fallback unwind plan if
+ // instruction emulation doesn't work out even for non call sites if it is
+ // available and use the architecture default unwind plan if it is not
+ // available. The eh_frame unwind plan is more reliable even on non call
+ // sites then the architecture default plan and for hand written assembly
+ // code it is often written in a way that it valid at all location what
+ // helps in the most common cases when the instruction emulation fails.
+ UnwindPlanSP call_site_unwind_plan =
+ func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(),
+ m_thread);
+ if (call_site_unwind_plan &&
+ call_site_unwind_plan.get() != unwind_plan_sp.get() &&
+ call_site_unwind_plan->GetSourceName() !=
+ unwind_plan_sp->GetSourceName()) {
+ m_fallback_unwind_plan_sp = call_site_unwind_plan;
+ } else {
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
+ }
+
+ if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) {
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because we "
+ "failed to find a call-site unwind plan that would work",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If nothing else, use the architectural default UnwindPlan and hope that
+ // does the job.
+ if (arch_default_unwind_plan_sp)
+ UnwindLogMsgVerbose(
+ "frame uses %s for full UnwindPlan because we are falling back "
+ "to the arch default plan",
+ arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ else
+ UnwindLogMsg(
+ "Unable to find any UnwindPlan for full unwind of this frame.");
+
+ return arch_default_unwind_plan_sp;
+}
+
+void RegisterContextUnwind::InvalidateAllRegisters() {
+ m_frame_type = eNotAValidFrame;
+}
+
+size_t RegisterContextUnwind::GetRegisterCount() {
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *RegisterContextUnwind::GetRegisterInfoAtIndex(size_t reg) {
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t RegisterContextUnwind::GetRegisterSetCount() {
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+const RegisterSet *RegisterContextUnwind::GetRegisterSet(size_t reg_set) {
+ return m_thread.GetRegisterContext()->GetRegisterSet(reg_set);
+}
+
+uint32_t RegisterContextUnwind::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
+ kind, num);
+}
+
+bool RegisterContextUnwind::ReadRegisterValueFromRegisterLocation(
+ lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info, RegisterValue &value) {
+ if (!IsValid())
+ return false;
+ bool success = false;
+
+ switch (regloc.type) {
+ case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext: {
+ const RegisterInfo *other_reg_info =
+ GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ success =
+ m_thread.GetRegisterContext()->ReadRegister(other_reg_info, value);
+ } break;
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister: {
+ const RegisterInfo *other_reg_info =
+ GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ if (IsFrameZero()) {
+ success =
+ m_thread.GetRegisterContext()->ReadRegister(other_reg_info, value);
+ } else {
+ success = GetNextFrame()->ReadRegister(other_reg_info, value);
+ }
+ } break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ success =
+ value.SetUInt(regloc.location.inferred_value, reg_info->byte_size);
+ break;
+
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ llvm_unreachable("FIXME debugger inferior function call unwind");
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: {
+ Status error(ReadRegisterValueFromMemory(
+ reg_info, regloc.location.target_memory_location, reg_info->byte_size,
+ value));
+ success = error.Success();
+ } break;
+ default:
+ llvm_unreachable("Unknown RegisterLocation type.");
+ }
+ return success;
+}
+
+bool RegisterContextUnwind::WriteRegisterValueToRegisterLocation(
+ lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ if (!IsValid())
+ return false;
+
+ bool success = false;
+
+ switch (regloc.type) {
+ case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext: {
+ const RegisterInfo *other_reg_info =
+ GetRegisterInfoAtIndex(regloc.location.register_number);
+ success =
+ m_thread.GetRegisterContext()->WriteRegister(other_reg_info, value);
+ } break;
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister: {
+ const RegisterInfo *other_reg_info =
+ GetRegisterInfoAtIndex(regloc.location.register_number);
+ if (IsFrameZero()) {
+ success =
+ m_thread.GetRegisterContext()->WriteRegister(other_reg_info, value);
+ } else {
+ success = GetNextFrame()->WriteRegister(other_reg_info, value);
+ }
+ } break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ llvm_unreachable("FIXME debugger inferior function call unwind");
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: {
+ Status error(WriteRegisterValueToMemory(
+ reg_info, regloc.location.target_memory_location, reg_info->byte_size,
+ value));
+ success = error.Success();
+ } break;
+ default:
+ llvm_unreachable("Unknown RegisterLocation type.");
+ }
+ return success;
+}
+
+bool RegisterContextUnwind::IsValid() const {
+ return m_frame_type != eNotAValidFrame;
+}
+
+// After the final stack frame in a stack walk we'll get one invalid
+// (eNotAValidFrame) stack frame -- one past the end of the stack walk. But
+// higher-level code will need to tell the difference between "the unwind plan
+// below this frame failed" versus "we successfully completed the stack walk"
+// so this method helps to disambiguate that.
+
+bool RegisterContextUnwind::IsTrapHandlerFrame() const {
+ return m_frame_type == eTrapHandlerFrame;
+}
+
+// A skip frame is a bogus frame on the stack -- but one where we're likely to
+// find a real frame farther
+// up the stack if we keep looking. It's always the second frame in an unwind
+// (i.e. the first frame after frame zero) where unwinding can be the
+// trickiest. Ideally we'll mark up this frame in some way so the user knows
+// we're displaying bad data and we may have skipped one frame of their real
+// program in the process of getting back on track.
+
+bool RegisterContextUnwind::IsSkipFrame() const {
+ return m_frame_type == eSkipFrame;
+}
+
+bool RegisterContextUnwind::IsTrapHandlerSymbol(
+ lldb_private::Process *process,
+ const lldb_private::SymbolContext &m_sym_ctx) const {
+ PlatformSP platform_sp(process->GetTarget().GetPlatform());
+ if (platform_sp) {
+ const std::vector<ConstString> trap_handler_names(
+ platform_sp->GetTrapHandlerSymbolNames());
+ for (ConstString name : trap_handler_names) {
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) {
+ return true;
+ }
+ }
+ }
+ const std::vector<ConstString> user_specified_trap_handler_names(
+ m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames());
+ for (ConstString name : user_specified_trap_handler_names) {
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Answer the question: Where did THIS frame save the CALLER frame ("previous"
+// frame)'s register value?
+
+enum UnwindLLDB::RegisterSearchResult
+RegisterContextUnwind::SavedLocationForRegister(
+ uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc) {
+ RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum);
+
+ // Have we already found this register location?
+ if (!m_registers.empty()) {
+ std::map<uint32_t,
+ lldb_private::UnwindLLDB::RegisterLocation>::const_iterator
+ iterator;
+ iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB));
+ if (iterator != m_registers.end()) {
+ regloc = iterator->second;
+ UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ // Look through the available UnwindPlans for the register location.
+
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ bool have_unwindplan_regloc = false;
+ RegisterKind unwindplan_registerkind = kNumRegisterKinds;
+
+ if (m_fast_unwind_plan_sp) {
+ UnwindPlan::RowSP active_row =
+ m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+ unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind();
+ if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) {
+ UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind "
+ "reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ (int)unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
+ unwindplan_regloc)) {
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using FastUnwindPlan",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ have_unwindplan_regloc = true;
+ }
+ }
+
+ if (!have_unwindplan_regloc) {
+ // m_full_unwind_plan_sp being NULL means that we haven't tried to find a
+ // full UnwindPlan yet
+ if (!m_full_unwind_plan_sp)
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame();
+
+ if (m_full_unwind_plan_sp) {
+ RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+
+ UnwindPlan::RowSP active_row =
+ m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind();
+
+ RegisterNumber return_address_reg;
+
+ // If we're fetching the saved pc and this UnwindPlan defines a
+ // ReturnAddress register (e.g. lr on arm), look for the return address
+ // register number in the UnwindPlan's row.
+ if (pc_regnum.IsValid() && pc_regnum == regnum &&
+ m_full_unwind_plan_sp->GetReturnAddressRegister() !=
+ LLDB_INVALID_REGNUM) {
+ // If this is a trap handler frame, we should have access to
+ // the complete register context when the interrupt/async
+ // signal was received, we should fetch the actual saved $pc
+ // value instead of the Return Address register.
+ // If $pc is not available, fall back to the RA reg.
+ UnwindPlan::Row::RegisterLocation scratch;
+ if (m_frame_type == eTrapHandlerFrame &&
+ active_row->GetRegisterInfo
+ (pc_regnum.GetAsKind (unwindplan_registerkind), scratch)) {
+ UnwindLogMsg("Providing pc register instead of rewriting to "
+ "RA reg because this is a trap handler and there is "
+ "a location for the saved pc register value.");
+ } else {
+ return_address_reg.init(
+ m_thread, m_full_unwind_plan_sp->GetRegisterKind(),
+ m_full_unwind_plan_sp->GetReturnAddressRegister());
+ regnum = return_address_reg;
+ UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a "
+ "RA reg; getting %s (%d) instead",
+ return_address_reg.GetName(),
+ return_address_reg.GetAsKind(eRegisterKindLLDB));
+ }
+ } else {
+ if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) {
+ if (unwindplan_registerkind == eRegisterKindGeneric) {
+ UnwindLogMsg("could not convert lldb regnum %s (%d) into "
+ "eRegisterKindGeneric reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ } else {
+ UnwindLogMsg("could not convert lldb regnum %s (%d) into %d "
+ "RegisterKind reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ (int)unwindplan_registerkind);
+ }
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (regnum.IsValid() &&
+ active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
+ unwindplan_regloc)) {
+ have_unwindplan_regloc = true;
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using %s UnwindPlan",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ }
+
+ // This is frame 0 and we're retrieving the PC and it's saved in a Return
+ // Address register and it hasn't been saved anywhere yet -- that is,
+ // it's still live in the actual register. Handle this specially.
+
+ if (!have_unwindplan_regloc && return_address_reg.IsValid() &&
+ IsFrameZero()) {
+ if (return_address_reg.GetAsKind(eRegisterKindLLDB) !=
+ LLDB_INVALID_REGNUM) {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type =
+ UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext;
+ new_regloc.location.register_number =
+ return_address_reg.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the live "
+ "RegisterContext at frame 0, saved in %d",
+ return_address_reg.GetName(),
+ return_address_reg.GetAsKind(eRegisterKindLLDB),
+ return_address_reg.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ // If this architecture stores the return address in a register (it
+ // defines a Return Address register) and we're on a non-zero stack frame
+ // and the Full UnwindPlan says that the pc is stored in the
+ // RA registers (e.g. lr on arm), then we know that the full unwindplan is
+ // not trustworthy -- this
+ // is an impossible situation and the instruction emulation code has
+ // likely been misled. If this stack frame meets those criteria, we need
+ // to throw away the Full UnwindPlan that the instruction emulation came
+ // up with and fall back to the architecture's Default UnwindPlan so the
+ // stack walk can get past this point.
+
+ // Special note: If the Full UnwindPlan was generated from the compiler,
+ // don't second-guess it when we're at a call site location.
+
+ // arch_default_ra_regnum is the return address register # in the Full
+ // UnwindPlan register numbering
+ RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_RA);
+
+ if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) !=
+ LLDB_INVALID_REGNUM &&
+ pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() &&
+ unwindplan_regloc.GetRegisterNumber() ==
+ arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) &&
+ m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes &&
+ !m_all_registers_available) {
+ UnwindLogMsg("%s UnwindPlan tried to restore the pc from the link "
+ "register but this is a non-zero frame",
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // Throw away the full unwindplan; install the arch default unwindplan
+ if (ForceSwitchToFallbackUnwindPlan()) {
+ // Update for the possibly new unwind plan
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind();
+ UnwindPlan::RowSP active_row =
+ m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+
+ // Sanity check: Verify that we can fetch a pc value and CFA value
+ // with this unwind plan
+
+ RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+ bool can_fetch_pc_value = false;
+ bool can_fetch_cfa = false;
+ addr_t cfa_value;
+ if (active_row) {
+ if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) !=
+ LLDB_INVALID_REGNUM &&
+ active_row->GetRegisterInfo(
+ arch_default_pc_reg.GetAsKind(unwindplan_registerkind),
+ unwindplan_regloc)) {
+ can_fetch_pc_value = true;
+ }
+ if (ReadFrameAddress(unwindplan_registerkind,
+ active_row->GetCFAValue(), cfa_value)) {
+ can_fetch_cfa = true;
+ }
+ }
+
+ have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa;
+ } else {
+ // We were unable to fall back to another unwind plan
+ have_unwindplan_regloc = false;
+ }
+ }
+ }
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (!have_unwindplan_regloc) {
+ // If the UnwindPlan failed to give us an unwind location for this
+ // register, we may be able to fall back to some ABI-defined default. For
+ // example, some ABIs allow to determine the caller's SP via the CFA. Also,
+ // the ABI may set volatile registers to the undefined state.
+ ABI *abi = process ? process->GetABI().get() : nullptr;
+ if (abi) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB));
+ if (reg_info &&
+ abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) {
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using ABI default",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ have_unwindplan_regloc = true;
+ }
+ }
+ }
+
+ if (!have_unwindplan_regloc) {
+ if (IsFrameZero()) {
+ // This is frame 0 - we should return the actual live register context
+ // value
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type =
+ UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext;
+ new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the live "
+ "RegisterContext at frame 0",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ } else {
+ std::string unwindplan_name("");
+ if (m_full_unwind_plan_sp) {
+ unwindplan_name += "via '";
+ unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString();
+ unwindplan_name += "'";
+ }
+ UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(),
+ regnum.GetAsKind(eRegisterKindLLDB),
+ unwindplan_name.c_str());
+ }
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ // unwindplan_regloc has valid contents about where to retrieve the register
+ if (unwindplan_regloc.IsUnspecified()) {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
+ UnwindLogMsg("save location for %s (%d) is unspecified, continue searching",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ if (unwindplan_regloc.IsUndefined()) {
+ UnwindLogMsg(
+ "did not supply reg location for %s (%d) because it is volatile",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
+ }
+
+ if (unwindplan_regloc.IsSame()) {
+ if (!IsFrameZero() &&
+ (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC ||
+ regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) {
+ UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or "
+ "return address reg on a non-zero frame -- treat as if we "
+ "have no information",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ } else {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg(
+ "supplying caller's register %s (%d), saved in register %s (%d)",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ if (unwindplan_regloc.IsCFAPlusOffset()) {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa + offset;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d), value is CFA plus "
+ "offset %d [value is 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+ regloc.location.inferred_value);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAtCFAPlusOffset()) {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = m_cfa + offset;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the stack, saved at "
+ "CFA plus offset %d [saved at 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+ regloc.location.target_memory_location);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAFAPlusOffset()) {
+ if (m_afa == LLDB_INVALID_ADDRESS)
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_afa + offset;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d), value is AFA plus "
+ "offset %d [value is 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+ regloc.location.inferred_value);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAtAFAPlusOffset()) {
+ if (m_afa == LLDB_INVALID_ADDRESS)
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = m_afa + offset;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the stack, saved at "
+ "AFA plus offset %d [saved at 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+ regloc.location.target_memory_location);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsInOtherRegister()) {
+ uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
+ RegisterNumber row_regnum(m_thread, unwindplan_registerkind,
+ unwindplan_regnum);
+ if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) {
+ UnwindLogMsg("could not supply caller's %s (%d) location - was saved in "
+ "another reg but couldn't convert that regnum",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = row_regnum.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg(
+ "supplying caller's register %s (%d), saved in register %s (%d)",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ row_regnum.GetName(), row_regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsDWARFExpression() ||
+ unwindplan_regloc.IsAtDWARFExpression()) {
+ DataExtractor dwarfdata(unwindplan_regloc.GetDWARFExpressionBytes(),
+ unwindplan_regloc.GetDWARFExpressionLength(),
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ ModuleSP opcode_ctx;
+ DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr);
+ dwarfexpr.SetRegisterKind(unwindplan_registerkind);
+ Value cfa_val = Scalar(m_cfa);
+ cfa_val.SetValueType(Value::eValueTypeLoadAddress);
+ Value result;
+ Status error;
+ if (dwarfexpr.Evaluate(&exe_ctx, this, 0, &cfa_val, nullptr, result,
+ &error)) {
+ addr_t val;
+ val = result.GetScalar().ULongLong();
+ if (unwindplan_regloc.IsDWARFExpression()) {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = val;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) via DWARF expression "
+ "(IsDWARFExpression)",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ } else {
+ regloc.type =
+ UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = val;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) via DWARF expression "
+ "(IsAtDWARFExpression)",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+ UnwindLogMsg("tried to use IsDWARFExpression or IsAtDWARFExpression for %s "
+ "(%d) but failed",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ UnwindLogMsg("no save location for %s (%d) in this stack frame",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+
+ // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are
+ // unsupported.
+
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+}
+
+// TryFallbackUnwindPlan() -- this method is a little tricky.
+//
+// When this is called, the frame above -- the caller frame, the "previous"
+// frame -- is invalid or bad.
+//
+// Instead of stopping the stack walk here, we'll try a different UnwindPlan
+// and see if we can get a valid frame above us.
+//
+// This most often happens when an unwind plan based on assembly instruction
+// inspection is not correct -- mostly with hand-written assembly functions or
+// functions where the stack frame is set up "out of band", e.g. the kernel
+// saved the register context and then called an asynchronous trap handler like
+// _sigtramp.
+//
+// Often in these cases, if we just do a dumb stack walk we'll get past this
+// tricky frame and our usual techniques can continue to be used.
+
+bool RegisterContextUnwind::TryFallbackUnwindPlan() {
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() ||
+ m_full_unwind_plan_sp->GetSourceName() ==
+ m_fallback_unwind_plan_sp->GetSourceName()) {
+ return false;
+ }
+
+ // If a compiler generated unwind plan failed, trying the arch default
+ // unwindplan isn't going to do any better.
+ if (m_full_unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes)
+ return false;
+
+ // Get the caller's pc value and our own CFA value. Swap in the fallback
+ // unwind plan, re-fetch the caller's pc value and CFA value. If they're the
+ // same, then the fallback unwind plan provides no benefit.
+
+ RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+
+ addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS;
+ addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS;
+ UnwindLLDB::RegisterLocation regloc;
+ if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB),
+ regloc) ==
+ UnwindLLDB::RegisterSearchResult::eRegisterFound) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(pc_regnum.GetAsKind(eRegisterKindLLDB));
+ if (reg_info) {
+ RegisterValue reg_value;
+ if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) {
+ old_caller_pc_value = reg_value.GetAsUInt64();
+ }
+ }
+ }
+
+ // This is a tricky wrinkle! If SavedLocationForRegister() detects a really
+ // impossible register location for the full unwind plan, it may call
+ // ForceSwitchToFallbackUnwindPlan() which in turn replaces the full
+ // unwindplan with the fallback... in short, we're done, we're using the
+ // fallback UnwindPlan. We checked if m_fallback_unwind_plan_sp was nullptr
+ // at the top -- the only way it became nullptr since then is via
+ // SavedLocationForRegister().
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return true;
+
+ // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide
+ // this isn't working, we need to restore. We'll also need to save & restore
+ // the value of the m_cfa ivar. Save is down below a bit in 'old_cfa'.
+ UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ addr_t old_cfa = m_cfa;
+ addr_t old_afa = m_afa;
+
+ m_registers.clear();
+
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+
+ UnwindPlan::RowSP active_row =
+ m_fallback_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+
+ if (active_row &&
+ active_row->GetCFAValue().GetValueType() !=
+ UnwindPlan::Row::FAValue::unspecified) {
+ addr_t new_cfa;
+ if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+ active_row->GetCFAValue(), new_cfa) ||
+ new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) {
+ UnwindLogMsg("failed to get cfa with fallback unwindplan");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ return false;
+ }
+ m_cfa = new_cfa;
+
+ ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+ active_row->GetAFAValue(), m_afa);
+
+ if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB),
+ regloc) ==
+ UnwindLLDB::RegisterSearchResult::eRegisterFound) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(pc_regnum.GetAsKind(eRegisterKindLLDB));
+ if (reg_info) {
+ RegisterValue reg_value;
+ if (ReadRegisterValueFromRegisterLocation(regloc, reg_info,
+ reg_value)) {
+ new_caller_pc_value = reg_value.GetAsUInt64();
+ }
+ }
+ }
+
+ if (new_caller_pc_value == LLDB_INVALID_ADDRESS) {
+ UnwindLogMsg("failed to get a pc value for the caller frame with the "
+ "fallback unwind plan");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ m_cfa = old_cfa;
+ m_afa = old_afa;
+ return false;
+ }
+
+ if (old_caller_pc_value == new_caller_pc_value &&
+ m_cfa == old_cfa &&
+ m_afa == old_afa) {
+ UnwindLogMsg("fallback unwind plan got the same values for this frame "
+ "CFA and caller frame pc, not using");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ return false;
+ }
+
+ UnwindLogMsg("trying to unwind from this function with the UnwindPlan '%s' "
+ "because UnwindPlan '%s' failed.",
+ m_fallback_unwind_plan_sp->GetSourceName().GetCString(),
+ original_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // We've copied the fallback unwind plan into the full - now clear the
+ // fallback.
+ m_fallback_unwind_plan_sp.reset();
+ PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
+ }
+
+ return true;
+}
+
+bool RegisterContextUnwind::ForceSwitchToFallbackUnwindPlan() {
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() ||
+ m_full_unwind_plan_sp->GetSourceName() ==
+ m_fallback_unwind_plan_sp->GetSourceName()) {
+ return false;
+ }
+
+ UnwindPlan::RowSP active_row =
+ m_fallback_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+
+ if (active_row &&
+ active_row->GetCFAValue().GetValueType() !=
+ UnwindPlan::Row::FAValue::unspecified) {
+ addr_t new_cfa;
+ if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+ active_row->GetCFAValue(), new_cfa) ||
+ new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) {
+ UnwindLogMsg("failed to get cfa with fallback unwindplan");
+ m_fallback_unwind_plan_sp.reset();
+ return false;
+ }
+
+ ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+ active_row->GetAFAValue(), m_afa);
+
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+ m_fallback_unwind_plan_sp.reset();
+
+ m_registers.clear();
+
+ m_cfa = new_cfa;
+
+ PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
+
+ UnwindLogMsg("switched unconditionally to the fallback unwindplan %s",
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ return true;
+ }
+ return false;
+}
+
+void RegisterContextUnwind::PropagateTrapHandlerFlagFromUnwindPlan(
+ lldb::UnwindPlanSP unwind_plan) {
+ if (unwind_plan->GetUnwindPlanForSignalTrap() != eLazyBoolYes) {
+ // Unwind plan does not indicate trap handler. Do nothing. We may
+ // already be flagged as trap handler flag due to the symbol being
+ // in the trap handler symbol list, and that should take precedence.
+ return;
+ } else if (m_frame_type != eNormalFrame) {
+ // If this is already a trap handler frame, nothing to do.
+ // If this is a skip or debug or invalid frame, don't override that.
+ return;
+ }
+
+ m_frame_type = eTrapHandlerFrame;
+
+ if (m_current_offset_backed_up_one != m_current_offset) {
+ // We backed up the pc by 1 to compute the symbol context, but
+ // now need to undo that because the pc of the trap handler
+ // frame may in fact be the first instruction of a signal return
+ // trampoline, rather than the instruction after a call. This
+ // happens on systems where the signal handler dispatch code, rather
+ // than calling the handler and being returned to, jumps to the
+ // handler after pushing the address of a return trampoline on the
+ // stack -- on these systems, when the handler returns, control will
+ // be transferred to the return trampoline, so that's the best
+ // symbol we can present in the callstack.
+ UnwindLogMsg("Resetting current offset and re-doing symbol lookup; "
+ "old symbol was %s",
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ m_current_offset_backed_up_one = m_current_offset;
+
+ AddressRange addr_range;
+ m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
+
+ UnwindLogMsg("Symbol is now %s",
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ Target *target = &process->GetTarget();
+
+ m_start_pc = addr_range.GetBaseAddress();
+ m_current_offset =
+ m_current_pc.GetLoadAddress(target) - m_start_pc.GetLoadAddress(target);
+ }
+}
+
+bool RegisterContextUnwind::ReadFrameAddress(
+ lldb::RegisterKind row_register_kind, UnwindPlan::Row::FAValue &fa,
+ addr_t &address) {
+ RegisterValue reg_value;
+
+ address = LLDB_INVALID_ADDRESS;
+ addr_t cfa_reg_contents;
+
+ switch (fa.GetValueType()) {
+ case UnwindPlan::Row::FAValue::isRegisterDereferenced: {
+ RegisterNumber cfa_reg(m_thread, row_register_kind,
+ fa.GetRegisterNumber());
+ if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(cfa_reg.GetAsKind(eRegisterKindLLDB));
+ RegisterValue reg_value;
+ if (reg_info) {
+ Status error = ReadRegisterValueFromMemory(
+ reg_info, cfa_reg_contents, reg_info->byte_size, reg_value);
+ if (error.Success()) {
+ address = reg_value.GetAsUInt64();
+ UnwindLogMsg(
+ "CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64
+ ", CFA value is 0x%" PRIx64,
+ cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+ cfa_reg_contents, address);
+ return true;
+ } else {
+ UnwindLogMsg("Tried to deref reg %s (%d) [0x%" PRIx64
+ "] but memory read failed.",
+ cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+ cfa_reg_contents);
+ }
+ }
+ }
+ break;
+ }
+ case UnwindPlan::Row::FAValue::isRegisterPlusOffset: {
+ RegisterNumber cfa_reg(m_thread, row_register_kind,
+ fa.GetRegisterNumber());
+ if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
+ if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 ||
+ cfa_reg_contents == 1) {
+ UnwindLogMsg(
+ "Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64,
+ cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+ cfa_reg_contents);
+ cfa_reg_contents = LLDB_INVALID_ADDRESS;
+ return false;
+ }
+ address = cfa_reg_contents + fa.GetOffset();
+ UnwindLogMsg(
+ "CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64
+ ", offset is %d",
+ address, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+ cfa_reg_contents, fa.GetOffset());
+ return true;
+ }
+ break;
+ }
+ case UnwindPlan::Row::FAValue::isDWARFExpression: {
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ DataExtractor dwarfdata(fa.GetDWARFExpressionBytes(),
+ fa.GetDWARFExpressionLength(),
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ ModuleSP opcode_ctx;
+ DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr);
+ dwarfexpr.SetRegisterKind(row_register_kind);
+ Value result;
+ Status error;
+ if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result,
+ &error)) {
+ address = result.GetScalar().ULongLong();
+
+ UnwindLogMsg("CFA value set by DWARF expression is 0x%" PRIx64,
+ address);
+ return true;
+ }
+ UnwindLogMsg("Failed to set CFA value via DWARF expression: %s",
+ error.AsCString());
+ break;
+ }
+ case UnwindPlan::Row::FAValue::isRaSearch: {
+ Process &process = *m_thread.GetProcess();
+ lldb::addr_t return_address_hint = GetReturnAddressHint(fa.GetOffset());
+ if (return_address_hint == LLDB_INVALID_ADDRESS)
+ return false;
+ const unsigned max_iterations = 256;
+ for (unsigned i = 0; i < max_iterations; ++i) {
+ Status st;
+ lldb::addr_t candidate_addr =
+ return_address_hint + i * process.GetAddressByteSize();
+ lldb::addr_t candidate =
+ process.ReadPointerFromMemory(candidate_addr, st);
+ if (st.Fail()) {
+ UnwindLogMsg("Cannot read memory at 0x%" PRIx64 ": %s", candidate_addr,
+ st.AsCString());
+ return false;
+ }
+ Address addr;
+ uint32_t permissions;
+ if (process.GetLoadAddressPermissions(candidate, permissions) &&
+ permissions & lldb::ePermissionsExecutable) {
+ address = candidate_addr;
+ UnwindLogMsg("Heuristically found CFA: 0x%" PRIx64, address);
+ return true;
+ }
+ }
+ UnwindLogMsg("No suitable CFA found");
+ break;
+ }
+ default:
+ return false;
+ }
+ return false;
+}
+
+lldb::addr_t RegisterContextUnwind::GetReturnAddressHint(int32_t plan_offset) {
+ addr_t hint;
+ if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, hint))
+ return LLDB_INVALID_ADDRESS;
+ if (!m_sym_ctx.module_sp || !m_sym_ctx.symbol)
+ return LLDB_INVALID_ADDRESS;
+
+ hint += plan_offset;
+
+ if (auto next = GetNextFrame()) {
+ if (!next->m_sym_ctx.module_sp || !next->m_sym_ctx.symbol)
+ return LLDB_INVALID_ADDRESS;
+ if (auto expected_size =
+ next->m_sym_ctx.module_sp->GetSymbolFile()->GetParameterStackSize(
+ *next->m_sym_ctx.symbol))
+ hint += *expected_size;
+ else {
+ UnwindLogMsgVerbose("Could not retrieve parameter size: %s",
+ llvm::toString(expected_size.takeError()).c_str());
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ return hint;
+}
+
+// Retrieve a general purpose register value for THIS frame, as saved by the
+// NEXT frame, i.e. the frame that
+// this frame called. e.g.
+//
+// foo () { }
+// bar () { foo (); }
+// main () { bar (); }
+//
+// stopped in foo() so
+// frame 0 - foo
+// frame 1 - bar
+// frame 2 - main
+// and this RegisterContext is for frame 1 (bar) - if we want to get the pc
+// value for frame 1, we need to ask
+// where frame 0 (the "next" frame) saved that and retrieve the value.
+
+bool RegisterContextUnwind::ReadGPRValue(lldb::RegisterKind register_kind,
+ uint32_t regnum, addr_t &value) {
+ if (!IsValid())
+ return false;
+
+ uint32_t lldb_regnum;
+ if (register_kind == eRegisterKindLLDB) {
+ lldb_regnum = regnum;
+ } else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds(
+ register_kind, regnum, eRegisterKindLLDB, lldb_regnum)) {
+ return false;
+ }
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ RegisterValue reg_value;
+ // if this is frame 0 (currently executing frame), get the requested reg
+ // contents from the actual thread registers
+ if (IsFrameZero()) {
+ if (m_thread.GetRegisterContext()->ReadRegister(reg_info, reg_value)) {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+ }
+
+ bool pc_register = false;
+ uint32_t generic_regnum;
+ if (register_kind == eRegisterKindGeneric &&
+ (regnum == LLDB_REGNUM_GENERIC_PC || regnum == LLDB_REGNUM_GENERIC_RA)) {
+ pc_register = true;
+ } else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds(
+ register_kind, regnum, eRegisterKindGeneric, generic_regnum) &&
+ (generic_regnum == LLDB_REGNUM_GENERIC_PC ||
+ generic_regnum == LLDB_REGNUM_GENERIC_RA)) {
+ pc_register = true;
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ if (!m_parent_unwind.SearchForSavedLocationForRegister(
+ lldb_regnum, regloc, m_frame_number - 1, pc_register)) {
+ return false;
+ }
+ if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+}
+
+bool RegisterContextUnwind::ReadGPRValue(const RegisterNumber &regnum,
+ addr_t &value) {
+ return ReadGPRValue(regnum.GetRegisterKind(), regnum.GetRegisterNumber(),
+ value);
+}
+
+// Find the value of a register in THIS frame
+
+bool RegisterContextUnwind::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose("looking for register saved location for reg %d",
+ lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero()) {
+ UnwindLogMsgVerbose("passing along to the live register context for reg %d",
+ lldb_regnum);
+ return m_thread.GetRegisterContext()->ReadRegister(reg_info, value);
+ }
+
+ bool is_pc_regnum = false;
+ if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC ||
+ reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA) {
+ is_pc_regnum = true;
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister(
+ lldb_regnum, regloc, m_frame_number - 1, is_pc_regnum))
+ return false;
+
+ return ReadRegisterValueFromRegisterLocation(regloc, reg_info, value);
+}
+
+bool RegisterContextUnwind::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose("looking for register saved location for reg %d",
+ lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero()) {
+ UnwindLogMsgVerbose("passing along to the live register context for reg %d",
+ lldb_regnum);
+ return m_thread.GetRegisterContext()->WriteRegister(reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister(
+ lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return WriteRegisterValueToRegisterLocation(regloc, reg_info, value);
+}
+
+// Don't need to implement this one
+bool RegisterContextUnwind::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+// Don't need to implement this one
+bool RegisterContextUnwind::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+// Retrieve the pc value for THIS from
+
+bool RegisterContextUnwind::GetCFA(addr_t &cfa) {
+ if (!IsValid()) {
+ return false;
+ }
+ if (m_cfa == LLDB_INVALID_ADDRESS) {
+ return false;
+ }
+ cfa = m_cfa;
+ return true;
+}
+
+RegisterContextUnwind::SharedPtr RegisterContextUnwind::GetNextFrame() const {
+ RegisterContextUnwind::SharedPtr regctx;
+ if (m_frame_number == 0)
+ return regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum(m_frame_number - 1);
+}
+
+RegisterContextUnwind::SharedPtr RegisterContextUnwind::GetPrevFrame() const {
+ RegisterContextUnwind::SharedPtr regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum(m_frame_number + 1);
+}
+
+// Retrieve the address of the start of the function of THIS frame
+
+bool RegisterContextUnwind::GetStartPC(addr_t &start_pc) {
+ if (!IsValid())
+ return false;
+
+ if (!m_start_pc.IsValid()) {
+ bool read_successfully = ReadPC (start_pc);
+ if (read_successfully)
+ {
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
+ start_pc = abi->FixCodeAddress(start_pc);
+ }
+ }
+ return read_successfully;
+ }
+ start_pc = m_start_pc.GetLoadAddress(CalculateTarget().get());
+ return true;
+}
+
+// Retrieve the current pc value for THIS frame, as saved by the NEXT frame.
+
+bool RegisterContextUnwind::ReadPC(addr_t &pc) {
+ if (!IsValid())
+ return false;
+
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() &&
+ GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
+ if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) {
+ // A pc value of 0 or 1 is impossible in the middle of the stack -- it
+ // indicates the end of a stack walk.
+ // On the currently executing frame (or such a frame interrupted
+ // asynchronously by sigtramp et al) this may occur if code has jumped
+ // through a NULL pointer -- we want to be able to unwind past that frame
+ // to help find the bug.
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+ }
+
+ return !(m_all_registers_available == false &&
+ above_trap_handler == false && (pc == 0 || pc == 1));
+ } else {
+ return false;
+ }
+}
+
+void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ if (log) {
+ va_list args;
+ va_start(args, fmt);
+
+ char *logmsg;
+ if (vasprintf(&logmsg, fmt, args) == -1 || logmsg == nullptr) {
+ if (logmsg)
+ free(logmsg);
+ va_end(args);
+ return;
+ }
+ va_end(args);
+
+ LLDB_LOGF(log, "%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "",
+ m_thread.GetIndexID(), m_frame_number, logmsg);
+ free(logmsg);
+ }
+}
+
+void RegisterContextUnwind::UnwindLogMsgVerbose(const char *fmt, ...) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose()) {
+ va_list args;
+ va_start(args, fmt);
+
+ char *logmsg;
+ if (vasprintf(&logmsg, fmt, args) == -1 || logmsg == nullptr) {
+ if (logmsg)
+ free(logmsg);
+ va_end(args);
+ return;
+ }
+ va_end(args);
+
+ LLDB_LOGF(log, "%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "",
+ m_thread.GetIndexID(), m_frame_number, logmsg);
+ free(logmsg);
+ }
+}
diff --git a/lldb/source/Target/RegisterNumber.cpp b/lldb/source/Target/RegisterNumber.cpp
index 63b58d3582fd..0ea9f212c693 100644
--- a/lldb/source/Target/RegisterNumber.cpp
+++ b/lldb/source/Target/RegisterNumber.cpp
@@ -1,4 +1,4 @@
-//===--------------------- RegisterNumber.cpp -------------------*- C++ -*-===//
+//===-- RegisterNumber.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/RemoteAwarePlatform.cpp b/lldb/source/Target/RemoteAwarePlatform.cpp
index faa217ac83ef..f53158b06b8f 100644
--- a/lldb/source/Target/RemoteAwarePlatform.cpp
+++ b/lldb/source/Target/RemoteAwarePlatform.cpp
@@ -1,4 +1,4 @@
-//===-- RemoteAwarePlatform.cpp ---------------------------------*- C++ -*-===//
+//===-- RemoteAwarePlatform.cpp -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,12 +7,17 @@
//===----------------------------------------------------------------------===//
#include "lldb/Target/RemoteAwarePlatform.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/FileCache.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
+using namespace lldb;
bool RemoteAwarePlatform::GetModuleSpec(const FileSpec &module_file_spec,
const ArchSpec &arch,
@@ -21,7 +26,148 @@ bool RemoteAwarePlatform::GetModuleSpec(const FileSpec &module_file_spec,
return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
module_spec);
- return Platform::GetModuleSpec(module_file_spec, arch, module_spec);
+ return false;
+}
+
+Status RemoteAwarePlatform::ResolveExecutable(
+ const ModuleSpec &module_spec, ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr) {
+ Status error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ char exe_path[PATH_MAX];
+ ModuleSpec resolved_module_spec(module_spec);
+
+ if (IsHost()) {
+ // If we have "ls" as the exe_file, resolve the executable location based
+ // on the current path variables
+ if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
+ resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
+ resolved_module_spec.GetFileSpec().SetFile(exe_path,
+ FileSpec::Style::native);
+ FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec());
+ }
+
+ if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
+ FileSystem::Instance().ResolveExecutableLocation(
+ resolved_module_spec.GetFileSpec());
+
+ // Resolve any executable within a bundle on MacOSX
+ Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
+
+ if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
+ error.Clear();
+ else {
+ const uint32_t permissions = FileSystem::Instance().GetPermissions(
+ resolved_module_spec.GetFileSpec());
+ if (permissions && (permissions & eFilePermissionsEveryoneR) == 0)
+ error.SetErrorStringWithFormat(
+ "executable '%s' is not readable",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ else
+ error.SetErrorStringWithFormat(
+ "unable to find executable for '%s'",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ } else {
+ if (m_remote_platform_sp) {
+ return GetCachedExecutable(resolved_module_spec, exe_module_sp,
+ module_search_paths_ptr,
+ *m_remote_platform_sp);
+ }
+
+ // We may connect to a process and use the provided executable (Don't use
+ // local $PATH).
+
+ // Resolve any executable within a bundle on MacOSX
+ Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
+
+ if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
+ error.Clear();
+ else
+ error.SetErrorStringWithFormat("the platform is not currently "
+ "connected, and '%s' doesn't exist in "
+ "the system root.",
+ exe_path);
+ }
+
+ if (error.Success()) {
+ if (resolved_module_spec.GetArchitecture().IsValid()) {
+ error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
+ module_search_paths_ptr, nullptr, nullptr);
+ if (error.Fail()) {
+ // If we failed, it may be because the vendor and os aren't known. If
+ // that is the case, try setting them to the host architecture and give
+ // it another try.
+ llvm::Triple &module_triple =
+ resolved_module_spec.GetArchitecture().GetTriple();
+ bool is_vendor_specified =
+ (module_triple.getVendor() != llvm::Triple::UnknownVendor);
+ bool is_os_specified =
+ (module_triple.getOS() != llvm::Triple::UnknownOS);
+ if (!is_vendor_specified || !is_os_specified) {
+ const llvm::Triple &host_triple =
+ HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple();
+
+ if (!is_vendor_specified)
+ module_triple.setVendorName(host_triple.getVendorName());
+ if (!is_os_specified)
+ module_triple.setOSName(host_triple.getOSName());
+
+ error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp, module_search_paths_ptr, nullptr, nullptr);
+ }
+ }
+
+ // TODO find out why exe_module_sp might be NULL
+ if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) {
+ exe_module_sp.reset();
+ error.SetErrorStringWithFormat(
+ "'%s' doesn't contain the architecture %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+ } else {
+ // No valid architecture was specified, ask the platform for the
+ // architectures that we should be using (in the correct order) and see
+ // if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
+ idx, resolved_module_spec.GetArchitecture());
+ ++idx) {
+ error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
+ module_search_paths_ptr, nullptr, nullptr);
+ // Did we find an executable using one of the
+ if (error.Success()) {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString(", ");
+ arch_names.PutCString(
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp) {
+ if (FileSystem::Instance().Readable(
+ resolved_module_spec.GetFileSpec())) {
+ error.SetErrorStringWithFormat(
+ "'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(), arch_names.GetData());
+ } else {
+ error.SetErrorStringWithFormat(
+ "'%s' is not readable",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ }
+
+ return error;
}
Status RemoteAwarePlatform::RunShellCommand(
diff --git a/lldb/source/Target/SectionLoadHistory.cpp b/lldb/source/Target/SectionLoadHistory.cpp
index ec16b58b4451..f329d425e34b 100644
--- a/lldb/source/Target/SectionLoadHistory.cpp
+++ b/lldb/source/Target/SectionLoadHistory.cpp
@@ -1,4 +1,4 @@
-//===-- SectionLoadHistory.cpp ----------------------------------*- C++ -*-===//
+//===-- SectionLoadHistory.cpp --------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/SectionLoadList.cpp b/lldb/source/Target/SectionLoadList.cpp
index f2546a893194..f1a626b04802 100644
--- a/lldb/source/Target/SectionLoadList.cpp
+++ b/lldb/source/Target/SectionLoadList.cpp
@@ -1,4 +1,4 @@
-//===-- SectionLoadList.cpp -------------------------------------*- C++ -*-===//
+//===-- SectionLoadList.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -253,6 +253,6 @@ void SectionLoadList::Dump(Stream &s, Target *target) {
++pos) {
s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", pos->first,
static_cast<void *>(pos->second.get()));
- pos->second->Dump(&s, target, 0);
+ pos->second->Dump(s.AsRawOstream(), s.GetIndentLevel(), target, 0);
}
}
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 5c6ea7a03933..3d6cc5dc90b3 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -1,4 +1,4 @@
-//===-- StackFrame.cpp ------------------------------------------*- C++ -*-===//
+//===-- StackFrame.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -606,7 +606,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
}
// We are dumping at least one child
- while (separator_idx != std::string::npos) {
+ while (!var_expr.empty()) {
// Calculate the next separator index ahead of time
ValueObjectSP child_valobj_sp;
const char separator_type = var_expr[0];
@@ -673,7 +673,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
if (actual_is_ptr != expr_is_ptr) {
// Incorrect use of "." with a pointer, or "->" with a
// class/union/struct instance or reference.
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
if (actual_is_ptr)
error.SetErrorStringWithFormat(
"\"%s\" is a pointer and . was used to attempt to access "
@@ -709,7 +709,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
"this frame",
name_const_string.GetCString());
} else {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
if (child_name) {
error.SetErrorStringWithFormat(
"\"%s\" is not a member of \"(%s) %s\"",
@@ -782,7 +782,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
Status error;
ValueObjectSP temp(valobj_sp->Dereference(error));
if (error.Fail()) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"could not dereference \"(%s) %s\"",
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -800,7 +800,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
Status error;
ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true));
if (error.Fail()) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"could not get item 0 for \"(%s) %s\"",
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -837,7 +837,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
|| synthetic == valobj_sp) /* synthetic is the same as
the original object */
{
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"\"(%s) %s\" is not an array type",
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -846,7 +846,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
static_cast<uint32_t>(child_index) >=
synthetic
->GetNumChildren() /* synthetic does not have that many values */) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"array index %ld is not valid for \"(%s) %s\"", child_index,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -854,7 +854,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
} else {
child_valobj_sp = synthetic->GetChildAtIndex(child_index, true);
if (!child_valobj_sp) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"array index %ld is not valid for \"(%s) %s\"", child_index,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -865,7 +865,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
child_valobj_sp =
valobj_sp->GetSyntheticArrayMember(child_index, true);
if (!child_valobj_sp) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"failed to use pointer as array for index %ld for "
"\"(%s) %s\"",
@@ -884,7 +884,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
valobj_sp->GetSyntheticArrayMember(child_index, true);
if (!child_valobj_sp) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"array index %ld is not valid for \"(%s) %s\"", child_index,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -895,7 +895,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(
child_index, child_index, true);
if (!child_valobj_sp) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"bitfield range %ld-%ld is not valid for \"(%s) %s\"",
child_index, child_index,
@@ -909,7 +909,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
|| synthetic == valobj_sp) /* synthetic is the same as the
original object */
{
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"\"(%s) %s\" is not an array type",
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -918,7 +918,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
static_cast<uint32_t>(child_index) >=
synthetic
->GetNumChildren() /* synthetic does not have that many values */) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"array index %ld is not valid for \"(%s) %s\"", child_index,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -926,7 +926,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
} else {
child_valobj_sp = synthetic->GetChildAtIndex(child_index, true);
if (!child_valobj_sp) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"array index %ld is not valid for \"(%s) %s\"", child_index,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -940,7 +940,6 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
return ValueObjectSP();
}
- separator_idx = var_expr.find_first_of(".-[");
if (use_dynamic != eNoDynamicValues) {
ValueObjectSP dynamic_value_sp(
child_valobj_sp->GetDynamicValue(use_dynamic));
@@ -982,7 +981,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
Status error;
ValueObjectSP temp(valobj_sp->Dereference(error));
if (error.Fail()) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"could not dereference \"(%s) %s\"",
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -999,7 +998,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
Status error;
ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true));
if (error.Fail()) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"could not get item 0 for \"(%s) %s\"",
valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -1013,7 +1012,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
child_valobj_sp =
valobj_sp->GetSyntheticBitFieldChild(child_index, final_index, true);
if (!child_valobj_sp) {
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"bitfield range %ld-%ld is not valid for \"(%s) %s\"", child_index,
final_index, valobj_sp->GetTypeName().AsCString("<invalid type>"),
@@ -1025,7 +1024,6 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
return ValueObjectSP();
}
- separator_idx = var_expr.find_first_of(".-[");
if (use_dynamic != eNoDynamicValues) {
ValueObjectSP dynamic_value_sp(
child_valobj_sp->GetDynamicValue(use_dynamic));
@@ -1039,7 +1037,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
default:
// Failure...
{
- valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ valobj_sp->GetExpressionPath(var_expr_path_strm);
error.SetErrorStringWithFormat(
"unexpected char '%c' encountered after \"%s\" in \"%s\"",
separator_type, var_expr_path_strm.GetData(),
@@ -1051,9 +1049,6 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
if (child_valobj_sp)
valobj_sp = child_valobj_sp;
-
- if (var_expr.empty())
- break;
}
if (valobj_sp) {
if (deref) {
@@ -1321,14 +1316,13 @@ lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) {
pc_range.GetBaseAddress() = GetFrameCodeAddress();
pc_range.SetByteSize(target_arch.GetMaximumOpcodeByteSize());
- ExecutionContext exe_ctx(shared_from_this());
-
const char *plugin_name = nullptr;
const char *flavor = nullptr;
const bool prefer_file_cache = false;
- DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
- target_arch, plugin_name, flavor, exe_ctx, pc_range, prefer_file_cache);
+ DisassemblerSP disassembler_sp =
+ Disassembler::DisassembleRange(target_arch, plugin_name, flavor,
+ *target_sp, pc_range, prefer_file_cache);
if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) {
return ValueObjectSP();
@@ -1500,7 +1494,7 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
// +18 that assigns to rdi, and calls itself recursively for that dereference
// DoGuessValueAt(frame, rdi, 8, dis, vars, 0x18) finds the instruction at
// +14 that assigns to rdi, and calls itself recursively for that
- // derefernece
+ // dereference
// DoGuessValueAt(frame, rbp, -8, dis, vars, 0x14) finds "f" in the
// variable list.
// Returns a ValueObject for f. (That's what was stored at rbp-8 at +14)
@@ -1702,13 +1696,12 @@ lldb::ValueObjectSP StackFrame::GuessValueForRegisterAndOffset(ConstString reg,
return ValueObjectSP();
}
- ExecutionContext exe_ctx(shared_from_this());
-
const char *plugin_name = nullptr;
const char *flavor = nullptr;
const bool prefer_file_cache = false;
- DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
- target_arch, plugin_name, flavor, exe_ctx, pc_range, prefer_file_cache);
+ DisassemblerSP disassembler_sp =
+ Disassembler::DisassembleRange(target_arch, plugin_name, flavor,
+ *target_sp, pc_range, prefer_file_cache);
if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) {
return ValueObjectSP();
@@ -1863,6 +1856,7 @@ void StackFrame::UpdatePreviousFrameFromCurrentFrame(StackFrame &curr_frame) {
m_concrete_frame_index = curr_frame.m_concrete_frame_index;
m_reg_context_sp = curr_frame.m_reg_context_sp;
m_frame_code_addr = curr_frame.m_frame_code_addr;
+ m_behaves_like_zeroth_frame = curr_frame.m_behaves_like_zeroth_frame;
assert(!m_sc.target_sp || !curr_frame.m_sc.target_sp ||
m_sc.target_sp.get() == curr_frame.m_sc.target_sp.get());
assert(!m_sc.module_sp || !curr_frame.m_sc.module_sp ||
@@ -1942,16 +1936,14 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
const uint32_t disasm_lines = debugger.GetDisassemblyLineCount();
if (disasm_lines > 0) {
const ArchSpec &target_arch = target->GetArchitecture();
- AddressRange pc_range;
- pc_range.GetBaseAddress() = GetFrameCodeAddress();
- pc_range.SetByteSize(disasm_lines *
- target_arch.GetMaximumOpcodeByteSize());
const char *plugin_name = nullptr;
const char *flavor = nullptr;
const bool mixed_source_and_assembly = false;
Disassembler::Disassemble(
target->GetDebugger(), target_arch, plugin_name, flavor,
- exe_ctx, pc_range, disasm_lines, mixed_source_and_assembly, 0,
+ exe_ctx, GetFrameCodeAddress(),
+ {Disassembler::Limit::Instructions, disasm_lines},
+ mixed_source_and_assembly, 0,
Disassembler::eOptionMarkPCAddress, strm);
}
}
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp
index 87b49849bc99..e4f5d3028366 100644
--- a/lldb/source/Target/StackFrameList.cpp
+++ b/lldb/source/Target/StackFrameList.cpp
@@ -1,4 +1,4 @@
-//===-- StackFrameList.cpp --------------------------------------*- C++ -*-===//
+//===-- StackFrameList.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -218,17 +218,14 @@ void StackFrameList::SetCurrentInlinedDepth(uint32_t new_depth) {
}
void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx,
- Unwind *unwinder) {
+ Unwind &unwinder) {
assert(m_thread.IsValid() && "Expected valid thread");
assert(m_frames.size() <= end_idx && "Expected there to be frames to fill");
if (end_idx < m_concrete_frames_fetched)
return;
- if (!unwinder)
- return;
-
- uint32_t num_frames = unwinder->GetFramesUpTo(end_idx);
+ uint32_t num_frames = unwinder.GetFramesUpTo(end_idx);
if (num_frames <= end_idx + 1) {
// Done unwinding.
m_concrete_frames_fetched = UINT32_MAX;
@@ -239,13 +236,22 @@ void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx,
m_frames.resize(num_frames);
}
+/// A sequence of calls that comprise some portion of a backtrace. Each frame
+/// is represented as a pair of a callee (Function *) and an address within the
+/// callee.
+struct CallDescriptor {
+ Function *func;
+ CallEdge::AddrType address_type = CallEdge::AddrType::Call;
+ addr_t address = LLDB_INVALID_ADDRESS;
+};
+using CallSequence = std::vector<CallDescriptor>;
+
/// Find the unique path through the call graph from \p begin (with return PC
/// \p return_pc) to \p end. On success this path is stored into \p path, and
/// on failure \p path is unchanged.
static void FindInterveningFrames(Function &begin, Function &end,
ExecutionContext &exe_ctx, Target &target,
- addr_t return_pc,
- std::vector<Function *> &path,
+ addr_t return_pc, CallSequence &path,
ModuleList &images, Log *log) {
LLDB_LOG(log, "Finding frames between {0} and {1}, retn-pc={2:x}",
begin.GetDisplayName(), end.GetDisplayName(), return_pc);
@@ -278,24 +284,27 @@ static void FindInterveningFrames(Function &begin, Function &end,
// Fully explore the set of functions reachable from the first edge via tail
// calls in order to detect ambiguous executions.
struct DFS {
- std::vector<Function *> active_path = {};
- std::vector<Function *> solution_path = {};
+ CallSequence active_path = {};
+ CallSequence solution_path = {};
llvm::SmallPtrSet<Function *, 2> visited_nodes = {};
bool ambiguous = false;
Function *end;
ModuleList &images;
+ Target &target;
ExecutionContext &context;
- DFS(Function *end, ModuleList &images, ExecutionContext &context)
- : end(end), images(images), context(context) {}
+ DFS(Function *end, ModuleList &images, Target &target,
+ ExecutionContext &context)
+ : end(end), images(images), target(target), context(context) {}
- void search(Function &first_callee, std::vector<Function *> &path) {
- dfs(first_callee);
+ void search(CallEdge &first_edge, Function &first_callee,
+ CallSequence &path) {
+ dfs(first_edge, first_callee);
if (!ambiguous)
path = std::move(solution_path);
}
- void dfs(Function &callee) {
+ void dfs(CallEdge &current_edge, Function &callee) {
// Found a path to the target function.
if (&callee == end) {
if (solution_path.empty())
@@ -315,13 +324,16 @@ static void FindInterveningFrames(Function &begin, Function &end,
}
// Search the calls made from this callee.
- active_path.push_back(&callee);
+ active_path.push_back(CallDescriptor{&callee});
for (const auto &edge : callee.GetTailCallingEdges()) {
Function *next_callee = edge->GetCallee(images, context);
if (!next_callee)
continue;
- dfs(*next_callee);
+ std::tie(active_path.back().address_type, active_path.back().address) =
+ edge->GetCallerAddress(callee, target);
+
+ dfs(*edge, *next_callee);
if (ambiguous)
return;
}
@@ -329,7 +341,7 @@ static void FindInterveningFrames(Function &begin, Function &end,
}
};
- DFS(&end, images, exe_ctx).search(*first_callee, path);
+ DFS(&end, images, target, exe_ctx).search(*first_edge, *first_callee, path);
}
/// Given that \p next_frame will be appended to the frame list, synthesize
@@ -348,6 +360,11 @@ static void FindInterveningFrames(Function &begin, Function &end,
/// | ... | <- Not-yet-visited frames.
/// --------------
void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
+ // Cannot synthesize tail call frames when the stack is empty (there is no
+ // "previous" frame).
+ if (m_frames.empty())
+ return;
+
TargetSP target_sp = next_frame.CalculateTarget();
if (!target_sp)
return;
@@ -358,7 +375,6 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- assert(!m_frames.empty() && "Cannot synthesize frames in an empty stack");
StackFrame &prev_frame = *m_frames.back().get();
// Find the functions prev_frame and next_frame are stopped in. The function
@@ -378,7 +394,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
// Try to find the unique sequence of (tail) calls which led from next_frame
// to prev_frame.
- std::vector<Function *> path;
+ CallSequence path;
addr_t return_pc = next_reg_ctx_sp->GetPC();
Target &target = *target_sp.get();
ModuleList &images = next_frame.CalculateTarget()->GetImages();
@@ -388,14 +404,17 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
path, images, log);
// Push synthetic tail call frames.
- for (Function *callee : llvm::reverse(path)) {
+ for (auto calleeInfo : llvm::reverse(path)) {
+ Function *callee = calleeInfo.func;
uint32_t frame_idx = m_frames.size();
uint32_t concrete_frame_idx = next_frame.GetConcreteFrameIndex();
addr_t cfa = LLDB_INVALID_ADDRESS;
bool cfa_is_valid = false;
- addr_t pc =
- callee->GetAddressRange().GetBaseAddress().GetLoadAddress(&target);
- constexpr bool behaves_like_zeroth_frame = false;
+ addr_t pc = calleeInfo.address;
+ // If the callee address refers to the call instruction, we do not want to
+ // subtract 1 from this value.
+ const bool behaves_like_zeroth_frame =
+ calleeInfo.address_type == CallEdge::AddrType::Call;
SymbolContext sc;
callee->CalculateSymbolContext(&sc);
auto synth_frame = std::make_shared<StackFrame>(
@@ -403,7 +422,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
cfa_is_valid, pc, StackFrame::Kind::Artificial,
behaves_like_zeroth_frame, &sc);
m_frames.push_back(synth_frame);
- LLDB_LOG(log, "Pushed frame {0}", callee->GetDisplayName());
+ LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);
}
// If any frames were created, adjust next_frame's index.
@@ -421,7 +440,7 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
if (m_frames.size() > end_idx || GetAllFramesFetched())
return;
- Unwind *unwinder = m_thread.GetUnwinder();
+ Unwind &unwinder = m_thread.GetUnwinder();
if (!m_show_inlined_frames) {
GetOnlyConcreteFramesUpTo(end_idx, unwinder);
@@ -459,9 +478,8 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext());
if (reg_ctx_sp) {
- const bool success = unwinder &&
- unwinder->GetFrameInfoAtIndex(
- idx, cfa, pc, behaves_like_zeroth_frame);
+ const bool success = unwinder.GetFrameInfoAtIndex(
+ idx, cfa, pc, behaves_like_zeroth_frame);
// There shouldn't be any way not to get the frame info for frame
// 0. But if the unwinder can't make one, lets make one by hand
// with the SP as the CFA and see if that gets any further.
@@ -480,9 +498,8 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
}
} else {
- const bool success = unwinder &&
- unwinder->GetFrameInfoAtIndex(
- idx, cfa, pc, behaves_like_zeroth_frame);
+ const bool success =
+ unwinder.GetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame);
if (!success) {
// We've gotten to the end of the stack.
SetAllFramesFetched();
@@ -665,31 +682,28 @@ StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) {
// GetFramesUpTo.
frame_sp = m_frames[idx];
} else {
- Unwind *unwinder = m_thread.GetUnwinder();
- if (unwinder) {
- addr_t pc, cfa;
- bool behaves_like_zeroth_frame = (idx == 0);
- if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc,
- behaves_like_zeroth_frame)) {
- const bool cfa_is_valid = true;
- frame_sp = std::make_shared<StackFrame>(
- m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
- StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
-
- Function *function =
- frame_sp->GetSymbolContext(eSymbolContextFunction).function;
- if (function) {
- // When we aren't showing inline functions we always use the top
- // most function block as the scope.
- frame_sp->SetSymbolContextScope(&function->GetBlock(false));
- } else {
- // Set the symbol scope from the symbol regardless if it is nullptr
- // or valid.
- frame_sp->SetSymbolContextScope(
- frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol);
- }
- SetFrameAtIndex(idx, frame_sp);
+ addr_t pc, cfa;
+ bool behaves_like_zeroth_frame = (idx == 0);
+ if (m_thread.GetUnwinder().GetFrameInfoAtIndex(
+ idx, cfa, pc, behaves_like_zeroth_frame)) {
+ const bool cfa_is_valid = true;
+ frame_sp = std::make_shared<StackFrame>(
+ m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
+ StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
+
+ Function *function =
+ frame_sp->GetSymbolContext(eSymbolContextFunction).function;
+ if (function) {
+ // When we aren't showing inline functions we always use the top
+ // most function block as the scope.
+ frame_sp->SetSymbolContextScope(&function->GetBlock(false));
+ } else {
+ // Set the symbol scope from the symbol regardless if it is nullptr
+ // or valid.
+ frame_sp->SetSymbolContextScope(
+ frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol);
}
+ SetFrameAtIndex(idx, frame_sp);
}
}
} else if (original_idx == 0) {
diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp
index 75a6cd215126..7dc6e9d1e490 100644
--- a/lldb/source/Target/StackFrameRecognizer.cpp
+++ b/lldb/source/Target/StackFrameRecognizer.cpp
@@ -1,4 +1,4 @@
-//===-- StackFrameRecognizer.cpp --------------------------------*- C++ -*-===//
+//===-- StackFrameRecognizer.cpp ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -50,31 +50,42 @@ ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) {
class StackFrameRecognizerManagerImpl {
public:
- void AddRecognizer(StackFrameRecognizerSP recognizer,
- ConstString module, ConstString symbol,
+ void AddRecognizer(StackFrameRecognizerSP recognizer, ConstString module,
+ llvm::ArrayRef<ConstString> symbols,
bool first_instruction_only) {
- m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, false, module, RegularExpressionSP(),
- symbol, RegularExpressionSP(),
- first_instruction_only});
+ m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer,
+ false, module, RegularExpressionSP(), symbols,
+ RegularExpressionSP(), first_instruction_only});
}
void AddRecognizer(StackFrameRecognizerSP recognizer,
RegularExpressionSP module, RegularExpressionSP symbol,
bool first_instruction_only) {
- m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, true, ConstString(), module,
- ConstString(), symbol, first_instruction_only});
+ m_recognizers.push_front(
+ {(uint32_t)m_recognizers.size(), false, recognizer, true, ConstString(),
+ module, std::vector<ConstString>(), symbol, first_instruction_only});
}
- void ForEach(
- std::function<void(uint32_t recognized_id, std::string recognizer_name, std::string module,
- std::string symbol, bool regexp)> const &callback) {
+ void ForEach(std::function<
+ void(uint32_t recognized_id, std::string recognizer_name,
+ std::string module, llvm::ArrayRef<ConstString> symbols,
+ bool regexp)> const &callback) {
for (auto entry : m_recognizers) {
if (entry.is_regexp) {
- callback(entry.recognizer_id, entry.recognizer->GetName(), entry.module_regexp->GetText(),
- entry.symbol_regexp->GetText(), true);
+ std::string module_name;
+ std::string symbol_name;
+
+ if (entry.module_regexp)
+ module_name = entry.module_regexp->GetText().str();
+ if (entry.symbol_regexp)
+ symbol_name = entry.symbol_regexp->GetText().str();
+
+ callback(entry.recognizer_id, entry.recognizer->GetName(), module_name,
+ llvm::makeArrayRef(ConstString(symbol_name)), true);
+
} else {
- callback(entry.recognizer_id, entry.recognizer->GetName(), entry.module.GetCString(),
- entry.symbol.GetCString(), false);
+ callback(entry.recognizer_id, entry.recognizer->GetName(),
+ entry.module.GetCString(), entry.symbols, false);
}
}
}
@@ -91,8 +102,8 @@ public:
}
StackFrameRecognizerSP GetRecognizerForFrame(StackFrameSP frame) {
- const SymbolContext &symctx =
- frame->GetSymbolContext(eSymbolContextModule | eSymbolContextFunction);
+ const SymbolContext &symctx = frame->GetSymbolContext(
+ eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol);
ConstString function_name = symctx.GetFunctionName();
ModuleSP module_sp = symctx.module_sp;
if (!module_sp) return StackFrameRecognizerSP();
@@ -110,8 +121,9 @@ public:
if (entry.module_regexp)
if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue;
- if (entry.symbol)
- if (entry.symbol != function_name) continue;
+ if (!entry.symbols.empty())
+ if (!llvm::is_contained(entry.symbols, function_name))
+ continue;
if (entry.symbol_regexp)
if (!entry.symbol_regexp->Execute(function_name.GetStringRef()))
@@ -139,7 +151,7 @@ public:
bool is_regexp;
ConstString module;
RegularExpressionSP module_regexp;
- ConstString symbol;
+ std::vector<ConstString> symbols;
RegularExpressionSP symbol_regexp;
bool first_instruction_only;
};
@@ -155,9 +167,9 @@ StackFrameRecognizerManagerImpl &GetStackFrameRecognizerManagerImpl() {
void StackFrameRecognizerManager::AddRecognizer(
StackFrameRecognizerSP recognizer, ConstString module,
- ConstString symbol, bool first_instruction_only) {
- GetStackFrameRecognizerManagerImpl().AddRecognizer(recognizer, module, symbol,
- first_instruction_only);
+ llvm::ArrayRef<ConstString> symbols, bool first_instruction_only) {
+ GetStackFrameRecognizerManagerImpl().AddRecognizer(
+ recognizer, module, symbols, first_instruction_only);
}
void StackFrameRecognizerManager::AddRecognizer(
@@ -168,8 +180,9 @@ void StackFrameRecognizerManager::AddRecognizer(
}
void StackFrameRecognizerManager::ForEach(
- std::function<void(uint32_t recognized_id, std::string recognizer_name, std::string module,
- std::string symbol, bool regexp)> const &callback) {
+ std::function<void(uint32_t recognized_id, std::string recognizer_name,
+ std::string module, llvm::ArrayRef<ConstString> symbols,
+ bool regexp)> const &callback) {
GetStackFrameRecognizerManagerImpl().ForEach(callback);
}
diff --git a/lldb/source/Target/StackID.cpp b/lldb/source/Target/StackID.cpp
index a8f6b787f4b4..410d5b7e820a 100644
--- a/lldb/source/Target/StackID.cpp
+++ b/lldb/source/Target/StackID.cpp
@@ -1,4 +1,4 @@
-//===-- StackID.cpp ---------------------------------------------*- C++ -*-===//
+//===-- StackID.cpp -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 28179b7e1ce0..7e830c6e2bed 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -1,4 +1,4 @@
-//===-- StopInfo.cpp --------------------------------------------*- C++ -*-===//
+//===-- StopInfo.cpp ------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -206,7 +206,7 @@ public:
strm.Printf("breakpoint ");
bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
- m_description = strm.GetString();
+ m_description = std::string(strm.GetString());
} else {
StreamString strm;
if (m_break_id != LLDB_INVALID_BREAK_ID) {
@@ -239,7 +239,7 @@ public:
" which has been deleted - was at 0x%" PRIx64,
m_value, m_address);
- m_description = strm.GetString();
+ m_description = std::string(strm.GetString());
}
}
}
@@ -453,7 +453,7 @@ protected:
} else {
LLDB_LOGF(log,
"Condition evaluated for breakpoint %s on thread "
- "0x%llx conditon_says_stop: %i.",
+ "0x%llx condition_says_stop: %i.",
loc_desc.GetData(),
static_cast<unsigned long long>(thread_sp->GetID()),
condition_says_stop);
@@ -631,7 +631,7 @@ public:
if (m_description.empty()) {
StreamString strm;
strm.Printf("watchpoint %" PRIi64, m_value);
- m_description = strm.GetString();
+ m_description = std::string(strm.GetString());
}
return m_description.c_str();
}
@@ -969,7 +969,7 @@ public:
strm.Printf("signal %s", signal_name);
else
strm.Printf("signal %" PRIi64, m_value);
- m_description = strm.GetString();
+ m_description = std::string(strm.GetString());
}
}
return m_description.c_str();
@@ -1034,7 +1034,7 @@ public:
if (m_description.empty()) {
StreamString strm;
m_plan_sp->GetDescription(&strm, eDescriptionLevelBrief);
- m_description = strm.GetString();
+ m_description = std::string(strm.GetString());
}
return m_description.c_str();
}
diff --git a/lldb/source/Target/StructuredDataPlugin.cpp b/lldb/source/Target/StructuredDataPlugin.cpp
index a22902d99f7c..bd899d2f7681 100644
--- a/lldb/source/Target/StructuredDataPlugin.cpp
+++ b/lldb/source/Target/StructuredDataPlugin.cpp
@@ -1,4 +1,4 @@
-//===-- StructuredDataPlugin.cpp --------------------------------*- C++ -*-===//
+//===-- StructuredDataPlugin.cpp ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/SystemRuntime.cpp b/lldb/source/Target/SystemRuntime.cpp
index 286bea09f854..cd3d8ba2c7b0 100644
--- a/lldb/source/Target/SystemRuntime.cpp
+++ b/lldb/source/Target/SystemRuntime.cpp
@@ -1,4 +1,4 @@
-//===-- SystemRuntime.cpp ---------------------------------------*- C++ -*-===//
+//===-- SystemRuntime.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 83e6f3062666..dad56376005c 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -1,4 +1,4 @@
-//===-- Target.cpp ----------------------------------------------*- C++ -*-===//
+//===-- Target.cpp --------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -27,6 +27,7 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/ExpressionVariable.h"
#include "lldb/Expression/REPL.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Host/Host.h"
@@ -36,8 +37,6 @@
#include "lldb/Interpreter/OptionGroupWatchpoint.h"
#include "lldb/Interpreter/OptionValues.h"
#include "lldb/Interpreter/Property.h"
-#include "lldb/Symbol/ClangASTContext.h"
-#include "lldb/Symbol/ClangASTImporter.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
@@ -91,7 +90,7 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch,
m_mutex(), m_arch(target_arch), m_images(this), m_section_load_history(),
m_breakpoint_list(false), m_internal_breakpoint_list(true),
m_watchpoint_list(), m_process_sp(), m_search_filter_sp(),
- m_image_search_paths(ImageSearchPathsChanged, this), m_ast_importer_sp(),
+ m_image_search_paths(ImageSearchPathsChanged, this),
m_source_manager_up(), m_stop_hooks(), m_stop_hook_next_id(0),
m_valid(true), m_suppress_stop_hooks(false),
m_is_dummy_target(is_dummy_target),
@@ -114,6 +113,8 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch,
target_arch.GetArchitectureName(),
target_arch.GetTriple().getTriple().c_str());
}
+
+ UpdateLaunchInfoFromProperties();
}
Target::~Target() {
@@ -128,12 +129,13 @@ void Target::PrimeFromDummyTarget(Target *target) {
m_stop_hooks = target->m_stop_hooks;
- for (BreakpointSP breakpoint_sp : target->m_breakpoint_list.Breakpoints()) {
+ for (const auto &breakpoint_sp : target->m_breakpoint_list.Breakpoints()) {
if (breakpoint_sp->IsInternal())
continue;
- BreakpointSP new_bp(new Breakpoint(*this, *breakpoint_sp.get()));
- AddBreakpoint(new_bp, false);
+ BreakpointSP new_bp(
+ Breakpoint::CopyFromBreakpoint(shared_from_this(), *breakpoint_sp));
+ AddBreakpoint(std::move(new_bp), false);
}
for (auto bp_name_entry : target->m_breakpoint_names) {
@@ -622,7 +624,7 @@ BreakpointSP Target::CreateBreakpoint(SearchFilterSP &filter_sp,
const bool hardware = request_hardware || GetRequireHardwareBreakpoints();
bp_sp.reset(new Breakpoint(*this, filter_sp, resolver_sp, hardware,
resolve_indirect_symbols));
- resolver_sp->SetBreakpoint(bp_sp.get());
+ resolver_sp->SetBreakpoint(bp_sp);
AddBreakpoint(bp_sp, internal);
}
return bp_sp;
@@ -1109,8 +1111,8 @@ Status Target::CreateBreakpointsFromFile(const FileSpec &file,
!Breakpoint::SerializedBreakpointMatchesNames(bkpt_data_sp, names))
continue;
- BreakpointSP bkpt_sp =
- Breakpoint::CreateFromStructuredData(*this, bkpt_data_sp, error);
+ BreakpointSP bkpt_sp = Breakpoint::CreateFromStructuredData(
+ shared_from_this(), bkpt_data_sp, error);
if (!error.Success()) {
error.SetErrorStringWithFormat(
"Error restoring breakpoint %zu from %s: %s.", i,
@@ -1378,7 +1380,6 @@ void Target::ClearModules(bool delete_locations) {
m_section_load_history.Clear();
m_images.Clear();
m_scratch_type_system_map.Clear();
- m_ast_importer_sp.reset();
}
void Target::DidExec() {
@@ -2258,16 +2259,6 @@ Target::GetUtilityFunctionForLanguage(const char *text,
return utility_fn;
}
-ClangASTImporterSP Target::GetClangASTImporter() {
- if (m_valid) {
- if (!m_ast_importer_sp) {
- m_ast_importer_sp = std::make_shared<ClangASTImporter>();
- }
- return m_ast_importer_sp;
- }
- return ClangASTImporterSP();
-}
-
void Target::SettingsInitialize() { Process::SettingsInitialize(); }
void Target::SettingsTerminate() { Process::SettingsTerminate(); }
@@ -2368,11 +2359,9 @@ ExpressionResults Target::EvaluateExpression(
} else {
llvm::StringRef prefix = GetExpressionPrefixContents();
Status error;
- execution_results =
- UserExpression::Evaluate(exe_ctx, options, expr, prefix,
- result_valobj_sp, error, fixed_expression,
- nullptr, // Module
- ctx_obj);
+ execution_results = UserExpression::Evaluate(exe_ctx, options, expr, prefix,
+ result_valobj_sp, error,
+ fixed_expression, ctx_obj);
}
return execution_results;
@@ -2469,7 +2458,7 @@ lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) {
SourceManager &Target::GetSourceManager() {
if (!m_source_manager_up)
- m_source_manager_up.reset(new SourceManager(shared_from_this()));
+ m_source_manager_up = std::make_unique<SourceManager>(shared_from_this());
return *m_source_manager_up;
}
@@ -2567,7 +2556,7 @@ void Target::RunStopHooks() {
if (!any_active_hooks)
return;
- CommandReturnObject result;
+ CommandReturnObject result(m_debugger.GetUseColor());
std::vector<ExecutionContext> exc_ctx_with_reasons;
std::vector<SymbolContext> sym_ctx_with_reasons;
@@ -2691,8 +2680,10 @@ Status Target::Install(ProcessLaunchInfo *launch_info) {
if (platform_sp) {
if (platform_sp->IsRemote()) {
if (platform_sp->IsConnected()) {
- // Install all files that have an install path, and always install the
- // main executable when connected to a remote platform
+ // Install all files that have an install path when connected to a
+ // remote platform. If target.auto-install-main-executable is set then
+ // also install the main executable even if it does not have an explicit
+ // install path specified.
const ModuleList &modules = GetImages();
const size_t num_images = modules.GetSize();
for (size_t idx = 0; idx < num_images; ++idx) {
@@ -2703,10 +2694,8 @@ Status Target::Install(ProcessLaunchInfo *launch_info) {
if (local_file) {
FileSpec remote_file(module_sp->GetRemoteInstallFileSpec());
if (!remote_file) {
- if (is_main_executable) // TODO: add setting for always
- // installing main executable???
- {
- // Always install the main executable
+ if (is_main_executable && GetAutoInstallMainExecutable()) {
+ // Automatically install the main executable.
remote_file = platform_sp->GetRemoteWorkingDirectory();
remote_file.AppendPathComponent(
module_sp->GetFileSpec().GetFilename().GetCString());
@@ -2971,11 +2960,6 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
}
}
m_process_sp->RestoreProcessEvents();
- } else {
- Status error2;
- error2.SetErrorStringWithFormat("process launch failed: %s",
- error.AsCString());
- error = error2;
}
return error;
}
@@ -3153,7 +3137,7 @@ Target::StopHook::StopHook(const StopHook &rhs)
m_thread_spec_up(), m_active(rhs.m_active),
m_auto_continue(rhs.m_auto_continue) {
if (rhs.m_thread_spec_up)
- m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up));
+ m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
}
Target::StopHook::~StopHook() = default;
@@ -3360,16 +3344,13 @@ enum {
class TargetOptionValueProperties : public OptionValueProperties {
public:
- TargetOptionValueProperties(ConstString name)
- : OptionValueProperties(name), m_target(nullptr), m_got_host_env(false) {}
+ TargetOptionValueProperties(ConstString name) : OptionValueProperties(name) {}
// This constructor is used when creating TargetOptionValueProperties when it
// is part of a new lldb_private::Target instance. It will copy all current
// global property values as needed
- TargetOptionValueProperties(Target *target,
- const TargetPropertiesSP &target_properties_sp)
- : OptionValueProperties(*target_properties_sp->GetValueProperties()),
- m_target(target), m_got_host_env(false) {}
+ TargetOptionValueProperties(const TargetPropertiesSP &target_properties_sp)
+ : OptionValueProperties(*target_properties_sp->GetValueProperties()) {}
const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx,
bool will_modify,
@@ -3377,9 +3358,6 @@ public:
// When getting the value for a key from the target options, we will always
// try and grab the setting from the current target if there is one. Else
// we just use the one from this instance.
- if (idx == ePropertyEnvVars)
- GetHostEnvironmentIfNeeded();
-
if (exe_ctx) {
Target *target = exe_ctx->GetTargetPtr();
if (target) {
@@ -3392,49 +3370,14 @@ public:
}
return ProtectedGetPropertyAtIndex(idx);
}
-
- lldb::TargetSP GetTargetSP() { return m_target->shared_from_this(); }
-
-protected:
- void GetHostEnvironmentIfNeeded() const {
- if (!m_got_host_env) {
- if (m_target) {
- m_got_host_env = true;
- const uint32_t idx = ePropertyInheritEnv;
- if (GetPropertyAtIndexAsBoolean(
- nullptr, idx, g_target_properties[idx].default_uint_value != 0)) {
- PlatformSP platform_sp(m_target->GetPlatform());
- if (platform_sp) {
- Environment env = platform_sp->GetEnvironment();
- OptionValueDictionary *env_dict =
- GetPropertyAtIndexAsOptionValueDictionary(nullptr,
- ePropertyEnvVars);
- if (env_dict) {
- const bool can_replace = false;
- for (const auto &KV : env) {
- // Don't allow existing keys to be replaced with ones we get
- // from the platform environment
- env_dict->SetValueForKey(
- ConstString(KV.first()),
- OptionValueSP(new OptionValueString(KV.second.c_str())),
- can_replace);
- }
- }
- }
- }
- }
- }
- }
- Target *m_target;
- mutable bool m_got_host_env;
};
// TargetProperties
-#define LLDB_PROPERTIES_experimental
+#define LLDB_PROPERTIES_target_experimental
#include "TargetProperties.inc"
enum {
-#define LLDB_PROPERTIES_experimental
+#define LLDB_PROPERTIES_target_experimental
#include "TargetPropertiesEnum.inc"
};
@@ -3448,15 +3391,15 @@ public:
TargetExperimentalProperties::TargetExperimentalProperties()
: Properties(OptionValuePropertiesSP(
new TargetExperimentalOptionValueProperties())) {
- m_collection_sp->Initialize(g_experimental_properties);
+ m_collection_sp->Initialize(g_target_experimental_properties);
}
// TargetProperties
TargetProperties::TargetProperties(Target *target)
- : Properties(), m_launch_info() {
+ : Properties(), m_launch_info(), m_target(target) {
if (target) {
m_collection_sp = std::make_shared<TargetOptionValueProperties>(
- target, Target::GetGlobalProperties());
+ Target::GetGlobalProperties());
// Set callbacks to update launch_info whenever "settins set" updated any
// of these properties
@@ -3467,6 +3410,10 @@ TargetProperties::TargetProperties(Target *target)
m_collection_sp->SetValueChangedCallback(
ePropertyEnvVars, [this] { EnvVarsValueChangedCallback(); });
m_collection_sp->SetValueChangedCallback(
+ ePropertyUnsetEnvVars, [this] { EnvVarsValueChangedCallback(); });
+ m_collection_sp->SetValueChangedCallback(
+ ePropertyInheritEnv, [this] { EnvVarsValueChangedCallback(); });
+ m_collection_sp->SetValueChangedCallback(
ePropertyInputPath, [this] { InputPathValueChangedCallback(); });
m_collection_sp->SetValueChangedCallback(
ePropertyOutputPath, [this] { OutputPathValueChangedCallback(); });
@@ -3480,29 +3427,19 @@ TargetProperties::TargetProperties(Target *target)
m_collection_sp->SetValueChangedCallback(
ePropertyDisableSTDIO, [this] { DisableSTDIOValueChangedCallback(); });
- m_experimental_properties_up.reset(new TargetExperimentalProperties());
+ m_experimental_properties_up =
+ std::make_unique<TargetExperimentalProperties>();
m_collection_sp->AppendProperty(
ConstString(Properties::GetExperimentalSettingsName()),
ConstString("Experimental settings - setting these won't produce "
"errors if the setting is not present."),
true, m_experimental_properties_up->GetValueProperties());
-
- // Update m_launch_info once it was created
- Arg0ValueChangedCallback();
- RunArgsValueChangedCallback();
- // EnvVarsValueChangedCallback(); // FIXME: cause segfault in
- // Target::GetPlatform()
- InputPathValueChangedCallback();
- OutputPathValueChangedCallback();
- ErrorPathValueChangedCallback();
- DetachOnErrorValueChangedCallback();
- DisableASLRValueChangedCallback();
- DisableSTDIOValueChangedCallback();
} else {
m_collection_sp =
std::make_shared<TargetOptionValueProperties>(ConstString("target"));
m_collection_sp->Initialize(g_target_properties);
- m_experimental_properties_up.reset(new TargetExperimentalProperties());
+ m_experimental_properties_up =
+ std::make_unique<TargetExperimentalProperties>();
m_collection_sp->AppendProperty(
ConstString(Properties::GetExperimentalSettingsName()),
ConstString("Experimental settings - setting these won't produce "
@@ -3516,6 +3453,18 @@ TargetProperties::TargetProperties(Target *target)
TargetProperties::~TargetProperties() = default;
+void TargetProperties::UpdateLaunchInfoFromProperties() {
+ Arg0ValueChangedCallback();
+ RunArgsValueChangedCallback();
+ EnvVarsValueChangedCallback();
+ InputPathValueChangedCallback();
+ OutputPathValueChangedCallback();
+ ErrorPathValueChangedCallback();
+ DetachOnErrorValueChangedCallback();
+ DisableASLRValueChangedCallback();
+ DisableSTDIOValueChangedCallback();
+}
+
bool TargetProperties::GetInjectLocalVariables(
ExecutionContext *exe_ctx) const {
const Property *exp_property = m_collection_sp->GetPropertyAtIndex(
@@ -3657,19 +3606,43 @@ void TargetProperties::SetRunArguments(const Args &args) {
m_launch_info.GetArguments() = args;
}
+Environment TargetProperties::ComputeEnvironment() const {
+ Environment env;
+
+ if (m_target &&
+ m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, ePropertyInheritEnv,
+ g_target_properties[ePropertyInheritEnv].default_uint_value != 0)) {
+ if (auto platform_sp = m_target->GetPlatform()) {
+ Environment platform_env = platform_sp->GetEnvironment();
+ for (const auto &KV : platform_env)
+ env[KV.first()] = KV.second;
+ }
+ }
+
+ Args property_unset_env;
+ m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyUnsetEnvVars,
+ property_unset_env);
+ for (const auto &var : property_unset_env)
+ env.erase(var.ref());
+
+ Args property_env;
+ m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyEnvVars,
+ property_env);
+ for (const auto &KV : Environment(property_env))
+ env[KV.first()] = KV.second;
+
+ return env;
+}
+
Environment TargetProperties::GetEnvironment() const {
- // TODO: Get rid of the Args intermediate step
- Args env;
- const uint32_t idx = ePropertyEnvVars;
- m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, env);
- return Environment(env);
+ return ComputeEnvironment();
}
void TargetProperties::SetEnvironment(Environment env) {
// TODO: Get rid of the Args intermediate step
const uint32_t idx = ePropertyEnvVars;
m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, Args(env));
- m_launch_info.GetEnvironment() = std::move(env);
}
bool TargetProperties::GetSkipPrologue() const {
@@ -3741,6 +3714,12 @@ bool TargetProperties::GetEnableAutoApplyFixIts() const {
nullptr, idx, g_target_properties[idx].default_uint_value != 0);
}
+uint64_t TargetProperties::GetNumberOfRetriesWithFixits() const {
+ const uint32_t idx = ePropertyRetriesWithFixIts;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(
+ nullptr, idx, g_target_properties[idx].default_uint_value);
+}
+
bool TargetProperties::GetEnableNotifyAboutFixIts() const {
const uint32_t idx = ePropertyNotifyAboutFixIts;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
@@ -3970,6 +3949,12 @@ void TargetProperties::SetRequireHardwareBreakpoints(bool b) {
m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
}
+bool TargetProperties::GetAutoInstallMainExecutable() const {
+ const uint32_t idx = ePropertyAutoInstallMainExecutable;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_target_properties[idx].default_uint_value != 0);
+}
+
void TargetProperties::Arg0ValueChangedCallback() {
m_launch_info.SetArg0(GetArg0());
}
@@ -3981,7 +3966,7 @@ void TargetProperties::RunArgsValueChangedCallback() {
}
void TargetProperties::EnvVarsValueChangedCallback() {
- m_launch_info.GetEnvironment() = GetEnvironment();
+ m_launch_info.GetEnvironment() = ComputeEnvironment();
}
void TargetProperties::InputPathValueChangedCallback() {
@@ -4073,7 +4058,7 @@ Target::TargetEventData::GetModuleListFromEvent(const Event *event_ptr) {
return module_list;
}
-std::recursive_mutex &Target::GetAPIMutex() {
+std::recursive_mutex &Target::GetAPIMutex() {
if (GetProcessSP() && GetProcessSP()->CurrentThreadIsPrivateStateThread())
return m_private_mutex;
else
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
index 1b4db0c2aba5..3974cb5de419 100644
--- a/lldb/source/Target/TargetList.cpp
+++ b/lldb/source/Target/TargetList.cpp
@@ -1,4 +1,4 @@
-//===-- TargetList.cpp ------------------------------------------*- C++ -*-===//
+//===-- TargetList.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -398,6 +398,8 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
if (user_exe_path_is_bundle)
exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
sizeof(resolved_bundle_exe_path));
+ if (target_sp->GetPreloadSymbols())
+ exe_module_sp->PreloadSymbols();
}
} else {
// No file was specified, just create an empty target with any arch if a
diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td
index ff8062aaa2cb..ae3abe354856 100644
--- a/lldb/source/Target/TargetProperties.td
+++ b/lldb/source/Target/TargetProperties.td
@@ -1,6 +1,6 @@
include "../../include/lldb/Core/PropertiesBase.td"
-let Definition = "experimental" in {
+let Definition = "target_experimental" in {
def InjectLocalVars : Property<"inject-local-vars", "Boolean">,
Global, DefaultTrue,
Desc<"If true, inject local variables explicitly into the expression text. This will fix symbol resolution when there are name collisions between ivars and local variables. But it can make expressions run much more slowly.">;
@@ -51,6 +51,9 @@ let Definition = "target" in {
def AutoApplyFixIts: Property<"auto-apply-fixits", "Boolean">,
DefaultTrue,
Desc<"Automatically apply fix-it hints to expressions.">;
+ def RetriesWithFixIts: Property<"retries-with-fixits", "UInt64">,
+ DefaultUnsignedValue<1>,
+ Desc<"Maximum number of attempts to fix an expression with Fix-Its">;
def NotifyAboutFixIts: Property<"notify-about-fixits", "Boolean">,
DefaultTrue,
Desc<"Print the fixed expression text.">;
@@ -79,8 +82,11 @@ let Definition = "target" in {
DefaultStringValue<"">,
Desc<"A list containing all the arguments to be passed to the executable when it is run. Note that this does NOT include the argv[0] which is in target.arg0.">;
def EnvVars: Property<"env-vars", "Dictionary">,
- DefaultUnsignedValue<16>,
- Desc<"A list of all the environment variables to be passed to the executable's environment, and their values.">;
+ ElementType<"String">,
+ Desc<"A list of user provided environment variables to be passed to the executable's environment, and their values.">;
+ def UnsetEnvVars: Property<"unset-env-vars", "Array">,
+ ElementType<"String">,
+ Desc<"A list of environment variable names to be unset in the inferior's environment. This is most useful to unset some host environment variables when target.inherit-env is true. target.env-vars takes precedence over target.unset-env-vars.">;
def InheritEnv: Property<"inherit-env", "Boolean">,
DefaultTrue,
Desc<"Inherit the environment from the process that is running LLDB.">;
@@ -140,7 +146,7 @@ let Definition = "target" in {
Desc<"Expressions that crash will show up in crash logs if the host system supports executable specific crash log strings and this setting is set to true.">;
def TrapHandlerNames: Property<"trap-handler-names", "Array">,
Global,
- DefaultUnsignedValue<16>,
+ ElementType<"String">,
Desc<"A list of trap handler function names, e.g. a common Unix user process one is _sigtramp.">;
def DisplayRuntimeSupportValues: Property<"display-runtime-support-values", "Boolean">,
DefaultFalse,
@@ -154,6 +160,16 @@ let Definition = "target" in {
def RequireHardwareBreakpoints: Property<"require-hardware-breakpoint", "Boolean">,
DefaultFalse,
Desc<"Require all breakpoints to be hardware breakpoints.">;
+ def AutoInstallMainExecutable: Property<"auto-install-main-executable", "Boolean">,
+ DefaultTrue,
+ Desc<"Always install the main executable when connected to a remote platform.">;
+}
+
+let Definition = "process_experimental" in {
+ def OSPluginReportsAllThreads: Property<"os-plugin-reports-all-threads", "Boolean">,
+ Global,
+ DefaultTrue,
+ Desc<"Set to False if your OS Plugins doesn't report all threads on each stop.">;
}
let Definition = "process" in {
@@ -161,7 +177,7 @@ let Definition = "process" in {
DefaultFalse,
Desc<"Disable reading and caching of memory in fixed-size units.">;
def ExtraStartCommand: Property<"extra-startup-command", "Array">,
- DefaultUnsignedValue<16>,
+ ElementType<"String">,
Desc<"A list containing extra commands understood by the particular process plugin used. For instance, to turn on debugserver logging set this to 'QSetLogging:bitmask=LOG_DEFAULT;'">;
def IgnoreBreakpointsInExpressions: Property<"ignore-breakpoints-in-expressions", "Boolean">,
Global,
@@ -188,6 +204,9 @@ let Definition = "process" in {
def WarningOptimization: Property<"optimization-warnings", "Boolean">,
DefaultTrue,
Desc<"If true, warn when stopped in code that is optimized where stepping and variable availability may not behave as expected.">;
+ def WarningUnsupportedLanguage: Property<"unsupported-language-warnings", "Boolean">,
+ DefaultTrue,
+ Desc<"If true, warn when stopped in code that is written in a source language that LLDB does not support.">;
def StopOnExec: Property<"stop-on-exec", "Boolean">,
Global,
DefaultTrue,
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index e12b90501103..24cf4bf3ee1e 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -1,4 +1,4 @@
-//===-- Thread.cpp ----------------------------------------------*- C++ -*-===//
+//===-- Thread.cpp --------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,8 +7,6 @@
//===----------------------------------------------------------------------===//
#include "lldb/Target/Thread.h"
-#include "Plugins/Process/Utility/UnwindLLDB.h"
-#include "Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FormatEntity.h"
@@ -35,6 +33,7 @@
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Target/ThreadPlanPython.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/ThreadPlanStack.h"
#include "lldb/Target/ThreadPlanStepInRange.h"
#include "lldb/Target/ThreadPlanStepInstruction.h"
#include "lldb/Target/ThreadPlanStepOut.h"
@@ -43,7 +42,7 @@
#include "lldb/Target/ThreadPlanStepThrough.h"
#include "lldb/Target/ThreadPlanStepUntil.h"
#include "lldb/Target/ThreadSpec.h"
-#include "lldb/Target/Unwind.h"
+#include "lldb/Target/UnwindLLDB.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/State.h"
@@ -230,8 +229,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id)
m_index_id(use_invalid_index_id ? LLDB_INVALID_INDEX32
: process.GetNextThreadIndexID(tid)),
m_reg_context_sp(), m_state(eStateUnloaded), m_state_mutex(),
- m_plan_stack(), m_completed_plan_stack(), m_frame_mutex(),
- m_curr_frames_sp(), m_prev_frames_sp(),
+ m_frame_mutex(), m_curr_frames_sp(), m_prev_frames_sp(),
m_resume_signal(LLDB_INVALID_SIGNAL_NUMBER),
m_resume_state(eStateRunning), m_temporary_resume_state(eStateRunning),
m_unwinder_up(), m_destroy_called(false),
@@ -242,8 +240,6 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id)
static_cast<void *>(this), GetID());
CheckInWithManager();
-
- QueueFundamentalPlan(true);
}
Thread::~Thread() {
@@ -256,30 +252,7 @@ Thread::~Thread() {
}
void Thread::DestroyThread() {
- // Tell any plans on the plan stacks that the thread is being destroyed since
- // any plans that have a thread go away in the middle of might need to do
- // cleanup, or in some cases NOT do cleanup...
- for (auto plan : m_plan_stack)
- plan->ThreadDestroyed();
-
- for (auto plan : m_discarded_plan_stack)
- plan->ThreadDestroyed();
-
- for (auto plan : m_completed_plan_stack)
- plan->ThreadDestroyed();
-
m_destroy_called = true;
- m_plan_stack.clear();
- m_discarded_plan_stack.clear();
- m_completed_plan_stack.clear();
-
- // Push a ThreadPlanNull on the plan stack. That way we can continue
- // assuming that the plan stack is never empty, but if somebody errantly asks
- // questions of a destroyed thread without checking first whether it is
- // destroyed, they won't crash.
- ThreadPlanSP null_plan_sp(new ThreadPlanNull(*this));
- m_plan_stack.push_back(null_plan_sp);
-
m_stop_info_sp.reset();
m_reg_context_sp.reset();
m_unwinder_up.reset();
@@ -298,7 +271,7 @@ lldb::StackFrameSP Thread::GetSelectedFrame() {
StackFrameListSP stack_frame_list_sp(GetStackFrameList());
StackFrameSP frame_sp = stack_frame_list_sp->GetFrameAtIndex(
stack_frame_list_sp->GetSelectedFrameIndex());
- FunctionOptimizationWarning(frame_sp.get());
+ FrameSelectedCallback(frame_sp.get());
return frame_sp;
}
@@ -307,7 +280,7 @@ uint32_t Thread::SetSelectedFrame(lldb_private::StackFrame *frame,
uint32_t ret_value = GetStackFrameList()->SetSelectedFrame(frame);
if (broadcast)
BroadcastSelectedFrameChange(frame->GetStackID());
- FunctionOptimizationWarning(frame);
+ FrameSelectedCallback(frame);
return ret_value;
}
@@ -317,7 +290,7 @@ bool Thread::SetSelectedFrameByIndex(uint32_t frame_idx, bool broadcast) {
GetStackFrameList()->SetSelectedFrame(frame_sp.get());
if (broadcast)
BroadcastSelectedFrameChange(frame_sp->GetStackID());
- FunctionOptimizationWarning(frame_sp.get());
+ FrameSelectedCallback(frame_sp.get());
return true;
} else
return false;
@@ -341,7 +314,7 @@ bool Thread::SetSelectedFrameByIndexNoisily(uint32_t frame_idx,
bool show_frame_info = true;
bool show_source = !already_shown;
- FunctionOptimizationWarning(frame_sp.get());
+ FrameSelectedCallback(frame_sp.get());
return frame_sp->GetStatus(output_stream, show_frame_info, show_source);
}
return false;
@@ -349,12 +322,17 @@ bool Thread::SetSelectedFrameByIndexNoisily(uint32_t frame_idx,
return false;
}
-void Thread::FunctionOptimizationWarning(StackFrame *frame) {
- if (frame && frame->HasDebugInformation() &&
- GetProcess()->GetWarningsOptimization()) {
+void Thread::FrameSelectedCallback(StackFrame *frame) {
+ if (!frame)
+ return;
+
+ if (frame->HasDebugInformation() &&
+ (GetProcess()->GetWarningsOptimization() ||
+ GetProcess()->GetWarningsUnsupportedLanguage())) {
SymbolContext sc =
frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextModule);
GetProcess()->PrintWarningOptimization(sc);
+ GetProcess()->PrintWarningUnsupportedLanguage(sc);
}
}
@@ -423,7 +401,7 @@ lldb::StopInfoSP Thread::GetPrivateStopInfo() {
// "m_stop_info_stop_id != process_stop_id" as the condition for the if
// statement below, we must also check the stop info to see if we need to
// override it. See the header documentation in
- // Process::GetStopInfoOverrideCallback() for more information on the stop
+ // Architecture::OverrideStopInfo() for more information on the stop
// info override callback.
if (m_stop_info_override_stop_id != process_stop_id) {
m_stop_info_override_stop_id = process_stop_id;
@@ -524,7 +502,8 @@ bool Thread::CheckpointThreadState(ThreadStateCheckpoint &saved_state) {
if (process_sp)
saved_state.orig_stop_id = process_sp->GetStopID();
saved_state.current_inlined_depth = GetCurrentInlinedDepth();
- saved_state.m_completed_plan_stack = m_completed_plan_stack;
+ saved_state.m_completed_plan_checkpoint =
+ GetPlans().CheckpointCompletedPlans();
return true;
}
@@ -558,7 +537,8 @@ bool Thread::RestoreThreadStateFromCheckpoint(
SetStopInfo(saved_state.stop_info_sp);
GetStackFrameList()->SetCurrentInlinedDepth(
saved_state.current_inlined_depth);
- m_completed_plan_stack = saved_state.m_completed_plan_stack;
+ GetPlans().RestoreCompletedPlanCheckpoint(
+ saved_state.m_completed_plan_checkpoint);
return true;
}
@@ -573,9 +553,68 @@ void Thread::SetState(StateType state) {
m_state = state;
}
+std::string Thread::GetStopDescription() {
+ StackFrameSP frame_sp = GetStackFrameAtIndex(0);
+
+ if (!frame_sp)
+ return GetStopDescriptionRaw();
+
+ auto recognized_frame_sp = frame_sp->GetRecognizedFrame();
+
+ if (!recognized_frame_sp)
+ return GetStopDescriptionRaw();
+
+ std::string recognized_stop_description =
+ recognized_frame_sp->GetStopDescription();
+
+ if (!recognized_stop_description.empty())
+ return recognized_stop_description;
+
+ return GetStopDescriptionRaw();
+}
+
+std::string Thread::GetStopDescriptionRaw() {
+ StopInfoSP stop_info_sp = GetStopInfo();
+ std::string raw_stop_description;
+ if (stop_info_sp && stop_info_sp->IsValid()) {
+ raw_stop_description = stop_info_sp->GetDescription();
+ assert((!raw_stop_description.empty() ||
+ stop_info_sp->GetStopReason() == eStopReasonNone) &&
+ "StopInfo returned an empty description.");
+ }
+ return raw_stop_description;
+}
+
+void Thread::SelectMostRelevantFrame() {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD);
+
+ auto frames_list_sp = GetStackFrameList();
+
+ // Only the top frame should be recognized.
+ auto frame_sp = frames_list_sp->GetFrameAtIndex(0);
+
+ auto recognized_frame_sp = frame_sp->GetRecognizedFrame();
+
+ if (!recognized_frame_sp) {
+ LLDB_LOG(log, "Frame #0 not recognized");
+ return;
+ }
+
+ if (StackFrameSP most_relevant_frame_sp =
+ recognized_frame_sp->GetMostRelevantFrame()) {
+ LLDB_LOG(log, "Found most relevant frame at index {0}",
+ most_relevant_frame_sp->GetFrameIndex());
+ SetSelectedFrame(most_relevant_frame_sp.get());
+ } else {
+ LLDB_LOG(log, "No relevant frame!");
+ }
+}
+
void Thread::WillStop() {
ThreadPlan *current_plan = GetCurrentPlan();
+ SelectMostRelevantFrame();
+
// FIXME: I may decide to disallow threads with no plans. In which
// case this should go to an assert.
@@ -632,8 +671,7 @@ void Thread::SetupForResume() {
bool Thread::ShouldResume(StateType resume_state) {
// At this point clear the completed plan stack.
- m_completed_plan_stack.clear();
- m_discarded_plan_stack.clear();
+ GetPlans().WillResume();
m_override_should_notify = eLazyBoolCalculate;
StateType prev_resume_state = GetTemporaryResumeState();
@@ -744,7 +782,9 @@ bool Thread::ShouldStop(Event *event_ptr) {
LLDB_LOGF(log, "^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^");
StreamString s;
s.IndentMore();
- DumpThreadPlans(&s);
+ GetProcess()->DumpThreadPlansForTID(
+ s, GetID(), eDescriptionLevelVerbose, true /* internal */,
+ false /* condense_trivial */, true /* skip_unreported */);
LLDB_LOGF(log, "Plan stack initial state:\n%s", s.GetData());
}
@@ -827,7 +867,7 @@ bool Thread::ShouldStop(Event *event_ptr) {
current_plan->GetName(), over_ride_stop);
// We're starting from the base plan, so just let it decide;
- if (PlanIsBasePlan(current_plan)) {
+ if (current_plan->IsBasePlan()) {
should_stop = current_plan->ShouldStop(event_ptr);
LLDB_LOGF(log, "Base plan says should stop: %i.", should_stop);
} else {
@@ -835,7 +875,7 @@ bool Thread::ShouldStop(Event *event_ptr) {
// to do, since presumably if there were other plans they would know what
// to do...
while (true) {
- if (PlanIsBasePlan(current_plan))
+ if (current_plan->IsBasePlan())
break;
should_stop = current_plan->ShouldStop(event_ptr);
@@ -881,7 +921,7 @@ bool Thread::ShouldStop(Event *event_ptr) {
// Discard the stale plans and all plans below them in the stack, plus move
// the completed plans to the completed plan stack
- while (!PlanIsBasePlan(plan_ptr)) {
+ while (!plan_ptr->IsBasePlan()) {
bool stale = plan_ptr->IsPlanStale();
ThreadPlan *examined_plan = plan_ptr;
plan_ptr = GetPreviousPlan(examined_plan);
@@ -908,7 +948,9 @@ bool Thread::ShouldStop(Event *event_ptr) {
if (log) {
StreamString s;
s.IndentMore();
- DumpThreadPlans(&s);
+ GetProcess()->DumpThreadPlansForTID(
+ s, GetID(), eDescriptionLevelVerbose, true /* internal */,
+ false /* condense_trivial */, true /* skip_unreported */);
LLDB_LOGF(log, "Plan stack final state:\n%s", s.GetData());
LLDB_LOGF(log, "vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv",
should_stop);
@@ -947,13 +989,14 @@ Vote Thread::ShouldReportStop(Event *event_ptr) {
return eVoteNoOpinion;
}
- if (m_completed_plan_stack.size() > 0) {
- // Don't use GetCompletedPlan here, since that suppresses private plans.
+ if (GetPlans().AnyCompletedPlans()) {
+ // Pass skip_private = false to GetCompletedPlan, since we want to ask
+ // the last plan, regardless of whether it is private or not.
LLDB_LOGF(log,
"Thread::ShouldReportStop() tid = 0x%4.4" PRIx64
": returning vote for complete stack's back plan",
GetID());
- return m_completed_plan_stack.back()->ShouldReportStop(event_ptr);
+ return GetPlans().GetCompletedPlan(false)->ShouldReportStop(event_ptr);
} else {
Vote thread_vote = eVoteNoOpinion;
ThreadPlan *plan_ptr = GetCurrentPlan();
@@ -962,7 +1005,7 @@ Vote Thread::ShouldReportStop(Event *event_ptr) {
thread_vote = plan_ptr->ShouldReportStop(event_ptr);
break;
}
- if (PlanIsBasePlan(plan_ptr))
+ if (plan_ptr->IsBasePlan())
break;
else
plan_ptr = GetPreviousPlan(plan_ptr);
@@ -984,16 +1027,17 @@ Vote Thread::ShouldReportRun(Event *event_ptr) {
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- if (m_completed_plan_stack.size() > 0) {
- // Don't use GetCompletedPlan here, since that suppresses private plans.
+ if (GetPlans().AnyCompletedPlans()) {
+ // Pass skip_private = false to GetCompletedPlan, since we want to ask
+ // the last plan, regardless of whether it is private or not.
LLDB_LOGF(log,
"Current Plan for thread %d(%p) (0x%4.4" PRIx64
", %s): %s being asked whether we should report run.",
GetIndexID(), static_cast<void *>(this), GetID(),
StateAsCString(GetTemporaryResumeState()),
- m_completed_plan_stack.back()->GetName());
+ GetCompletedPlan()->GetName());
- return m_completed_plan_stack.back()->ShouldReportRun(event_ptr);
+ return GetPlans().GetCompletedPlan(false)->ShouldReportRun(event_ptr);
} else {
LLDB_LOGF(log,
"Current Plan for thread %d(%p) (0x%4.4" PRIx64
@@ -1010,148 +1054,85 @@ bool Thread::MatchesSpec(const ThreadSpec *spec) {
return (spec == nullptr) ? true : spec->ThreadPassesBasicTests(*this);
}
-void Thread::PushPlan(ThreadPlanSP &thread_plan_sp) {
- if (thread_plan_sp) {
- // If the thread plan doesn't already have a tracer, give it its parent's
- // tracer:
- if (!thread_plan_sp->GetThreadPlanTracer()) {
- assert(!m_plan_stack.empty());
- thread_plan_sp->SetThreadPlanTracer(
- m_plan_stack.back()->GetThreadPlanTracer());
- }
- m_plan_stack.push_back(thread_plan_sp);
+ThreadPlanStack &Thread::GetPlans() const {
+ ThreadPlanStack *plans = GetProcess()->FindThreadPlans(GetID());
+ if (plans)
+ return *plans;
- thread_plan_sp->DidPush();
+ // History threads don't have a thread plan, but they do ask get asked to
+ // describe themselves, which usually involves pulling out the stop reason.
+ // That in turn will check for a completed plan on the ThreadPlanStack.
+ // Instead of special-casing at that point, we return a Stack with a
+ // ThreadPlanNull as its base plan. That will give the right answers to the
+ // queries GetDescription makes, and only assert if you try to run the thread.
+ if (!m_null_plan_stack_up)
+ m_null_plan_stack_up = std::make_unique<ThreadPlanStack>(*this, true);
+ return *(m_null_plan_stack_up.get());
+}
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- if (log) {
- StreamString s;
- thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
- LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".",
- static_cast<void *>(this), s.GetData(),
- thread_plan_sp->GetThread().GetID());
- }
+void Thread::PushPlan(ThreadPlanSP thread_plan_sp) {
+ assert(thread_plan_sp && "Don't push an empty thread plan.");
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
+ if (log) {
+ StreamString s;
+ thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
+ LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".",
+ static_cast<void *>(this), s.GetData(),
+ thread_plan_sp->GetThread().GetID());
}
+
+ GetPlans().PushPlan(std::move(thread_plan_sp));
}
void Thread::PopPlan() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
-
- if (m_plan_stack.size() <= 1)
- return;
- else {
- ThreadPlanSP &plan = m_plan_stack.back();
- if (log) {
- LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".",
- plan->GetName(), plan->GetThread().GetID());
- }
- m_completed_plan_stack.push_back(plan);
- plan->WillPop();
- m_plan_stack.pop_back();
+ ThreadPlanSP popped_plan_sp = GetPlans().PopPlan();
+ if (log) {
+ LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".",
+ popped_plan_sp->GetName(), popped_plan_sp->GetThread().GetID());
}
}
void Thread::DiscardPlan() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- if (m_plan_stack.size() > 1) {
- ThreadPlanSP &plan = m_plan_stack.back();
- LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".",
- plan->GetName(), plan->GetThread().GetID());
-
- m_discarded_plan_stack.push_back(plan);
- plan->WillPop();
- m_plan_stack.pop_back();
- }
-}
+ ThreadPlanSP discarded_plan_sp = GetPlans().PopPlan();
-ThreadPlan *Thread::GetCurrentPlan() {
- // There will always be at least the base plan. If somebody is mucking with
- // a thread with an empty plan stack, we should assert right away.
- return m_plan_stack.empty() ? nullptr : m_plan_stack.back().get();
+ LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".",
+ discarded_plan_sp->GetName(),
+ discarded_plan_sp->GetThread().GetID());
}
-ThreadPlanSP Thread::GetCompletedPlan() {
- ThreadPlanSP empty_plan_sp;
- if (!m_completed_plan_stack.empty()) {
- for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) {
- ThreadPlanSP completed_plan_sp;
- completed_plan_sp = m_completed_plan_stack[i];
- if (!completed_plan_sp->GetPrivate())
- return completed_plan_sp;
- }
- }
- return empty_plan_sp;
+ThreadPlan *Thread::GetCurrentPlan() const {
+ return GetPlans().GetCurrentPlan().get();
}
-ValueObjectSP Thread::GetReturnValueObject() {
- if (!m_completed_plan_stack.empty()) {
- for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) {
- ValueObjectSP return_valobj_sp;
- return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject();
- if (return_valobj_sp)
- return return_valobj_sp;
- }
- }
- return ValueObjectSP();
+ThreadPlanSP Thread::GetCompletedPlan() const {
+ return GetPlans().GetCompletedPlan();
}
-ExpressionVariableSP Thread::GetExpressionVariable() {
- if (!m_completed_plan_stack.empty()) {
- for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) {
- ExpressionVariableSP expression_variable_sp;
- expression_variable_sp =
- m_completed_plan_stack[i]->GetExpressionVariable();
- if (expression_variable_sp)
- return expression_variable_sp;
- }
- }
- return ExpressionVariableSP();
+ValueObjectSP Thread::GetReturnValueObject() const {
+ return GetPlans().GetReturnValueObject();
}
-bool Thread::IsThreadPlanDone(ThreadPlan *plan) {
- if (!m_completed_plan_stack.empty()) {
- for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) {
- if (m_completed_plan_stack[i].get() == plan)
- return true;
- }
- }
- return false;
+ExpressionVariableSP Thread::GetExpressionVariable() const {
+ return GetPlans().GetExpressionVariable();
}
-bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) {
- if (!m_discarded_plan_stack.empty()) {
- for (int i = m_discarded_plan_stack.size() - 1; i >= 0; i--) {
- if (m_discarded_plan_stack[i].get() == plan)
- return true;
- }
- }
- return false;
+bool Thread::IsThreadPlanDone(ThreadPlan *plan) const {
+ return GetPlans().IsPlanDone(plan);
}
-bool Thread::CompletedPlanOverridesBreakpoint() {
- return (!m_completed_plan_stack.empty()) ;
+bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) const {
+ return GetPlans().WasPlanDiscarded(plan);
}
-ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) {
- if (current_plan == nullptr)
- return nullptr;
-
- int stack_size = m_completed_plan_stack.size();
- for (int i = stack_size - 1; i > 0; i--) {
- if (current_plan == m_completed_plan_stack[i].get())
- return m_completed_plan_stack[i - 1].get();
- }
-
- if (stack_size > 0 && m_completed_plan_stack[0].get() == current_plan) {
- return GetCurrentPlan();
- }
+bool Thread::CompletedPlanOverridesBreakpoint() const {
+ return GetPlans().AnyCompletedPlans();
+}
- stack_size = m_plan_stack.size();
- for (int i = stack_size - 1; i > 0; i--) {
- if (current_plan == m_plan_stack[i].get())
- return m_plan_stack[i - 1].get();
- }
- return nullptr;
+ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) const{
+ return GetPlans().GetPreviousPlan(current_plan);
}
Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp,
@@ -1185,38 +1166,18 @@ Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp,
}
void Thread::EnableTracer(bool value, bool single_stepping) {
- int stack_size = m_plan_stack.size();
- for (int i = 0; i < stack_size; i++) {
- if (m_plan_stack[i]->GetThreadPlanTracer()) {
- m_plan_stack[i]->GetThreadPlanTracer()->EnableTracing(value);
- m_plan_stack[i]->GetThreadPlanTracer()->EnableSingleStep(single_stepping);
- }
- }
+ GetPlans().EnableTracer(value, single_stepping);
}
void Thread::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) {
- int stack_size = m_plan_stack.size();
- for (int i = 0; i < stack_size; i++)
- m_plan_stack[i]->SetThreadPlanTracer(tracer_sp);
+ GetPlans().SetTracer(tracer_sp);
}
-bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t thread_index) {
+bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t plan_index) {
// Count the user thread plans from the back end to get the number of the one
// we want to discard:
- uint32_t idx = 0;
- ThreadPlan *up_to_plan_ptr = nullptr;
-
- for (ThreadPlanSP plan_sp : m_plan_stack) {
- if (plan_sp->GetPrivate())
- continue;
- if (idx == thread_index) {
- up_to_plan_ptr = plan_sp.get();
- break;
- } else
- idx++;
- }
-
+ ThreadPlan *up_to_plan_ptr = GetPlans().GetPlanByIndex(plan_index).get();
if (up_to_plan_ptr == nullptr)
return false;
@@ -1234,30 +1195,7 @@ void Thread::DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr) {
"Discarding thread plans for thread tid = 0x%4.4" PRIx64
", up to %p",
GetID(), static_cast<void *>(up_to_plan_ptr));
-
- int stack_size = m_plan_stack.size();
-
- // If the input plan is nullptr, discard all plans. Otherwise make sure this
- // plan is in the stack, and if so discard up to and including it.
-
- if (up_to_plan_ptr == nullptr) {
- for (int i = stack_size - 1; i > 0; i--)
- DiscardPlan();
- } else {
- bool found_it = false;
- for (int i = stack_size - 1; i > 0; i--) {
- if (m_plan_stack[i].get() == up_to_plan_ptr)
- found_it = true;
- }
- if (found_it) {
- bool last_one = false;
- for (int i = stack_size - 1; i > 0 && !last_one; i--) {
- if (GetCurrentPlan() == up_to_plan_ptr)
- last_one = true;
- DiscardPlan();
- }
- }
- }
+ GetPlans().DiscardPlansUpToPlan(up_to_plan_ptr);
}
void Thread::DiscardThreadPlans(bool force) {
@@ -1270,73 +1208,20 @@ void Thread::DiscardThreadPlans(bool force) {
}
if (force) {
- int stack_size = m_plan_stack.size();
- for (int i = stack_size - 1; i > 0; i--) {
- DiscardPlan();
- }
+ GetPlans().DiscardAllPlans();
return;
}
-
- while (true) {
- int master_plan_idx;
- bool discard = true;
-
- // Find the first master plan, see if it wants discarding, and if yes
- // discard up to it.
- for (master_plan_idx = m_plan_stack.size() - 1; master_plan_idx >= 0;
- master_plan_idx--) {
- if (m_plan_stack[master_plan_idx]->IsMasterPlan()) {
- discard = m_plan_stack[master_plan_idx]->OkayToDiscard();
- break;
- }
- }
-
- if (discard) {
- // First pop all the dependent plans:
- for (int i = m_plan_stack.size() - 1; i > master_plan_idx; i--) {
- // FIXME: Do we need a finalize here, or is the rule that
- // "PrepareForStop"
- // for the plan leaves it in a state that it is safe to pop the plan
- // with no more notice?
- DiscardPlan();
- }
-
- // Now discard the master plan itself.
- // The bottom-most plan never gets discarded. "OkayToDiscard" for it
- // means discard it's dependent plans, but not it...
- if (master_plan_idx > 0) {
- DiscardPlan();
- }
- } else {
- // If the master plan doesn't want to get discarded, then we're done.
- break;
- }
- }
-}
-
-bool Thread::PlanIsBasePlan(ThreadPlan *plan_ptr) {
- if (plan_ptr->IsBasePlan())
- return true;
- else if (m_plan_stack.size() == 0)
- return false;
- else
- return m_plan_stack[0].get() == plan_ptr;
+ GetPlans().DiscardConsultingMasterPlans();
}
Status Thread::UnwindInnermostExpression() {
Status error;
- int stack_size = m_plan_stack.size();
-
- // If the input plan is nullptr, discard all plans. Otherwise make sure this
- // plan is in the stack, and if so discard up to and including it.
-
- for (int i = stack_size - 1; i > 0; i--) {
- if (m_plan_stack[i]->GetKind() == ThreadPlan::eKindCallFunction) {
- DiscardThreadPlansUpToPlan(m_plan_stack[i].get());
- return error;
- }
- }
- error.SetErrorString("No expressions currently active on this thread");
+ ThreadPlan *innermost_expr_plan = GetPlans().GetInnermostExpression();
+ if (!innermost_expr_plan) {
+ error.SetErrorString("No expressions currently active on this thread");
+ return error;
+ }
+ DiscardThreadPlansUpToPlan(innermost_expr_plan);
return error;
}
@@ -1502,73 +1387,6 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted(
uint32_t Thread::GetIndexID() const { return m_index_id; }
-static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan,
- lldb::DescriptionLevel desc_level,
- int32_t elem_idx) {
- s->IndentMore();
- s->Indent();
- s->Printf("Element %d: ", elem_idx);
- plan->GetDescription(s, desc_level);
- s->EOL();
- s->IndentLess();
-}
-
-static void PrintPlanStack(Stream *s,
- const std::vector<lldb::ThreadPlanSP> &plan_stack,
- lldb::DescriptionLevel desc_level,
- bool include_internal) {
- int32_t print_idx = 0;
- for (ThreadPlanSP plan_sp : plan_stack) {
- if (include_internal || !plan_sp->GetPrivate()) {
- PrintPlanElement(s, plan_sp, desc_level, print_idx++);
- }
- }
-}
-
-void Thread::DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level,
- bool include_internal,
- bool ignore_boring_threads) const {
- uint32_t stack_size;
-
- if (ignore_boring_threads) {
- uint32_t stack_size = m_plan_stack.size();
- uint32_t completed_stack_size = m_completed_plan_stack.size();
- uint32_t discarded_stack_size = m_discarded_plan_stack.size();
- if (stack_size == 1 && completed_stack_size == 0 &&
- discarded_stack_size == 0) {
- s->Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID());
- s->IndentMore();
- s->Indent();
- s->Printf("No active thread plans\n");
- s->IndentLess();
- return;
- }
- }
-
- s->Indent();
- s->Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID());
- s->IndentMore();
- s->Indent();
- s->Printf("Active plan stack:\n");
- PrintPlanStack(s, m_plan_stack, desc_level, include_internal);
-
- stack_size = m_completed_plan_stack.size();
- if (stack_size > 0) {
- s->Indent();
- s->Printf("Completed Plan Stack:\n");
- PrintPlanStack(s, m_completed_plan_stack, desc_level, include_internal);
- }
-
- stack_size = m_discarded_plan_stack.size();
- if (stack_size > 0) {
- s->Indent();
- s->Printf("Discarded Plan Stack:\n");
- PrintPlanStack(s, m_discarded_plan_stack, desc_level, include_internal);
- }
-
- s->IndentLess();
-}
-
TargetSP Thread::CalculateTarget() {
TargetSP target_sp;
ProcessSP process_sp(GetProcess());
@@ -1600,9 +1418,7 @@ StackFrameListSP Thread::GetStackFrameList() {
void Thread::ClearStackFrames() {
std::lock_guard<std::recursive_mutex> guard(m_frame_mutex);
- Unwind *unwinder = GetUnwinder();
- if (unwinder)
- unwinder->Clear();
+ GetUnwinder().Clear();
// Only store away the old "reference" StackFrameList if we got all its
// frames:
@@ -1773,7 +1589,7 @@ Status Thread::JumpToLine(const FileSpec &file, uint32_t line,
"first location:\n",
file.GetFilename().AsCString(), line);
DumpAddressList(sstr, candidates, target);
- *warnings = sstr.GetString();
+ *warnings = std::string(sstr.GetString());
}
if (!reg_ctx->SetPC(dest))
@@ -2041,37 +1857,10 @@ size_t Thread::GetStackFrameStatus(Stream &strm, uint32_t first_frame,
strm, first_frame, num_frames, show_frame_info, num_frames_with_source);
}
-Unwind *Thread::GetUnwinder() {
- if (!m_unwinder_up) {
- const ArchSpec target_arch(CalculateTarget()->GetArchitecture());
- const llvm::Triple::ArchType machine = target_arch.GetMachine();
- switch (machine) {
- case llvm::Triple::x86_64:
- case llvm::Triple::x86:
- case llvm::Triple::arm:
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- case llvm::Triple::thumb:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::systemz:
- case llvm::Triple::hexagon:
- case llvm::Triple::arc:
- m_unwinder_up.reset(new UnwindLLDB(*this));
- break;
-
- default:
- if (target_arch.GetTriple().getVendor() == llvm::Triple::Apple)
- m_unwinder_up.reset(new UnwindMacOSXFrameBackchain(*this));
- break;
- }
- }
- return m_unwinder_up.get();
+Unwind &Thread::GetUnwinder() {
+ if (!m_unwinder_up)
+ m_unwinder_up = std::make_unique<UnwindLLDB>(*this);
+ return *m_unwinder_up;
}
void Thread::Flush() {
diff --git a/lldb/source/Target/ThreadCollection.cpp b/lldb/source/Target/ThreadCollection.cpp
index cf3c1e242999..05b041c20dd0 100644
--- a/lldb/source/Target/ThreadCollection.cpp
+++ b/lldb/source/Target/ThreadCollection.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadCollection.cpp ------------------------------------*- C++ -*-===//
+//===-- ThreadCollection.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp
index 183b39c2cfa9..032dcc9e5fbd 100644
--- a/lldb/source/Target/ThreadList.cpp
+++ b/lldb/source/Target/ThreadList.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadList.cpp ------------------------------------------*- C++ -*-===//
+//===-- ThreadList.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -715,6 +715,11 @@ void ThreadList::Update(ThreadList &rhs) {
// to work around the issue
collection::iterator rhs_pos, rhs_end = rhs.m_threads.end();
for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos) {
+ // If this thread has already been destroyed, we don't need to look for
+ // it to destroy it again.
+ if (!(*rhs_pos)->IsValid())
+ continue;
+
const lldb::tid_t tid = (*rhs_pos)->GetID();
bool thread_is_alive = false;
const uint32_t num_threads = m_threads.size();
@@ -726,8 +731,9 @@ void ThreadList::Update(ThreadList &rhs) {
break;
}
}
- if (!thread_is_alive)
+ if (!thread_is_alive) {
(*rhs_pos)->DestroyThread();
+ }
}
}
}
diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp
index ba56f8d15d8a..d8e92b8fd0de 100644
--- a/lldb/source/Target/ThreadPlan.cpp
+++ b/lldb/source/Target/ThreadPlan.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlan.cpp ------------------------------------------*- C++ -*-===//
+//===-- ThreadPlan.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -21,9 +21,10 @@ using namespace lldb_private;
// ThreadPlan constructor
ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,
Vote stop_vote, Vote run_vote)
- : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote),
+ : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
+ m_stop_vote(stop_vote), m_run_vote(run_vote),
m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false),
- m_kind(kind), m_name(name), m_plan_complete_mutex(),
+ m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(),
m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false),
m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false),
m_plan_succeeded(true) {
@@ -33,6 +34,19 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,
// Destructor
ThreadPlan::~ThreadPlan() = default;
+Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); }
+
+const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); }
+
+Thread &ThreadPlan::GetThread() {
+ if (m_thread)
+ return *m_thread;
+
+ ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
+ m_thread = thread_sp.get();
+ return *m_thread;
+}
+
bool ThreadPlan::PlanExplainsStop(Event *event_ptr) {
if (m_cached_plan_explains_stop == eLazyBoolCalculate) {
bool actual_value = DoPlanExplainsStop(event_ptr);
@@ -103,7 +117,7 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
if (log) {
- RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
assert(reg_ctx);
addr_t pc = reg_ctx->GetPC();
addr_t sp = reg_ctx->GetSP();
@@ -113,13 +127,17 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) {
"%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64
", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "
"plan = '%s', state = %s, stop others = %d",
- __FUNCTION__, m_thread.GetIndexID(), static_cast<void *>(&m_thread),
- m_thread.GetID(), static_cast<uint64_t>(pc),
+ __FUNCTION__, GetThread().GetIndexID(),
+ static_cast<void *>(&GetThread()), m_tid, static_cast<uint64_t>(pc),
static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(),
StateAsCString(resume_state), StopOthers());
}
}
- return DoWillResume(resume_state, current_plan);
+ bool success = DoWillResume(resume_state, current_plan);
+ m_thread = nullptr; // We don't cache the thread pointer over resumes. This
+ // Thread might go away, and another Thread represent
+ // the same underlying object on a later stop.
+ return success;
}
lldb::user_id_t ThreadPlan::GetNextID() {
@@ -174,14 +192,13 @@ bool ThreadPlanNull::ValidatePlan(Stream *error) {
fprintf(stderr,
"error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#else
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(),
- m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#endif
return true;
}
@@ -191,14 +208,13 @@ bool ThreadPlanNull::ShouldStop(Event *event_ptr) {
fprintf(stderr,
"error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#else
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(),
- m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#endif
return true;
}
@@ -208,14 +224,13 @@ bool ThreadPlanNull::WillStop() {
fprintf(stderr,
"error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#else
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(),
- m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#endif
return true;
}
@@ -225,14 +240,13 @@ bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) {
fprintf(stderr,
"error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID());
#else
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(),
- m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#endif
return true;
}
@@ -244,14 +258,13 @@ bool ThreadPlanNull::MischiefManaged() {
fprintf(stderr,
"error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#else
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(),
- m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#endif
return false;
}
@@ -262,14 +275,13 @@ lldb::StateType ThreadPlanNull::GetPlanRunState() {
fprintf(stderr,
"error: %s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#else
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64
", ptid = 0x%" PRIx64 ")",
- LLVM_PRETTY_FUNCTION, m_thread.GetID(),
- m_thread.GetProtocolID());
+ LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID());
#endif
return eStateRunning;
}
diff --git a/lldb/source/Target/ThreadPlanBase.cpp b/lldb/source/Target/ThreadPlanBase.cpp
index 821643d4bce5..650393d678e8 100644
--- a/lldb/source/Target/ThreadPlanBase.cpp
+++ b/lldb/source/Target/ThreadPlanBase.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanBase.cpp --------------------------------------*- C++ -*-===//
+//===-- ThreadPlanBase.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -34,11 +34,11 @@ ThreadPlanBase::ThreadPlanBase(Thread &thread)
#define THREAD_PLAN_USE_ASSEMBLY_TRACER 1
#ifdef THREAD_PLAN_USE_ASSEMBLY_TRACER
- ThreadPlanTracerSP new_tracer_sp(new ThreadPlanAssemblyTracer(m_thread));
+ ThreadPlanTracerSP new_tracer_sp(new ThreadPlanAssemblyTracer(thread));
#else
ThreadPlanTracerSP new_tracer_sp(new ThreadPlanTracer(m_thread));
#endif
- new_tracer_sp->EnableTracing(m_thread.GetTraceEnabledState());
+ new_tracer_sp->EnableTracing(thread.GetTraceEnabledState());
SetThreadPlanTracer(new_tracer_sp);
SetIsMasterPlan(true);
}
@@ -58,7 +58,7 @@ bool ThreadPlanBase::DoPlanExplainsStop(Event *event_ptr) {
}
Vote ThreadPlanBase::ShouldReportStop(Event *event_ptr) {
- StopInfoSP stop_info_sp = m_thread.GetStopInfo();
+ StopInfoSP stop_info_sp = GetThread().GetStopInfo();
if (stop_info_sp) {
bool should_notify = stop_info_sp->ShouldNotify(event_ptr);
if (should_notify)
@@ -96,8 +96,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
log,
"Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64
" (breakpoint hit.)",
- m_thread.GetID());
- m_thread.DiscardThreadPlans(false);
+ m_tid);
+ GetThread().DiscardThreadPlans(false);
return true;
}
// If we aren't going to stop at this breakpoint, and it is internal,
@@ -125,9 +125,9 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
LLDB_LOGF(
log,
"Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64
- " (exception: %s)",
- m_thread.GetID(), stop_info_sp->GetDescription());
- m_thread.DiscardThreadPlans(false);
+ " (exception: %s)",
+ m_tid, stop_info_sp->GetDescription());
+ GetThread().DiscardThreadPlans(false);
return true;
case eStopReasonExec:
@@ -138,8 +138,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
log,
"Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64
" (exec.)",
- m_thread.GetID());
- m_thread.DiscardThreadPlans(false);
+ m_tid);
+ GetThread().DiscardThreadPlans(false);
return true;
case eStopReasonThreadExiting:
@@ -148,9 +148,9 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
LLDB_LOGF(
log,
"Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64
- " (signal: %s)",
- m_thread.GetID(), stop_info_sp->GetDescription());
- m_thread.DiscardThreadPlans(false);
+ " (signal: %s)",
+ m_tid, stop_info_sp->GetDescription());
+ GetThread().DiscardThreadPlans(false);
return true;
} else {
// We're not going to stop, but while we are here, let's figure out
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
index 23d114e30990..dbe26f42c9bf 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanCallFunction.cpp ------------------------------*- C++ -*-===//
+//===-- ThreadPlanCallFunction.cpp ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -146,7 +146,7 @@ void ThreadPlanCallFunction::ReportRegisterState(const char *message) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
if (log && log->GetVerbose()) {
StreamString strm;
- RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
log->PutCString(message);
@@ -178,19 +178,19 @@ void ThreadPlanCallFunction::DoTakedown(bool success) {
}
if (!m_takedown_done) {
+ Thread &thread = GetThread();
if (success) {
SetReturnValue();
}
LLDB_LOGF(log,
"ThreadPlanCallFunction(%p): DoTakedown called for thread "
"0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n",
- static_cast<void *>(this), m_thread.GetID(), m_valid,
- IsPlanComplete());
+ static_cast<void *>(this), m_tid, m_valid, IsPlanComplete());
m_takedown_done = true;
m_stop_address =
- m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
+ thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
m_real_stop_info_sp = GetPrivateStopInfo();
- if (!m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) {
+ if (!thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) {
LLDB_LOGF(log,
"ThreadPlanCallFunction(%p): DoTakedown failed to restore "
"register state",
@@ -205,8 +205,7 @@ void ThreadPlanCallFunction::DoTakedown(bool success) {
LLDB_LOGF(log,
"ThreadPlanCallFunction(%p): DoTakedown called as no-op for "
"thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n",
- static_cast<void *>(this), m_thread.GetID(), m_valid,
- IsPlanComplete());
+ static_cast<void *>(this), m_tid, m_valid, IsPlanComplete());
}
}
@@ -216,9 +215,8 @@ void ThreadPlanCallFunction::GetDescription(Stream *s, DescriptionLevel level) {
if (level == eDescriptionLevelBrief) {
s->Printf("Function call thread plan");
} else {
- TargetSP target_sp(m_thread.CalculateTarget());
s->Printf("Thread plan to call 0x%" PRIx64,
- m_function_addr.GetLoadAddress(target_sp.get()));
+ m_function_addr.GetLoadAddress(&GetTarget()));
}
}
@@ -283,11 +281,9 @@ bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) {
// m_ignore_breakpoints.
if (stop_reason == eStopReasonBreakpoint) {
- ProcessSP process_sp(m_thread.CalculateProcess());
uint64_t break_site_id = m_real_stop_info_sp->GetValue();
BreakpointSiteSP bp_site_sp;
- if (process_sp)
- bp_site_sp = process_sp->GetBreakpointSiteList().FindByID(break_site_id);
+ bp_site_sp = m_process.GetBreakpointSiteList().FindByID(break_site_id);
if (bp_site_sp) {
uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
bool is_internal = true;
@@ -374,10 +370,11 @@ void ThreadPlanCallFunction::DidPush() {
GetThread().SetStopInfoToNothing();
#ifndef SINGLE_STEP_EXPRESSIONS
- m_subplan_sp = std::make_shared<ThreadPlanRunToAddress>(
- m_thread, m_start_addr, m_stop_other_threads);
+ Thread &thread = GetThread();
+ m_subplan_sp = std::make_shared<ThreadPlanRunToAddress>(thread, m_start_addr,
+ m_stop_other_threads);
- m_thread.QueueThreadPlan(m_subplan_sp, false);
+ thread.QueueThreadPlan(m_subplan_sp, false);
m_subplan_sp->SetPrivate(true);
#endif
}
@@ -399,11 +396,10 @@ bool ThreadPlanCallFunction::MischiefManaged() {
}
void ThreadPlanCallFunction::SetBreakpoints() {
- ProcessSP process_sp(m_thread.CalculateProcess());
- if (m_trap_exceptions && process_sp) {
+ if (m_trap_exceptions) {
m_cxx_language_runtime =
- process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus);
- m_objc_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeObjC);
+ m_process.GetLanguageRuntime(eLanguageTypeC_plus_plus);
+ m_objc_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeObjC);
if (m_cxx_language_runtime) {
m_should_clear_cxx_exception_bp =
@@ -463,11 +459,10 @@ bool ThreadPlanCallFunction::RestoreThreadState() {
}
void ThreadPlanCallFunction::SetReturnValue() {
- ProcessSP process_sp(m_thread.GetProcess());
- const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr;
+ const ABI *abi = m_process.GetABI().get();
if (abi && m_return_type.IsValid()) {
const bool persistent = false;
m_return_valobj_sp =
- abi->GetReturnValueObject(m_thread, m_return_type, persistent);
+ abi->GetReturnValueObject(GetThread(), m_return_type, persistent);
}
}
diff --git a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp
index 3155e6f7965f..52b27309e912 100644
--- a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanCallFunctionUsingABI.cpp ----------------------*- C++ -*-===//
+//===-- ThreadPlanCallFunctionUsingABI.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -49,20 +49,18 @@ void ThreadPlanCallFunctionUsingABI::GetDescription(Stream *s,
if (level == eDescriptionLevelBrief) {
s->Printf("Function call thread plan using ABI instead of JIT");
} else {
- TargetSP target_sp(m_thread.CalculateTarget());
s->Printf("Thread plan to call 0x%" PRIx64 " using ABI instead of JIT",
- m_function_addr.GetLoadAddress(target_sp.get()));
+ m_function_addr.GetLoadAddress(&GetTarget()));
}
}
void ThreadPlanCallFunctionUsingABI::SetReturnValue() {
- ProcessSP process_sp(m_thread.GetProcess());
- const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr;
+ const ABI *abi = m_process.GetABI().get();
// Ask the abi for the return value
if (abi) {
const bool persistent = false;
m_return_valobj_sp =
- abi->GetReturnValueObject(m_thread, m_return_type, persistent);
+ abi->GetReturnValueObject(GetThread(), m_return_type, persistent);
}
}
diff --git a/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp b/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp
index 3330adc0c2af..7471e9b3d7ac 100644
--- a/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp
+++ b/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanCallOnFunctionExit.cpp ------------------------*- C++ -*-===//
+//===-- ThreadPlanCallOnFunctionExit.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp
index 436938c8f207..00b01c76d900 100644
--- a/lldb/source/Target/ThreadPlanCallUserExpression.cpp
+++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanCallUserExpression.cpp -------------------------*- C++-*-===//
+//===-- ThreadPlanCallUserExpression.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -101,8 +101,7 @@ StopInfoSP ThreadPlanCallUserExpression::GetRealStopInfo() {
if (stop_info_sp) {
lldb::addr_t addr = GetStopAddress();
- DynamicCheckerFunctions *checkers =
- m_thread.GetProcess()->GetDynamicCheckers();
+ DynamicCheckerFunctions *checkers = m_process.GetDynamicCheckers();
StreamString s;
if (checkers && checkers->DoCheckersExplainStop(addr, s))
diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp
index df432a0af3da..8171186319f5 100644
--- a/lldb/source/Target/ThreadPlanPython.cpp
+++ b/lldb/source/Target/ThreadPlanPython.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanPython.cpp ------------------------------------*- C++ -*-===//
+//===-- ThreadPlanPython.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -55,15 +55,16 @@ bool ThreadPlanPython::ValidatePlan(Stream *error) {
return true;
}
+ScriptInterpreter *ThreadPlanPython::GetScriptInterpreter() {
+ return m_process.GetTarget().GetDebugger().GetScriptInterpreter();
+}
+
void ThreadPlanPython::DidPush() {
// We set up the script side in DidPush, so that it can push other plans in
// the constructor, and doesn't have to care about the details of DidPush.
m_did_push = true;
if (!m_class_name.empty()) {
- ScriptInterpreter *script_interp = m_thread.GetProcess()
- ->GetTarget()
- .GetDebugger()
- .GetScriptInterpreter();
+ ScriptInterpreter *script_interp = GetScriptInterpreter();
if (script_interp) {
m_implementation_sp = script_interp->CreateScriptedThreadPlan(
m_class_name.c_str(), m_args_data, m_error_str,
@@ -79,10 +80,7 @@ bool ThreadPlanPython::ShouldStop(Event *event_ptr) {
bool should_stop = true;
if (m_implementation_sp) {
- ScriptInterpreter *script_interp = m_thread.GetProcess()
- ->GetTarget()
- .GetDebugger()
- .GetScriptInterpreter();
+ ScriptInterpreter *script_interp = GetScriptInterpreter();
if (script_interp) {
bool script_error;
should_stop = script_interp->ScriptedThreadPlanShouldStop(
@@ -101,10 +99,7 @@ bool ThreadPlanPython::IsPlanStale() {
bool is_stale = true;
if (m_implementation_sp) {
- ScriptInterpreter *script_interp = m_thread.GetProcess()
- ->GetTarget()
- .GetDebugger()
- .GetScriptInterpreter();
+ ScriptInterpreter *script_interp = GetScriptInterpreter();
if (script_interp) {
bool script_error;
is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp,
@@ -123,10 +118,7 @@ bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) {
bool explains_stop = true;
if (m_implementation_sp) {
- ScriptInterpreter *script_interp = m_thread.GetProcess()
- ->GetTarget()
- .GetDebugger()
- .GetScriptInterpreter();
+ ScriptInterpreter *script_interp = GetScriptInterpreter();
if (script_interp) {
bool script_error;
explains_stop = script_interp->ScriptedThreadPlanExplainsStop(
@@ -159,10 +151,7 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() {
m_class_name.c_str());
lldb::StateType run_state = eStateRunning;
if (m_implementation_sp) {
- ScriptInterpreter *script_interp = m_thread.GetProcess()
- ->GetTarget()
- .GetDebugger()
- .GetScriptInterpreter();
+ ScriptInterpreter *script_interp = GetScriptInterpreter();
if (script_interp) {
bool script_error;
run_state = script_interp->ScriptedThreadPlanGetRunState(
diff --git a/lldb/source/Target/ThreadPlanRunToAddress.cpp b/lldb/source/Target/ThreadPlanRunToAddress.cpp
index 32ea2e675270..cb4a58b1cf25 100644
--- a/lldb/source/Target/ThreadPlanRunToAddress.cpp
+++ b/lldb/source/Target/ThreadPlanRunToAddress.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanRunToAddress.cpp ------------------------------*- C++ -*-===//
+//===-- ThreadPlanRunToAddress.cpp ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -25,7 +25,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address,
eVoteNoOpinion, eVoteNoOpinion),
m_stop_others(stop_others), m_addresses(), m_break_ids() {
m_addresses.push_back(
- address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get()));
+ address.GetOpcodeLoadAddress(thread.CalculateTarget().get()));
SetInitialBreakpoints();
}
@@ -36,7 +36,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread,
eVoteNoOpinion, eVoteNoOpinion),
m_stop_others(stop_others), m_addresses(), m_break_ids() {
m_addresses.push_back(
- m_thread.CalculateTarget()->GetOpcodeLoadAddress(address));
+ thread.CalculateTarget()->GetOpcodeLoadAddress(address));
SetInitialBreakpoints();
}
@@ -62,14 +62,13 @@ void ThreadPlanRunToAddress::SetInitialBreakpoints() {
for (size_t i = 0; i < num_addresses; i++) {
Breakpoint *breakpoint;
- breakpoint = m_thread.CalculateTarget()
- ->CreateBreakpoint(m_addresses[i], true, false)
- .get();
+ breakpoint =
+ GetTarget().CreateBreakpoint(m_addresses[i], true, false).get();
if (breakpoint != nullptr) {
if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations())
m_could_not_resolve_hw_bp = true;
m_break_ids[i] = breakpoint->GetID();
- breakpoint->SetThreadID(m_thread.GetID());
+ breakpoint->SetThreadID(m_tid);
breakpoint->SetBreakpointKind("run-to-address");
}
}
@@ -78,7 +77,7 @@ void ThreadPlanRunToAddress::SetInitialBreakpoints() {
ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {
size_t num_break_ids = m_break_ids.size();
for (size_t i = 0; i < num_break_ids; i++) {
- m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]);
+ GetTarget().RemoveBreakpointByID(m_break_ids[i]);
}
m_could_not_resolve_hw_bp = false;
}
@@ -119,7 +118,7 @@ void ThreadPlanRunToAddress::GetDescription(Stream *s,
DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));
s->Printf(" using breakpoint: %d - ", m_break_ids[i]);
Breakpoint *breakpoint =
- m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get();
+ GetTarget().GetBreakpointByID(m_break_ids[i]).get();
if (breakpoint)
breakpoint->Dump(s);
else
@@ -178,7 +177,7 @@ bool ThreadPlanRunToAddress::MischiefManaged() {
for (size_t i = 0; i < num_break_ids; i++) {
if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) {
- m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]);
+ GetTarget().RemoveBreakpointByID(m_break_ids[i]);
m_break_ids[i] = LLDB_INVALID_BREAK_ID;
}
}
@@ -190,7 +189,7 @@ bool ThreadPlanRunToAddress::MischiefManaged() {
}
bool ThreadPlanRunToAddress::AtOurAddress() {
- lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC();
+ lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC();
bool found_it = false;
size_t num_addresses = m_addresses.size();
for (size_t i = 0; i < num_addresses; i++) {
diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
index 9599d8197b07..7774e027c056 100644
--- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp
+++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanShouldStopHere.cpp ----------------------------*- C++ -*-===//
+//===-- ThreadPlanShouldStopHere.cpp --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp
new file mode 100644
index 000000000000..1cfc41dcd390
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStack.cpp
@@ -0,0 +1,508 @@
+//===-- ThreadPlanStack.cpp -------------------------------------*- C++ -*-===//
+//
+// 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/ThreadPlanStack.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan,
+ lldb::DescriptionLevel desc_level,
+ int32_t elem_idx) {
+ s.IndentMore();
+ s.Indent();
+ s.Printf("Element %d: ", elem_idx);
+ plan->GetDescription(&s, desc_level);
+ s.EOL();
+ s.IndentLess();
+}
+
+ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) {
+ if (make_null) {
+ // The ThreadPlanNull doesn't do anything to the Thread, so this is actually
+ // still a const operation.
+ m_plans.push_back(
+ ThreadPlanSP(new ThreadPlanNull(const_cast<Thread &>(thread))));
+ }
+}
+
+void ThreadPlanStack::DumpThreadPlans(Stream &s,
+ lldb::DescriptionLevel desc_level,
+ bool include_internal) const {
+ s.IndentMore();
+ PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal);
+ PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level,
+ include_internal);
+ PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level,
+ include_internal);
+ s.IndentLess();
+}
+
+void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name,
+ const PlanStack &stack,
+ lldb::DescriptionLevel desc_level,
+ bool include_internal) const {
+ // If the stack is empty, just exit:
+ if (stack.empty())
+ return;
+
+ // Make sure there are public completed plans:
+ bool any_public = false;
+ if (!include_internal) {
+ for (auto plan : stack) {
+ if (!plan->GetPrivate()) {
+ any_public = true;
+ break;
+ }
+ }
+ }
+
+ if (include_internal || any_public) {
+ int print_idx = 0;
+ s.Indent();
+ s << stack_name << ":\n";
+ for (auto plan : stack) {
+ if (!include_internal && plan->GetPrivate())
+ continue;
+ PrintPlanElement(s, plan, desc_level, print_idx++);
+ }
+ }
+}
+
+size_t ThreadPlanStack::CheckpointCompletedPlans() {
+ m_completed_plan_checkpoint++;
+ m_completed_plan_store.insert(
+ std::make_pair(m_completed_plan_checkpoint, m_completed_plans));
+ return m_completed_plan_checkpoint;
+}
+
+void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) {
+ auto result = m_completed_plan_store.find(checkpoint);
+ assert(result != m_completed_plan_store.end() &&
+ "Asked for a checkpoint that didn't exist");
+ m_completed_plans.swap((*result).second);
+ m_completed_plan_store.erase(result);
+}
+
+void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) {
+ m_completed_plan_store.erase(checkpoint);
+}
+
+void ThreadPlanStack::ThreadDestroyed(Thread *thread) {
+ // Tell the plan stacks that this thread is going away:
+ for (ThreadPlanSP plan : m_plans)
+ plan->ThreadDestroyed();
+
+ for (ThreadPlanSP plan : m_discarded_plans)
+ plan->ThreadDestroyed();
+
+ for (ThreadPlanSP plan : m_completed_plans)
+ plan->ThreadDestroyed();
+
+ // Now clear the current plan stacks:
+ m_plans.clear();
+ m_discarded_plans.clear();
+ m_completed_plans.clear();
+
+ // Push a ThreadPlanNull on the plan stack. That way we can continue
+ // assuming that the plan stack is never empty, but if somebody errantly asks
+ // questions of a destroyed thread without checking first whether it is
+ // destroyed, they won't crash.
+ if (thread != nullptr) {
+ lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread));
+ m_plans.push_back(null_plan_sp);
+ }
+}
+
+void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) {
+ for (ThreadPlanSP plan : m_plans) {
+ if (plan->GetThreadPlanTracer()) {
+ plan->GetThreadPlanTracer()->EnableTracing(value);
+ plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping);
+ }
+ }
+}
+
+void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) {
+ for (ThreadPlanSP plan : m_plans)
+ plan->SetThreadPlanTracer(tracer_sp);
+}
+
+void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) {
+ // If the thread plan doesn't already have a tracer, give it its parent's
+ // tracer:
+ // The first plan has to be a base plan:
+ assert((m_plans.size() > 0 || new_plan_sp->IsBasePlan()) &&
+ "Zeroth plan must be a base plan");
+
+ if (!new_plan_sp->GetThreadPlanTracer()) {
+ assert(!m_plans.empty());
+ new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer());
+ }
+ m_plans.push_back(new_plan_sp);
+ new_plan_sp->DidPush();
+}
+
+lldb::ThreadPlanSP ThreadPlanStack::PopPlan() {
+ assert(m_plans.size() > 1 && "Can't pop the base thread plan");
+
+ lldb::ThreadPlanSP plan_sp = std::move(m_plans.back());
+ m_completed_plans.push_back(plan_sp);
+ plan_sp->WillPop();
+ m_plans.pop_back();
+ return plan_sp;
+}
+
+lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() {
+ assert(m_plans.size() > 1 && "Can't discard the base thread plan");
+
+ lldb::ThreadPlanSP plan_sp = std::move(m_plans.back());
+ m_discarded_plans.push_back(plan_sp);
+ plan_sp->WillPop();
+ m_plans.pop_back();
+ return plan_sp;
+}
+
+// If the input plan is nullptr, discard all plans. Otherwise make sure this
+// plan is in the stack, and if so discard up to and including it.
+void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) {
+ int stack_size = m_plans.size();
+
+ if (up_to_plan_ptr == nullptr) {
+ for (int i = stack_size - 1; i > 0; i--)
+ DiscardPlan();
+ return;
+ }
+
+ bool found_it = false;
+ for (int i = stack_size - 1; i > 0; i--) {
+ if (m_plans[i].get() == up_to_plan_ptr) {
+ found_it = true;
+ break;
+ }
+ }
+
+ if (found_it) {
+ bool last_one = false;
+ for (int i = stack_size - 1; i > 0 && !last_one; i--) {
+ if (GetCurrentPlan().get() == up_to_plan_ptr)
+ last_one = true;
+ DiscardPlan();
+ }
+ }
+}
+
+void ThreadPlanStack::DiscardAllPlans() {
+ int stack_size = m_plans.size();
+ for (int i = stack_size - 1; i > 0; i--) {
+ DiscardPlan();
+ }
+ return;
+}
+
+void ThreadPlanStack::DiscardConsultingMasterPlans() {
+ while (true) {
+ int master_plan_idx;
+ bool discard = true;
+
+ // Find the first master plan, see if it wants discarding, and if yes
+ // discard up to it.
+ for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0;
+ master_plan_idx--) {
+ if (m_plans[master_plan_idx]->IsMasterPlan()) {
+ discard = m_plans[master_plan_idx]->OkayToDiscard();
+ break;
+ }
+ }
+
+ // If the master plan doesn't want to get discarded, then we're done.
+ if (!discard)
+ return;
+
+ // First pop all the dependent plans:
+ for (int i = m_plans.size() - 1; i > master_plan_idx; i--) {
+ DiscardPlan();
+ }
+
+ // Now discard the master plan itself.
+ // The bottom-most plan never gets discarded. "OkayToDiscard" for it
+ // means discard it's dependent plans, but not it...
+ if (master_plan_idx > 0) {
+ DiscardPlan();
+ }
+ }
+}
+
+lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const {
+ assert(m_plans.size() != 0 && "There will always be a base plan.");
+ return m_plans.back();
+}
+
+lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const {
+ if (m_completed_plans.empty())
+ return {};
+
+ if (!skip_private)
+ return m_completed_plans.back();
+
+ for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
+ lldb::ThreadPlanSP completed_plan_sp;
+ completed_plan_sp = m_completed_plans[i];
+ if (!completed_plan_sp->GetPrivate())
+ return completed_plan_sp;
+ }
+ return {};
+}
+
+lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx,
+ bool skip_private) const {
+ uint32_t idx = 0;
+
+ for (lldb::ThreadPlanSP plan_sp : m_plans) {
+ if (skip_private && plan_sp->GetPrivate())
+ continue;
+ if (idx == plan_idx)
+ return plan_sp;
+ idx++;
+ }
+ return {};
+}
+
+lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const {
+ if (m_completed_plans.empty())
+ return {};
+
+ for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
+ lldb::ValueObjectSP return_valobj_sp;
+ return_valobj_sp = m_completed_plans[i]->GetReturnValueObject();
+ if (return_valobj_sp)
+ return return_valobj_sp;
+ }
+ return {};
+}
+
+lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const {
+ if (m_completed_plans.empty())
+ return {};
+
+ for (int i = m_completed_plans.size() - 1; i >= 0; i--) {
+ lldb::ExpressionVariableSP expression_variable_sp;
+ expression_variable_sp = m_completed_plans[i]->GetExpressionVariable();
+ if (expression_variable_sp)
+ return expression_variable_sp;
+ }
+ return {};
+}
+bool ThreadPlanStack::AnyPlans() const {
+ // There is always a base plan...
+ return m_plans.size() > 1;
+}
+
+bool ThreadPlanStack::AnyCompletedPlans() const {
+ return !m_completed_plans.empty();
+}
+
+bool ThreadPlanStack::AnyDiscardedPlans() const {
+ return !m_discarded_plans.empty();
+}
+
+bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const {
+ for (auto plan : m_completed_plans) {
+ if (plan.get() == in_plan)
+ return true;
+ }
+ return false;
+}
+
+bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const {
+ for (auto plan : m_discarded_plans) {
+ if (plan.get() == in_plan)
+ return true;
+ }
+ return false;
+}
+
+ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const {
+ if (current_plan == nullptr)
+ return nullptr;
+
+ // Look first in the completed plans, if the plan is here and there is
+ // a completed plan above it, return that.
+ int stack_size = m_completed_plans.size();
+ for (int i = stack_size - 1; i > 0; i--) {
+ if (current_plan == m_completed_plans[i].get())
+ return m_completed_plans[i - 1].get();
+ }
+
+ // If this is the first completed plan, the previous one is the
+ // bottom of the regular plan stack.
+ if (stack_size > 0 && m_completed_plans[0].get() == current_plan) {
+ return GetCurrentPlan().get();
+ }
+
+ // Otherwise look for it in the regular plans.
+ stack_size = m_plans.size();
+ for (int i = stack_size - 1; i > 0; i--) {
+ if (current_plan == m_plans[i].get())
+ return m_plans[i - 1].get();
+ }
+ return nullptr;
+}
+
+ThreadPlan *ThreadPlanStack::GetInnermostExpression() const {
+ int stack_size = m_plans.size();
+
+ for (int i = stack_size - 1; i > 0; i--) {
+ if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction)
+ return m_plans[i].get();
+ }
+ return nullptr;
+}
+
+void ThreadPlanStack::WillResume() {
+ m_completed_plans.clear();
+ m_discarded_plans.clear();
+}
+
+const ThreadPlanStack::PlanStack &
+ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const {
+ switch (kind) {
+ case ePlans:
+ return m_plans;
+ case eCompletedPlans:
+ return m_completed_plans;
+ case eDiscardedPlans:
+ return m_discarded_plans;
+ }
+ llvm_unreachable("Invalid StackKind value");
+}
+
+void ThreadPlanStackMap::Update(ThreadList &current_threads,
+ bool delete_missing,
+ bool check_for_new) {
+
+ // Now find all the new threads and add them to the map:
+ if (check_for_new) {
+ for (auto thread : current_threads.Threads()) {
+ lldb::tid_t cur_tid = thread->GetID();
+ if (!Find(cur_tid)) {
+ AddThread(*thread.get());
+ thread->QueueFundamentalPlan(true);
+ }
+ }
+ }
+
+ // If we aren't reaping missing threads at this point,
+ // we are done.
+ if (!delete_missing)
+ return;
+ // Otherwise scan for absent TID's.
+ std::vector<lldb::tid_t> missing_threads;
+ // If we are going to delete plans from the plan stack,
+ // then scan for absent TID's:
+ for (auto thread_plans : m_plans_list) {
+ lldb::tid_t cur_tid = thread_plans.first;
+ ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid);
+ if (!thread_sp)
+ missing_threads.push_back(cur_tid);
+ }
+ for (lldb::tid_t tid : missing_threads) {
+ RemoveTID(tid);
+ }
+}
+
+void ThreadPlanStackMap::DumpPlans(Stream &strm,
+ lldb::DescriptionLevel desc_level,
+ bool internal, bool condense_if_trivial,
+ bool skip_unreported) {
+ for (auto elem : m_plans_list) {
+ lldb::tid_t tid = elem.first;
+ uint32_t index_id = 0;
+ ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
+
+ if (skip_unreported) {
+ if (!thread_sp)
+ continue;
+ }
+ if (thread_sp)
+ index_id = thread_sp->GetIndexID();
+
+ if (condense_if_trivial) {
+ if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() &&
+ !elem.second.AnyDiscardedPlans()) {
+ strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
+ strm.IndentMore();
+ strm.Indent();
+ strm.Printf("No active thread plans\n");
+ strm.IndentLess();
+ return;
+ }
+ }
+
+ strm.Indent();
+ strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
+
+ elem.second.DumpThreadPlans(strm, desc_level, internal);
+ }
+}
+
+bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid,
+ lldb::DescriptionLevel desc_level,
+ bool internal,
+ bool condense_if_trivial,
+ bool skip_unreported) {
+ uint32_t index_id = 0;
+ ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
+
+ if (skip_unreported) {
+ if (!thread_sp) {
+ strm.Format("Unknown TID: {0}", tid);
+ return false;
+ }
+ }
+
+ if (thread_sp)
+ index_id = thread_sp->GetIndexID();
+ ThreadPlanStack *stack = Find(tid);
+ if (!stack) {
+ strm.Format("Unknown TID: {0}\n", tid);
+ return false;
+ }
+
+ if (condense_if_trivial) {
+ if (!stack->AnyPlans() && !stack->AnyCompletedPlans() &&
+ !stack->AnyDiscardedPlans()) {
+ strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
+ strm.IndentMore();
+ strm.Indent();
+ strm.Printf("No active thread plans\n");
+ strm.IndentLess();
+ return true;
+ }
+ }
+
+ strm.Indent();
+ strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
+
+ stack->DumpThreadPlans(strm, desc_level, internal);
+ return true;
+}
+
+bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) {
+ // We only remove the plans for unreported TID's.
+ ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
+ if (thread_sp)
+ return false;
+
+ return RemoveTID(tid);
+}
diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp
index ab1f6a21a862..c5f81d6665a1 100644
--- a/lldb/source/Target/ThreadPlanStepInRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepInRange.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanStepInRange.cpp -------------------------------*- C++ -*-===//
+//===-- ThreadPlanStepInRange.cpp -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -69,7 +69,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug(
LazyBool step_in_avoids_code_without_debug_info,
LazyBool step_out_avoids_code_without_debug_info) {
bool avoid_nodebug = true;
-
+ Thread &thread = GetThread();
switch (step_in_avoids_code_without_debug_info) {
case eLazyBoolYes:
avoid_nodebug = true;
@@ -78,7 +78,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug(
avoid_nodebug = false;
break;
case eLazyBoolCalculate:
- avoid_nodebug = m_thread.GetStepInAvoidsNoDebug();
+ avoid_nodebug = thread.GetStepInAvoidsNoDebug();
break;
}
if (avoid_nodebug)
@@ -94,7 +94,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug(
avoid_nodebug = false;
break;
case eLazyBoolCalculate:
- avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ avoid_nodebug = thread.GetStepOutAvoidsNoDebug();
break;
}
if (avoid_nodebug)
@@ -145,9 +145,8 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
if (log) {
StreamString s;
- DumpAddress(
- s.AsRawOstream(), m_thread.GetRegisterContext()->GetPC(),
- m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
+ DumpAddress(s.AsRawOstream(), GetThread().GetRegisterContext()->GetPC(),
+ GetTarget().GetArchitecture().GetAddressByteSize());
LLDB_LOGF(log, "ThreadPlanStepInRange reached %s.", s.GetData());
}
@@ -180,6 +179,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
FrameComparison frame_order = CompareCurrentFrameToStartFrame();
+ Thread &thread = GetThread();
if (frame_order == eFrameCompareOlder ||
frame_order == eFrameCompareSameParent) {
// If we're in an older frame then we should stop.
@@ -189,7 +189,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
// I'm going to make the assumption that you wouldn't RETURN to a
// trampoline. So if we are in a trampoline we think the frame is older
// because the trampoline confused the backtracer.
- m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(
+ m_sub_plan_sp = thread.QueueThreadPlanForStepThrough(
m_stack_id, false, stop_others, m_status);
if (!m_sub_plan_sp) {
// Otherwise check the ShouldStopHere for step out:
@@ -233,7 +233,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
// We may have set the plan up above in the FrameIsOlder section:
if (!m_sub_plan_sp)
- m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(
+ m_sub_plan_sp = thread.QueueThreadPlanForStepThrough(
m_stack_id, false, stop_others, m_status);
if (log) {
@@ -254,10 +254,10 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
if (!m_sub_plan_sp && frame_order == eFrameCompareYounger &&
m_step_past_prologue) {
- lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
+ lldb::StackFrameSP curr_frame = thread.GetStackFrameAtIndex(0);
if (curr_frame) {
size_t bytes_to_skip = 0;
- lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
+ lldb::addr_t curr_addr = thread.GetRegisterContext()->GetPC();
Address func_start_address;
SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction |
@@ -265,25 +265,20 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
if (sc.function) {
func_start_address = sc.function->GetAddressRange().GetBaseAddress();
- if (curr_addr ==
- func_start_address.GetLoadAddress(
- m_thread.CalculateTarget().get()))
+ if (curr_addr == func_start_address.GetLoadAddress(&GetTarget()))
bytes_to_skip = sc.function->GetPrologueByteSize();
} else if (sc.symbol) {
func_start_address = sc.symbol->GetAddress();
- if (curr_addr ==
- func_start_address.GetLoadAddress(
- m_thread.CalculateTarget().get()))
+ if (curr_addr == func_start_address.GetLoadAddress(&GetTarget()))
bytes_to_skip = sc.symbol->GetPrologueByteSize();
}
if (bytes_to_skip == 0 && sc.symbol) {
- TargetSP target = m_thread.CalculateTarget();
- const Architecture *arch = target->GetArchitecturePlugin();
+ const Architecture *arch = GetTarget().GetArchitecturePlugin();
if (arch) {
Address curr_sec_addr;
- target->GetSectionLoadList().ResolveLoadAddress(curr_addr,
- curr_sec_addr);
+ GetTarget().GetSectionLoadList().ResolveLoadAddress(curr_addr,
+ curr_sec_addr);
bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr);
}
}
@@ -293,7 +288,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP);
LLDB_LOGF(log, "Pushing past prologue ");
- m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(
+ m_sub_plan_sp = thread.QueueThreadPlanForRunToAddress(
false, func_start_address, true, m_status);
}
}
@@ -316,7 +311,7 @@ void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) {
if (m_avoid_regexp_up)
*m_avoid_regexp_up = RegularExpression(name_ref);
else
- m_avoid_regexp_up.reset(new RegularExpression(name_ref));
+ m_avoid_regexp_up = std::make_unique<RegularExpression>(name_ref);
}
void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value) {
@@ -486,15 +481,16 @@ bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state,
bool current_plan) {
m_virtual_step = false;
if (resume_state == eStateStepping && current_plan) {
+ Thread &thread = GetThread();
// See if we are about to step over a virtual inlined call.
- bool step_without_resume = m_thread.DecrementCurrentInlinedDepth();
+ bool step_without_resume = thread.DecrementCurrentInlinedDepth();
if (step_without_resume) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
LLDB_LOGF(log,
"ThreadPlanStepInRange::DoWillResume: returning false, "
"inline_depth: %d",
- m_thread.GetCurrentInlinedDepth());
- SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
+ thread.GetCurrentInlinedDepth());
+ SetStopInfo(StopInfo::CreateStopReasonToTrace(thread));
// FIXME: Maybe it would be better to create a InlineStep stop reason, but
// then
diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp
index afcc9d608b27..c0da735c44b6 100644
--- a/lldb/source/Target/ThreadPlanStepInstruction.cpp
+++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===//
+//===-- ThreadPlanStepInstruction.cpp -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -36,14 +36,15 @@ ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread,
ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default;
void ThreadPlanStepInstruction::SetUpState() {
- m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
- StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
+ Thread &thread = GetThread();
+ m_instruction_addr = thread.GetRegisterContext()->GetPC(0);
+ StackFrameSP start_frame_sp(thread.GetStackFrameAtIndex(0));
m_stack_id = start_frame_sp->GetStackID();
m_start_has_symbol =
start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr;
- StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
+ StackFrameSP parent_frame_sp = thread.GetStackFrameAtIndex(1);
if (parent_frame_sp)
m_parent_frame_id = parent_frame_sp->GetStackID();
}
@@ -95,18 +96,19 @@ bool ThreadPlanStepInstruction::DoPlanExplainsStop(Event *event_ptr) {
bool ThreadPlanStepInstruction::IsPlanStale() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ Thread &thread = GetThread();
+ StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID();
if (cur_frame_id == m_stack_id) {
// Set plan Complete when we reach next instruction
- uint64_t pc = m_thread.GetRegisterContext()->GetPC(0);
- uint32_t max_opcode_size = m_thread.CalculateTarget()
- ->GetArchitecture().GetMaximumOpcodeByteSize();
+ uint64_t pc = thread.GetRegisterContext()->GetPC(0);
+ uint32_t max_opcode_size =
+ GetTarget().GetArchitecture().GetMaximumOpcodeByteSize();
bool next_instruction_reached = (pc > m_instruction_addr) &&
(pc <= m_instruction_addr + max_opcode_size);
if (next_instruction_reached) {
SetPlanComplete();
}
- return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr);
+ return (thread.GetRegisterContext()->GetPC(0) != m_instruction_addr);
} else if (cur_frame_id < m_stack_id) {
// If the current frame is younger than the start frame and we are stepping
// over, then we need to continue, but if we are doing just one step, we're
@@ -123,10 +125,10 @@ bool ThreadPlanStepInstruction::IsPlanStale() {
}
bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
+ Thread &thread = GetThread();
if (m_step_over) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
-
- StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0);
+ StackFrameSP cur_frame_sp = thread.GetStackFrameAtIndex(0);
if (!cur_frame_sp) {
LLDB_LOGF(
log,
@@ -138,7 +140,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
StackID cur_frame_zero_id = cur_frame_sp->GetStackID();
if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) {
- if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) {
+ if (thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) {
if (--m_iteration_count <= 0) {
SetPlanComplete();
return true;
@@ -152,7 +154,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
return false;
} else {
// We've stepped in, step back out again:
- StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
+ StackFrame *return_frame = thread.GetStackFrameAtIndex(1).get();
if (return_frame) {
if (return_frame->GetStackID() != m_parent_frame_id ||
m_start_has_symbol) {
@@ -162,7 +164,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
if (cur_frame_sp->IsInlined()) {
StackFrameSP parent_frame_sp =
- m_thread.GetFrameWithStackID(m_stack_id);
+ thread.GetFrameWithStackID(m_stack_id);
if (parent_frame_sp &&
parent_frame_sp->GetConcreteFrameIndex() ==
@@ -181,24 +183,20 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
StreamString s;
s.PutCString("Stepped in to: ");
addr_t stop_addr =
- m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
+ thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
DumpAddress(s.AsRawOstream(), stop_addr,
- m_thread.CalculateTarget()
- ->GetArchitecture()
- .GetAddressByteSize());
+ GetTarget().GetArchitecture().GetAddressByteSize());
s.PutCString(" stepping out to: ");
addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
DumpAddress(s.AsRawOstream(), return_addr,
- m_thread.CalculateTarget()
- ->GetArchitecture()
- .GetAddressByteSize());
+ GetTarget().GetArchitecture().GetAddressByteSize());
LLDB_LOGF(log, "%s.", s.GetData());
}
// StepInstruction should probably have the tri-state RunMode, but
// for now it is safer to run others.
const bool stop_others = false;
- m_thread.QueueThreadPlanForStepOutNoShouldStop(
+ thread.QueueThreadPlanForStepOutNoShouldStop(
false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
m_status);
return false;
@@ -219,7 +217,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
}
}
} else {
- lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0);
+ lldb::addr_t pc_addr = thread.GetRegisterContext()->GetPC(0);
if (pc_addr != m_instruction_addr) {
if (--m_iteration_count <= 0) {
SetPlanComplete();
diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp
index f15a343aaa38..9f0749c0fdb3 100644
--- a/lldb/source/Target/ThreadPlanStepOut.cpp
+++ b/lldb/source/Target/ThreadPlanStepOut.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanStepOut.cpp -----------------------------------*- C++ -*-===//
+//===-- ThreadPlanStepOut.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -47,13 +47,11 @@ ThreadPlanStepOut::ThreadPlanStepOut(
SetFlagsToDefault();
SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
- m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
+ m_step_from_insn = thread.GetRegisterContext()->GetPC(0);
uint32_t return_frame_index = frame_idx + 1;
- StackFrameSP return_frame_sp(
- m_thread.GetStackFrameAtIndex(return_frame_index));
- StackFrameSP immediate_return_from_sp(
- m_thread.GetStackFrameAtIndex(frame_idx));
+ StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(return_frame_index));
+ StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(frame_idx));
if (!return_frame_sp || !immediate_return_from_sp)
return; // we can't do anything here. ValidatePlan() will return false.
@@ -63,7 +61,7 @@ ThreadPlanStepOut::ThreadPlanStepOut(
m_stepped_past_frames.push_back(return_frame_sp);
++return_frame_index;
- return_frame_sp = m_thread.GetStackFrameAtIndex(return_frame_index);
+ return_frame_sp = thread.GetStackFrameAtIndex(return_frame_index);
// We never expect to see an artificial frame without a regular ancestor.
// If this happens, log the issue and defensively refuse to step out.
@@ -85,7 +83,7 @@ ThreadPlanStepOut::ThreadPlanStepOut(
// First queue a plan that gets us to this inlined frame, and when we get
// there we'll queue a second plan that walks us out of this frame.
m_step_out_to_inline_plan_sp = std::make_shared<ThreadPlanStepOut>(
- m_thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion,
+ thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion,
frame_idx - 1, eLazyBoolNo, continue_to_next_branch);
static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())
->SetShouldStopHereCallbacks(nullptr, nullptr);
@@ -114,28 +112,22 @@ ThreadPlanStepOut::ThreadPlanStepOut(
range = return_address_sc.line_entry.GetSameLineContiguousAddressRange(
include_inlined_functions);
if (range.GetByteSize() > 0) {
- return_address =
- m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction(
- return_address, range);
+ return_address = m_process.AdvanceAddressToNextBranchInstruction(
+ return_address, range);
}
}
}
- m_return_addr =
- return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget());
+ m_return_addr = return_address.GetLoadAddress(&m_process.GetTarget());
if (m_return_addr == LLDB_INVALID_ADDRESS)
return;
// Perform some additional validation on the return address.
uint32_t permissions = 0;
- if (!m_thread.GetProcess()->GetLoadAddressPermissions(m_return_addr,
- permissions)) {
- m_constructor_errors.Printf("Return address (0x%" PRIx64
- ") permissions not found.",
- m_return_addr);
- LLDB_LOGF(log, "ThreadPlanStepOut(%p): %s", static_cast<void *>(this),
- m_constructor_errors.GetData());
- return;
+ if (!m_process.GetLoadAddressPermissions(m_return_addr, permissions)) {
+ LLDB_LOGF(log, "ThreadPlanStepOut(%p): Return address (0x%" PRIx64
+ ") permissions not found.", static_cast<void *>(this),
+ m_return_addr);
} else if (!(permissions & ePermissionsExecutable)) {
m_constructor_errors.Printf("Return address (0x%" PRIx64
") did not point to executable memory.",
@@ -145,14 +137,13 @@ ThreadPlanStepOut::ThreadPlanStepOut(
return;
}
- Breakpoint *return_bp = m_thread.CalculateTarget()
- ->CreateBreakpoint(m_return_addr, true, false)
- .get();
+ Breakpoint *return_bp =
+ GetTarget().CreateBreakpoint(m_return_addr, true, false).get();
if (return_bp != nullptr) {
if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
m_could_not_resolve_hw_bp = true;
- return_bp->SetThreadID(m_thread.GetID());
+ return_bp->SetThreadID(m_tid);
m_return_bp_id = return_bp->GetID();
return_bp->SetBreakpointKind("step-out");
}
@@ -178,7 +169,7 @@ void ThreadPlanStepOut::SetupAvoidNoDebug(
avoid_nodebug = false;
break;
case eLazyBoolCalculate:
- avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
break;
}
if (avoid_nodebug)
@@ -188,15 +179,16 @@ void ThreadPlanStepOut::SetupAvoidNoDebug(
}
void ThreadPlanStepOut::DidPush() {
+ Thread &thread = GetThread();
if (m_step_out_to_inline_plan_sp)
- m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);
+ thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);
else if (m_step_through_inline_plan_sp)
- m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
+ thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
}
ThreadPlanStepOut::~ThreadPlanStepOut() {
if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
- m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id);
+ GetTarget().RemoveBreakpointByID(m_return_bp_id);
}
void ThreadPlanStepOut::GetDescription(Stream *s,
@@ -212,7 +204,7 @@ void ThreadPlanStepOut::GetDescription(Stream *s,
s->Printf("Stepping out from ");
Address tmp_address;
if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) {
- tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription,
+ tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription,
Address::DumpStyleLoadAddress);
} else {
s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn);
@@ -224,7 +216,7 @@ void ThreadPlanStepOut::GetDescription(Stream *s,
s->Printf(" returning to frame at ");
if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) {
- tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription,
+ tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription,
Address::DumpStyleLoadAddress);
} else {
s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr);
@@ -235,6 +227,9 @@ void ThreadPlanStepOut::GetDescription(Stream *s,
}
}
+ if (m_stepped_past_frames.empty())
+ return;
+
s->Printf("\n");
for (StackFrameSP frame_sp : m_stepped_past_frames) {
s->Printf("Stepped out past: ");
@@ -296,12 +291,12 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
// If this is OUR breakpoint, we're fine, otherwise we don't know why
// this happened...
BreakpointSiteSP site_sp(
- m_thread.GetProcess()->GetBreakpointSiteList().FindByID(
- stop_info_sp->GetValue()));
+ m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue()));
if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) {
bool done;
- StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ StackID frame_zero_id =
+ GetThread().GetStackFrameAtIndex(0)->GetStackID();
if (m_step_out_to_id == frame_zero_id)
done = true;
@@ -368,7 +363,7 @@ bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) {
}
if (!done) {
- StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID();
done = !(frame_zero_id < m_step_out_to_id);
}
@@ -402,8 +397,7 @@ bool ThreadPlanStepOut::DoWillResume(StateType resume_state,
return false;
if (current_plan) {
- Breakpoint *return_bp =
- m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
+ Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get();
if (return_bp != nullptr)
return_bp->SetEnabled(true);
}
@@ -412,8 +406,7 @@ bool ThreadPlanStepOut::DoWillResume(StateType resume_state,
bool ThreadPlanStepOut::WillStop() {
if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
- Breakpoint *return_bp =
- m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
+ Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get();
if (return_bp != nullptr)
return_bp->SetEnabled(false);
}
@@ -434,7 +427,7 @@ bool ThreadPlanStepOut::MischiefManaged() {
if (log)
LLDB_LOGF(log, "Completed step out plan.");
if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
- m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id);
+ GetTarget().RemoveBreakpointByID(m_return_bp_id);
m_return_bp_id = LLDB_INVALID_BREAK_ID;
}
@@ -449,7 +442,8 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) {
// Now figure out the range of this inlined block, and set up a "step through
// range" plan for that. If we've been provided with a context, then use the
// block in that context.
- StackFrameSP immediate_return_from_sp(m_thread.GetStackFrameAtIndex(0));
+ Thread &thread = GetThread();
+ StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(0));
if (!immediate_return_from_sp)
return false;
@@ -476,7 +470,7 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) {
m_step_through_inline_plan_sp =
std::make_shared<ThreadPlanStepOverRange>(
- m_thread, inline_range, inlined_sc, run_mode, avoid_no_debug);
+ thread, inline_range, inlined_sc, run_mode, avoid_no_debug);
ThreadPlanStepOverRange *step_through_inline_plan_ptr =
static_cast<ThreadPlanStepOverRange *>(
m_step_through_inline_plan_sp.get());
@@ -496,7 +490,7 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) {
}
if (queue_now)
- m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
+ thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
return true;
}
}
@@ -517,10 +511,10 @@ void ThreadPlanStepOut::CalculateReturnValue() {
m_immediate_step_from_function->GetCompilerType()
.GetFunctionReturnType();
if (return_compiler_type) {
- lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI();
+ lldb::ABISP abi_sp = m_process.GetABI();
if (abi_sp)
m_return_valobj_sp =
- abi_sp->GetReturnValueObject(m_thread, return_compiler_type);
+ abi_sp->GetReturnValueObject(GetThread(), return_compiler_type);
}
}
}
@@ -529,6 +523,6 @@ bool ThreadPlanStepOut::IsPlanStale() {
// If we are still lower on the stack than the frame we are returning to,
// then there's something for us to do. Otherwise, we're stale.
- StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID();
return !(frame_zero_id < m_step_out_to_id);
}
diff --git a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
index 725669b1e9a8..f3d35a91fcbc 100644
--- a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
+++ b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanStepOverBreakpoint.cpp ------------------------*- C++ -*-===//
+//===-- ThreadPlanStepOverBreakpoint.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -30,9 +30,9 @@ ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint(Thread &thread)
m_auto_continue(false), m_reenabled_breakpoint_site(false)
{
- m_breakpoint_addr = m_thread.GetRegisterContext()->GetPC();
+ m_breakpoint_addr = thread.GetRegisterContext()->GetPC();
m_breakpoint_site_id =
- m_thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress(
+ thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress(
m_breakpoint_addr);
}
@@ -86,7 +86,7 @@ bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) {
// Be careful, however, as we may have "seen a breakpoint under the PC
// because we stopped without changing the PC, in which case we do want
// to re-claim this stop so we'll try again.
- lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC();
+ lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC();
if (pc_addr == m_breakpoint_addr) {
LLDB_LOGF(log,
@@ -120,10 +120,9 @@ bool ThreadPlanStepOverBreakpoint::DoWillResume(StateType resume_state,
bool current_plan) {
if (current_plan) {
BreakpointSiteSP bp_site_sp(
- m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress(
- m_breakpoint_addr));
+ m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr));
if (bp_site_sp && bp_site_sp->IsEnabled()) {
- m_thread.GetProcess()->DisableBreakpointSite(bp_site_sp.get());
+ m_process.DisableBreakpointSite(bp_site_sp.get());
m_reenabled_breakpoint_site = false;
}
}
@@ -140,7 +139,7 @@ void ThreadPlanStepOverBreakpoint::WillPop() {
}
bool ThreadPlanStepOverBreakpoint::MischiefManaged() {
- lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC();
+ lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC();
if (pc_addr == m_breakpoint_addr) {
// If we are still at the PC of our breakpoint, then for some reason we
@@ -161,10 +160,9 @@ void ThreadPlanStepOverBreakpoint::ReenableBreakpointSite() {
if (!m_reenabled_breakpoint_site) {
m_reenabled_breakpoint_site = true;
BreakpointSiteSP bp_site_sp(
- m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress(
- m_breakpoint_addr));
+ m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr));
if (bp_site_sp) {
- m_thread.GetProcess()->EnableBreakpointSite(bp_site_sp.get());
+ m_process.EnableBreakpointSite(bp_site_sp.get());
}
}
}
@@ -181,5 +179,5 @@ bool ThreadPlanStepOverBreakpoint::ShouldAutoContinue(Event *event_ptr) {
}
bool ThreadPlanStepOverBreakpoint::IsPlanStale() {
- return m_thread.GetRegisterContext()->GetPC() != m_breakpoint_addr;
+ return GetThread().GetRegisterContext()->GetPC() != m_breakpoint_addr;
}
diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp
index 3dc1967e6d4e..1bf3d5352c5b 100644
--- a/lldb/source/Target/ThreadPlanStepOverRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanStepOverRange.cpp -----------------------------*- C++ -*-===//
+//===-- ThreadPlanStepOverRange.cpp ---------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -85,7 +85,7 @@ void ThreadPlanStepOverRange::SetupAvoidNoDebug(
avoid_nodebug = false;
break;
case eLazyBoolCalculate:
- avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
break;
}
if (avoid_nodebug)
@@ -125,12 +125,12 @@ bool ThreadPlanStepOverRange::IsEquivalentContext(
bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
+ Thread &thread = GetThread();
if (log) {
StreamString s;
- DumpAddress(
- s.AsRawOstream(), m_thread.GetRegisterContext()->GetPC(),
- m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
+ DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(),
+ GetTarget().GetArchitecture().GetAddressByteSize());
LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData());
}
@@ -151,8 +151,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
// because the trampoline confused the backtracer. As below, we step
// through first, and then try to figure out how to get back out again.
- new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
- stop_others, m_status);
+ new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
+ stop_others, m_status);
if (new_plan_sp && log)
LLDB_LOGF(log,
@@ -161,7 +161,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
// Make sure we really are in a new frame. Do that by unwinding and seeing
// if the start function really is our start function...
for (uint32_t i = 1;; ++i) {
- StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i);
+ StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i);
if (!older_frame_sp) {
// We can't unwind the next frame we should just get out of here &
// stop...
@@ -171,12 +171,16 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
const SymbolContext &older_context =
older_frame_sp->GetSymbolContext(eSymbolContextEverything);
if (IsEquivalentContext(older_context)) {
- new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
+ // If we have the next-branch-breakpoint in the range, we can just
+ // rely on that breakpoint to trigger once we return to the range.
+ if (m_next_branch_bp_sp)
+ return false;
+ new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop(
false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
m_status, true);
break;
} else {
- new_plan_sp = m_thread.QueueThreadPlanForStepThrough(
+ new_plan_sp = thread.QueueThreadPlanForStepThrough(
m_stack_id, false, stop_others, m_status);
// If we found a way through, then we should stop recursing.
if (new_plan_sp)
@@ -196,8 +200,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
// we are in a stub then it's likely going to be hard to get out from
// here. It is probably easiest to step into the stub, and then it will
// be straight-forward to step out.
- new_plan_sp = m_thread.QueueThreadPlanForStepThrough(
- m_stack_id, false, stop_others, m_status);
+ new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
+ stop_others, m_status);
} else {
// The current clang (at least through 424) doesn't always get the
// address range for the DW_TAG_inlined_subroutines right, so that when
@@ -212,7 +216,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
if (m_addr_context.line_entry.IsValid()) {
SymbolContext sc;
- StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0);
+ StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0);
sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
if (sc.line_entry.IsValid()) {
if (sc.line_entry.original_file !=
@@ -278,7 +282,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
m_addr_context.line_entry.original_file) {
const bool abort_other_plans = false;
const RunMode stop_other_threads = RunMode::eAllThreads;
- lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0)
+ lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0)
->GetRegisterContext()
->GetPC();
AddressRange step_range(
@@ -286,7 +290,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
next_line_address.GetLoadAddress(&GetTarget()) -
cur_pc);
- new_plan_sp = m_thread.QueueThreadPlanForStepOverRange(
+ new_plan_sp = thread.QueueThreadPlanForStepOverRange(
abort_other_plans, step_range, sc, stop_other_threads,
m_status);
break;
@@ -365,23 +369,24 @@ bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
if (resume_state != eStateSuspended && m_first_resume) {
m_first_resume = false;
if (resume_state == eStateStepping && current_plan) {
+ Thread &thread = GetThread();
// See if we are about to step over an inlined call in the middle of the
// inlined stack, if so figure out its extents and reset our range to
// step over that.
- bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth();
+ bool in_inlined_stack = thread.DecrementCurrentInlinedDepth();
if (in_inlined_stack) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
LLDB_LOGF(log,
"ThreadPlanStepInRange::DoWillResume: adjusting range to "
"the frame at inlined depth %d.",
- m_thread.GetCurrentInlinedDepth());
- StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0);
+ thread.GetCurrentInlinedDepth());
+ StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
if (stack_sp) {
Block *frame_block = stack_sp->GetFrameBlock();
- lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
+ lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
AddressRange my_range;
if (frame_block->GetRangeContainingLoadAddress(
- curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) {
+ curr_pc, m_process.GetTarget(), my_range)) {
m_address_ranges.clear();
m_address_ranges.push_back(my_range);
if (log) {
@@ -390,11 +395,7 @@ bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
frame_block->GetInlinedFunctionInfo();
const char *name;
if (inline_info)
- name =
- inline_info
- ->GetName(frame_block->CalculateSymbolContextFunction()
- ->GetLanguage())
- .AsCString();
+ name = inline_info->GetName().AsCString();
else
name = "<unknown-notinlined>";
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
index d1c56165da50..f4b2ee3d08a2 100644
--- a/lldb/source/Target/ThreadPlanStepRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanStepRange.cpp ---------------------------------*- C++ -*-===//
+//===-- ThreadPlanStepRange.cpp -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -41,8 +41,8 @@ ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name,
m_given_ranges_only(given_ranges_only) {
m_use_fast_step = GetTarget().GetUseFastStepping();
AddRange(range);
- m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
- StackFrameSP parent_stack = m_thread.GetStackFrameAtIndex(1);
+ m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID();
+ StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1);
if (parent_stack)
m_parent_stack_id = parent_stack->GetStackID();
}
@@ -88,13 +88,11 @@ void ThreadPlanStepRange::AddRange(const AddressRange &new_range) {
void ThreadPlanStepRange::DumpRanges(Stream *s) {
size_t num_ranges = m_address_ranges.size();
if (num_ranges == 1) {
- m_address_ranges[0].Dump(s, m_thread.CalculateTarget().get(),
- Address::DumpStyleLoadAddress);
+ m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
} else {
for (size_t i = 0; i < num_ranges; i++) {
s->Printf(" %" PRIu64 ": ", uint64_t(i));
- m_address_ranges[i].Dump(s, m_thread.CalculateTarget().get(),
- Address::DumpStyleLoadAddress);
+ m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
}
}
}
@@ -102,20 +100,20 @@ void ThreadPlanStepRange::DumpRanges(Stream *s) {
bool ThreadPlanStepRange::InRange() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
bool ret_value = false;
-
- lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
+ Thread &thread = GetThread();
+ lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC();
size_t num_ranges = m_address_ranges.size();
for (size_t i = 0; i < num_ranges; i++) {
- ret_value = m_address_ranges[i].ContainsLoadAddress(
- pc_load_addr, m_thread.CalculateTarget().get());
+ ret_value =
+ m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget());
if (ret_value)
break;
}
if (!ret_value && !m_given_ranges_only) {
// See if we've just stepped to another part of the same line number...
- StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
+ StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
SymbolContext new_context(
frame->GetSymbolContext(eSymbolContextEverything));
@@ -132,8 +130,8 @@ bool ThreadPlanStepRange::InRange() {
ret_value = true;
if (log) {
StreamString s;
- m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(),
- true, Address::DumpStyleLoadAddress,
+ m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
+ Address::DumpStyleLoadAddress,
Address::DumpStyleLoadAddress, true);
LLDB_LOGF(
@@ -151,8 +149,8 @@ bool ThreadPlanStepRange::InRange() {
ret_value = true;
if (log) {
StreamString s;
- m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(),
- true, Address::DumpStyleLoadAddress,
+ m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
+ Address::DumpStyleLoadAddress,
Address::DumpStyleLoadAddress, true);
LLDB_LOGF(log,
@@ -161,7 +159,7 @@ bool ThreadPlanStepRange::InRange() {
s.GetData());
}
} else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(
- m_thread.CalculateTarget().get()) != pc_load_addr) {
+ &GetTarget()) != pc_load_addr) {
// Another thing that sometimes happens here is that we step out of
// one line into the MIDDLE of another line. So far I mostly see
// this due to bugs in the debug information. But we probably don't
@@ -174,8 +172,8 @@ bool ThreadPlanStepRange::InRange() {
ret_value = true;
if (log) {
StreamString s;
- m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(),
- true, Address::DumpStyleLoadAddress,
+ m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
+ Address::DumpStyleLoadAddress,
Address::DumpStyleLoadAddress, true);
LLDB_LOGF(log,
@@ -195,14 +193,14 @@ bool ThreadPlanStepRange::InRange() {
}
bool ThreadPlanStepRange::InSymbol() {
- lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
+ lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC();
if (m_addr_context.function != nullptr) {
return m_addr_context.function->GetAddressRange().ContainsLoadAddress(
- cur_pc, m_thread.CalculateTarget().get());
+ cur_pc, &GetTarget());
} else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) {
AddressRange range(m_addr_context.symbol->GetAddressRef(),
m_addr_context.symbol->GetByteSize());
- return range.ContainsLoadAddress(cur_pc, m_thread.CalculateTarget().get());
+ return range.ContainsLoadAddress(cur_pc, &GetTarget());
}
return false;
}
@@ -216,15 +214,15 @@ bool ThreadPlanStepRange::InSymbol() {
lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() {
FrameComparison frame_order;
-
- StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ Thread &thread = GetThread();
+ StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID();
if (cur_frame_id == m_stack_id) {
frame_order = eFrameCompareEqual;
} else if (cur_frame_id < m_stack_id) {
frame_order = eFrameCompareYounger;
} else {
- StackFrameSP cur_parent_frame = m_thread.GetStackFrameAtIndex(1);
+ StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1);
StackID cur_parent_id;
if (cur_parent_frame)
cur_parent_id = cur_parent_frame->GetStackID();
@@ -264,12 +262,11 @@ InstructionList *ThreadPlanStepRange::GetInstructionsForAddress(
if (!m_instruction_ranges[i]) {
// Disassemble the address range given:
- ExecutionContext exe_ctx(m_thread.GetProcess());
const char *plugin_name = nullptr;
const char *flavor = nullptr;
const bool prefer_file_cache = true;
m_instruction_ranges[i] = Disassembler::DisassembleRange(
- GetTarget().GetArchitecture(), plugin_name, flavor, exe_ctx,
+ GetTarget().GetArchitecture(), plugin_name, flavor, GetTarget(),
m_address_ranges[i], prefer_file_cache);
}
if (!m_instruction_ranges[i])
@@ -378,11 +375,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
"ThreadPlanStepRange::SetNextBranchBreakpoint - Setting "
"breakpoint %d (site %d) to run to address 0x%" PRIx64,
m_next_branch_bp_sp->GetID(), bp_site_id,
- run_to_address.GetLoadAddress(
- &m_thread.GetProcess()->GetTarget()));
+ run_to_address.GetLoadAddress(&m_process.GetTarget()));
}
- m_next_branch_bp_sp->SetThreadID(m_thread.GetID());
+ m_next_branch_bp_sp->SetThreadID(m_tid);
m_next_branch_bp_sp->SetBreakpointKind("next-branch-location");
return true;
@@ -401,7 +397,7 @@ bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
break_id_t bp_site_id = stop_info_sp->GetValue();
BreakpointSiteSP bp_site_sp =
- m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id);
+ m_process.GetBreakpointSiteList().FindByID(bp_site_id);
if (!bp_site_sp)
return false;
else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID()))
@@ -488,11 +484,11 @@ bool ThreadPlanStepRange::IsPlanStale() {
// check that we are in the same symbol.
if (!InRange()) {
// Set plan Complete when we reach next instruction just after the range
- lldb::addr_t addr = m_thread.GetRegisterContext()->GetPC() - 1;
+ lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1;
size_t num_ranges = m_address_ranges.size();
for (size_t i = 0; i < num_ranges; i++) {
- bool in_range = m_address_ranges[i].ContainsLoadAddress(
- addr, m_thread.CalculateTarget().get());
+ bool in_range =
+ m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget());
if (in_range) {
SetPlanComplete();
}
diff --git a/lldb/source/Target/ThreadPlanStepThrough.cpp b/lldb/source/Target/ThreadPlanStepThrough.cpp
index 8c7b180fce2d..06b626935aba 100644
--- a/lldb/source/Target/ThreadPlanStepThrough.cpp
+++ b/lldb/source/Target/ThreadPlanStepThrough.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanStepThrough.cpp -------------------------------*- C++ -*-===//
+//===-- ThreadPlanStepThrough.cpp -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -44,21 +44,20 @@ ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread,
// some inlined code that we're in the middle of by doing this, but it's
// easier than trying to figure out where the inlined code might return to.
- StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID(m_stack_id);
+ StackFrameSP return_frame_sp = thread.GetFrameWithStackID(m_stack_id);
if (return_frame_sp) {
m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(
- m_thread.CalculateTarget().get());
+ thread.CalculateTarget().get());
Breakpoint *return_bp =
- m_thread.GetProcess()
- ->GetTarget()
+ m_process.GetTarget()
.CreateBreakpoint(m_backstop_addr, true, false)
.get();
if (return_bp != nullptr) {
if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
m_could_not_resolve_hw_bp = true;
- return_bp->SetThreadID(m_thread.GetID());
+ return_bp->SetThreadID(m_tid);
m_backstop_bkpt_id = return_bp->GetID();
return_bp->SetBreakpointKind("step-through-backstop");
}
@@ -79,18 +78,17 @@ void ThreadPlanStepThrough::DidPush() {
}
void ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() {
- DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader();
+ Thread &thread = GetThread();
+ DynamicLoader *loader = thread.GetProcess()->GetDynamicLoader();
if (loader)
- m_sub_plan_sp =
- loader->GetStepThroughTrampolinePlan(m_thread, m_stop_others);
+ m_sub_plan_sp = loader->GetStepThroughTrampolinePlan(thread, m_stop_others);
// If the DynamicLoader was unable to provide us with a ThreadPlan, then we
// try the LanguageRuntimes.
if (!m_sub_plan_sp) {
- for (LanguageRuntime *runtime :
- m_thread.GetProcess()->GetLanguageRuntimes()) {
+ for (LanguageRuntime *runtime : m_process.GetLanguageRuntimes()) {
m_sub_plan_sp =
- runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others);
+ runtime->GetStepThroughTrampolinePlan(thread, m_stop_others);
if (m_sub_plan_sp)
break;
@@ -223,7 +221,7 @@ bool ThreadPlanStepThrough::WillStop() { return true; }
void ThreadPlanStepThrough::ClearBackstopBreakpoint() {
if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) {
- m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id);
+ m_process.GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id);
m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
m_could_not_resolve_hw_bp = false;
}
@@ -244,15 +242,15 @@ bool ThreadPlanStepThrough::MischiefManaged() {
}
bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() {
- StopInfoSP stop_info_sp(m_thread.GetStopInfo());
+ Thread &thread = GetThread();
+ StopInfoSP stop_info_sp(thread.GetStopInfo());
if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) {
break_id_t stop_value = (break_id_t)stop_info_sp->GetValue();
BreakpointSiteSP cur_site_sp =
- m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value);
+ m_process.GetBreakpointSiteList().FindByID(stop_value);
if (cur_site_sp &&
cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) {
- StackID cur_frame_zero_id =
- m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ StackID cur_frame_zero_id = thread.GetStackFrameAtIndex(0)->GetStackID();
if (cur_frame_zero_id == m_return_stack_id) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp
index 54d276337488..650fa624cd52 100644
--- a/lldb/source/Target/ThreadPlanStepUntil.cpp
+++ b/lldb/source/Target/ThreadPlanStepUntil.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanStepUntil.cpp ---------------------------------*- C++ -*-===//
+//===-- ThreadPlanStepUntil.cpp -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -34,17 +34,16 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
m_until_points(), m_stop_others(stop_others) {
// Stash away our "until" addresses:
- TargetSP target_sp(m_thread.CalculateTarget());
+ TargetSP target_sp(thread.CalculateTarget());
- StackFrameSP frame_sp(m_thread.GetStackFrameAtIndex(frame_idx));
+ StackFrameSP frame_sp(thread.GetStackFrameAtIndex(frame_idx));
if (frame_sp) {
m_step_from_insn = frame_sp->GetStackID().GetPC();
- lldb::user_id_t thread_id = m_thread.GetID();
// Find the return address and set a breakpoint there:
// FIXME - can we do this more securely if we know first_insn?
- StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1));
+ StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(frame_idx + 1));
if (return_frame_sp) {
// TODO: add inline functionality
m_return_addr = return_frame_sp->GetStackID().GetPC();
@@ -54,7 +53,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
if (return_bp != nullptr) {
if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
m_could_not_resolve_hw_bp = true;
- return_bp->SetThreadID(thread_id);
+ return_bp->SetThreadID(m_tid);
m_return_bp_id = return_bp->GetID();
return_bp->SetBreakpointKind("until-return-backstop");
}
@@ -67,7 +66,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
Breakpoint *until_bp =
target_sp->CreateBreakpoint(address_list[i], true, false).get();
if (until_bp != nullptr) {
- until_bp->SetThreadID(thread_id);
+ until_bp->SetThreadID(m_tid);
m_until_points[address_list[i]] = until_bp->GetID();
until_bp->SetBreakpointKind("until-target");
} else {
@@ -80,17 +79,15 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); }
void ThreadPlanStepUntil::Clear() {
- TargetSP target_sp(m_thread.CalculateTarget());
- if (target_sp) {
- if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
- target_sp->RemoveBreakpointByID(m_return_bp_id);
- m_return_bp_id = LLDB_INVALID_BREAK_ID;
- }
+ Target &target = GetTarget();
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
+ target.RemoveBreakpointByID(m_return_bp_id);
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ }
- until_collection::iterator pos, end = m_until_points.end();
- for (pos = m_until_points.begin(); pos != end; pos++) {
- target_sp->RemoveBreakpointByID((*pos).second);
- }
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++) {
+ target.RemoveBreakpointByID((*pos).second);
}
m_until_points.clear();
m_could_not_resolve_hw_bp = false;
@@ -158,8 +155,7 @@ void ThreadPlanStepUntil::AnalyzeStop() {
// If this is OUR breakpoint, we're fine, otherwise we don't know why
// this happened...
BreakpointSiteSP this_site =
- m_thread.GetProcess()->GetBreakpointSiteList().FindByID(
- stop_info_sp->GetValue());
+ m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue());
if (!this_site) {
m_explains_stop = false;
return;
@@ -196,17 +192,17 @@ void ThreadPlanStepUntil::AnalyzeStop() {
for (pos = m_until_points.begin(); pos != end; pos++) {
if (this_site->IsBreakpointAtThisSite((*pos).second)) {
// If we're at the right stack depth, then we're done.
-
+ Thread &thread = GetThread();
bool done;
StackID frame_zero_id =
- m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ thread.GetStackFrameAtIndex(0)->GetStackID();
if (frame_zero_id == m_stack_id)
done = true;
else if (frame_zero_id < m_stack_id)
done = false;
else {
- StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
+ StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(1);
// But if we can't even unwind one frame we should just get out
// of here & stop...
@@ -280,20 +276,16 @@ StateType ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning; }
bool ThreadPlanStepUntil::DoWillResume(StateType resume_state,
bool current_plan) {
if (current_plan) {
- TargetSP target_sp(m_thread.CalculateTarget());
- if (target_sp) {
- Breakpoint *return_bp =
- target_sp->GetBreakpointByID(m_return_bp_id).get();
- if (return_bp != nullptr)
- return_bp->SetEnabled(true);
+ Target &target = GetTarget();
+ Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != nullptr)
+ return_bp->SetEnabled(true);
- until_collection::iterator pos, end = m_until_points.end();
- for (pos = m_until_points.begin(); pos != end; pos++) {
- Breakpoint *until_bp =
- target_sp->GetBreakpointByID((*pos).second).get();
- if (until_bp != nullptr)
- until_bp->SetEnabled(true);
- }
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++) {
+ Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
+ if (until_bp != nullptr)
+ until_bp->SetEnabled(true);
}
}
@@ -304,18 +296,16 @@ bool ThreadPlanStepUntil::DoWillResume(StateType resume_state,
}
bool ThreadPlanStepUntil::WillStop() {
- TargetSP target_sp(m_thread.CalculateTarget());
- if (target_sp) {
- Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
- if (return_bp != nullptr)
- return_bp->SetEnabled(false);
-
- until_collection::iterator pos, end = m_until_points.end();
- for (pos = m_until_points.begin(); pos != end; pos++) {
- Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
- if (until_bp != nullptr)
- until_bp->SetEnabled(false);
- }
+ Target &target = GetTarget();
+ Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != nullptr)
+ return_bp->SetEnabled(false);
+
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++) {
+ Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
+ if (until_bp != nullptr)
+ until_bp->SetEnabled(false);
}
return true;
}
diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp
index b50c1636b7ff..c00415f3c1ee 100644
--- a/lldb/source/Target/ThreadPlanTracer.cpp
+++ b/lldb/source/Target/ThreadPlanTracer.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadPlanTracer.cpp ------------------------------------*- C++ -*-===//
+//===-- ThreadPlanTracer.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -34,23 +34,32 @@ using namespace lldb_private;
#pragma mark ThreadPlanTracer
ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
- : m_thread(thread), m_single_step(true), m_enabled(false),
- m_stream_sp(stream_sp) {}
+ : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
+ m_single_step(true), m_enabled(false), m_stream_sp(stream_sp) {}
ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
- : m_thread(thread), m_single_step(true), m_enabled(false), m_stream_sp() {}
+ : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
+ m_single_step(true), m_enabled(false), m_stream_sp() {}
Stream *ThreadPlanTracer::GetLogStream() {
if (m_stream_sp)
return m_stream_sp.get();
else {
- TargetSP target_sp(m_thread.CalculateTarget());
+ TargetSP target_sp(GetThread().CalculateTarget());
if (target_sp)
return &(target_sp->GetDebugger().GetOutputStream());
}
return nullptr;
}
+Thread &ThreadPlanTracer::GetThread() {
+ if (m_thread)
+ return *m_thread;
+
+ ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
+ m_thread = thread_sp.get();
+ return *m_thread;
+}
void ThreadPlanTracer::Log() {
SymbolContext sc;
bool show_frame_index = false;
@@ -58,8 +67,8 @@ void ThreadPlanTracer::Log() {
Stream *stream = GetLogStream();
if (stream) {
- m_thread.GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
- show_fullpaths);
+ GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
+ show_fullpaths);
stream->Printf("\n");
stream->Flush();
}
@@ -67,7 +76,7 @@ void ThreadPlanTracer::Log() {
bool ThreadPlanTracer::TracerExplainsStop() {
if (m_enabled && m_single_step) {
- lldb::StopInfoSP stop_info = m_thread.GetStopInfo();
+ lldb::StopInfoSP stop_info = GetThread().GetStopInfo();
return (stop_info->GetStopReason() == eStopReasonTrace);
} else
return false;
@@ -87,13 +96,13 @@ ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread)
Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() {
if (!m_disassembler_sp)
m_disassembler_sp = Disassembler::FindPlugin(
- m_thread.GetProcess()->GetTarget().GetArchitecture(), nullptr, nullptr);
+ m_process.GetTarget().GetArchitecture(), nullptr, nullptr);
return m_disassembler_sp.get();
}
TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() {
if (!m_intptr_type.IsValid()) {
- if (auto target_sp = m_thread.CalculateTarget()) {
+ if (auto target_sp = m_process.CalculateTarget()) {
auto type_system_or_err =
target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
if (auto err = type_system_or_err.takeError()) {
@@ -125,29 +134,27 @@ void ThreadPlanAssemblyTracer::Log() {
if (!stream)
return;
- RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
lldb::addr_t pc = reg_ctx->GetPC();
- ProcessSP process_sp(m_thread.GetProcess());
Address pc_addr;
bool addr_valid = false;
uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
- addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(
+ addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress(
pc, pc_addr);
- pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription,
+ pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription,
Address::DumpStyleModuleWithFileAddress);
stream->PutCString(" ");
Disassembler *disassembler = GetDisassembler();
if (disassembler) {
Status err;
- process_sp->ReadMemory(pc, buffer, sizeof(buffer), err);
+ m_process.ReadMemory(pc, buffer, sizeof(buffer), err);
if (err.Success()) {
- DataExtractor extractor(buffer, sizeof(buffer),
- process_sp->GetByteOrder(),
- process_sp->GetAddressByteSize());
+ DataExtractor extractor(buffer, sizeof(buffer), m_process.GetByteOrder(),
+ m_process.GetAddressByteSize());
bool data_from_file = false;
if (addr_valid)
@@ -167,10 +174,7 @@ void ThreadPlanAssemblyTracer::Log() {
Instruction *instruction =
instruction_list.GetInstructionAtIndex(0).get();
const FormatEntity::Entry *disassemble_format =
- m_thread.GetProcess()
- ->GetTarget()
- .GetDebugger()
- .GetDisassemblyFormat();
+ m_process.GetTarget().GetDebugger().GetDisassemblyFormat();
instruction->Dump(stream, max_opcode_byte_size, show_address,
show_bytes, nullptr, nullptr, nullptr,
disassemble_format, 0);
@@ -178,7 +182,7 @@ void ThreadPlanAssemblyTracer::Log() {
}
}
- const ABI *abi = process_sp->GetABI().get();
+ const ABI *abi = m_process.GetABI().get();
TypeFromUser intptr_type = GetIntPointerType();
if (abi && intptr_type.IsValid()) {
@@ -192,7 +196,7 @@ void ThreadPlanAssemblyTracer::Log() {
value_list.PushValue(value);
}
- if (abi->GetArgumentValues(m_thread, value_list)) {
+ if (abi->GetArgumentValues(GetThread(), value_list)) {
for (int arg_index = 0; arg_index < num_args; ++arg_index) {
stream->Printf(
"\n\targ[%d]=%llx", arg_index,
@@ -205,7 +209,7 @@ void ThreadPlanAssemblyTracer::Log() {
}
if (m_register_values.empty()) {
- RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
m_register_values.resize(reg_ctx->GetRegisterCount());
}
diff --git a/lldb/source/Target/ThreadSpec.cpp b/lldb/source/Target/ThreadSpec.cpp
index 1a733cb551e5..1f6639379c45 100644
--- a/lldb/source/Target/ThreadSpec.cpp
+++ b/lldb/source/Target/ThreadSpec.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadSpec.cpp ------------------------------------------*- C++ -*-===//
+//===-- ThreadSpec.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp
index 33090a72df54..dce32adbf0a3 100644
--- a/lldb/source/Target/UnixSignals.cpp
+++ b/lldb/source/Target/UnixSignals.cpp
@@ -1,4 +1,4 @@
-//===-- UnixSignals.cpp -----------------------------------------*- C++ -*-===//
+//===-- UnixSignals.cpp ---------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -145,10 +145,8 @@ bool UnixSignals::SignalIsValid(int32_t signo) const {
}
ConstString UnixSignals::GetShortName(ConstString name) const {
- if (name) {
- const char *signame = name.AsCString();
- return ConstString(signame + 3); // Remove "SIG" from name
- }
+ if (name)
+ return ConstString(name.GetStringRef().substr(3)); // Remove "SIG" from name
return name;
}
diff --git a/lldb/source/Target/UnwindAssembly.cpp b/lldb/source/Target/UnwindAssembly.cpp
index d3d8068687c0..3a87e3da5bca 100644
--- a/lldb/source/Target/UnwindAssembly.cpp
+++ b/lldb/source/Target/UnwindAssembly.cpp
@@ -1,4 +1,4 @@
-//===-- UnwindAssembly.cpp --------------------------------------*- C++ -*-===//
+//===-- UnwindAssembly.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp
new file mode 100644
index 000000000000..980ad4d2e342
--- /dev/null
+++ b/lldb/source/Target/UnwindLLDB.cpp
@@ -0,0 +1,518 @@
+//===-- UnwindLLDB.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/UnwindLLDB.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/RegisterContextUnwind.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindLLDB::UnwindLLDB(Thread &thread)
+ : Unwind(thread), m_frames(), m_unwind_complete(false),
+ m_user_supplied_trap_handler_functions() {
+ ProcessSP process_sp(thread.GetProcess());
+ if (process_sp) {
+ Args args;
+ process_sp->GetTarget().GetUserSpecifiedTrapHandlerNames(args);
+ size_t count = args.GetArgumentCount();
+ for (size_t i = 0; i < count; i++) {
+ const char *func_name = args.GetArgumentAtIndex(i);
+ m_user_supplied_trap_handler_functions.push_back(ConstString(func_name));
+ }
+ }
+}
+
+uint32_t UnwindLLDB::DoGetFrameCount() {
+ if (!m_unwind_complete) {
+//#define DEBUG_FRAME_SPEED 1
+#if DEBUG_FRAME_SPEED
+#define FRAME_COUNT 10000
+ using namespace std::chrono;
+ auto time_value = steady_clock::now();
+#endif
+ if (!AddFirstFrame())
+ return 0;
+
+ ProcessSP process_sp(m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr;
+
+ while (AddOneMoreFrame(abi)) {
+#if DEBUG_FRAME_SPEED
+ if ((m_frames.size() % FRAME_COUNT) == 0) {
+ const auto now = steady_clock::now();
+ const auto delta_t = now - time_value;
+ printf("%u frames in %.9f ms (%g frames/sec)\n", FRAME_COUNT,
+ duration<double, std::milli>(delta_t).count(),
+ (float)FRAME_COUNT / duration<double>(delta_t).count());
+ time_value = now;
+ }
+#endif
+ }
+ }
+ return m_frames.size();
+}
+
+bool UnwindLLDB::AddFirstFrame() {
+ if (m_frames.size() > 0)
+ return true;
+
+ ProcessSP process_sp(m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr;
+
+ // First, set up the 0th (initial) frame
+ CursorSP first_cursor_sp(new Cursor());
+ RegisterContextLLDBSP reg_ctx_sp(new RegisterContextUnwind(
+ m_thread, RegisterContextLLDBSP(), first_cursor_sp->sctx, 0, *this));
+ if (reg_ctx_sp.get() == nullptr)
+ goto unwind_done;
+
+ if (!reg_ctx_sp->IsValid())
+ goto unwind_done;
+
+ if (!reg_ctx_sp->GetCFA(first_cursor_sp->cfa))
+ goto unwind_done;
+
+ if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc))
+ goto unwind_done;
+
+ // Everything checks out, so release the auto pointer value and let the
+ // cursor own it in its shared pointer
+ first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ m_frames.push_back(first_cursor_sp);
+
+ // Update the Full Unwind Plan for this frame if not valid
+ UpdateUnwindPlanForFirstFrameIfInvalid(abi);
+
+ return true;
+
+unwind_done:
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+ if (log) {
+ LLDB_LOGF(log, "th%d Unwind of this thread is complete.",
+ m_thread.GetIndexID());
+ }
+ m_unwind_complete = true;
+ return false;
+}
+
+UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) {
+ assert(m_frames.size() != 0 &&
+ "Get one more frame called with empty frame list");
+
+ // If we've already gotten to the end of the stack, don't bother to try
+ // again...
+ if (m_unwind_complete)
+ return nullptr;
+
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+
+ CursorSP prev_frame = m_frames.back();
+ uint32_t cur_idx = m_frames.size();
+
+ CursorSP cursor_sp(new Cursor());
+ RegisterContextLLDBSP reg_ctx_sp(new RegisterContextUnwind(
+ m_thread, prev_frame->reg_ctx_lldb_sp, cursor_sp->sctx, cur_idx, *this));
+
+ uint64_t max_stack_depth = m_thread.GetMaxBacktraceDepth();
+
+ // We want to detect an unwind that cycles erroneously and stop backtracing.
+ // Don't want this maximum unwind limit to be too low -- if you have a
+ // backtrace with an "infinitely recursing" bug, it will crash when the stack
+ // blows out and the first 35,000 frames are uninteresting - it's the top
+ // most 5 frames that you actually care about. So you can't just cap the
+ // unwind at 10,000 or something. Realistically anything over around 200,000
+ // is going to blow out the stack space. If we're still unwinding at that
+ // point, we're probably never going to finish.
+ if (cur_idx >= max_stack_depth) {
+ LLDB_LOGF(log,
+ "%*sFrame %d unwound too many frames, assuming unwind has "
+ "gone astray, stopping.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+
+ if (reg_ctx_sp.get() == nullptr) {
+ // If the RegisterContextUnwind has a fallback UnwindPlan, it will switch to
+ // that and return true. Subsequent calls to TryFallbackUnwindPlan() will
+ // return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) {
+ // TryFallbackUnwindPlan for prev_frame succeeded and updated
+ // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame
+ // still needs to be updated. Hence updating it.
+ if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa)))
+ return nullptr;
+
+ return GetOneMoreFrame(abi);
+ }
+
+ LLDB_LOGF(log, "%*sFrame %d did not get a RegisterContext, stopping.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+
+ if (!reg_ctx_sp->IsValid()) {
+ // We failed to get a valid RegisterContext. See if the regctx below this
+ // on the stack has a fallback unwind plan it can use. Subsequent calls to
+ // TryFallbackUnwindPlan() will return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) {
+ // TryFallbackUnwindPlan for prev_frame succeeded and updated
+ // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame
+ // still needs to be updated. Hence updating it.
+ if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa)))
+ return nullptr;
+
+ return GetOneMoreFrame(abi);
+ }
+
+ LLDB_LOGF(log,
+ "%*sFrame %d invalid RegisterContext for this frame, "
+ "stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ if (!reg_ctx_sp->GetCFA(cursor_sp->cfa)) {
+ // If the RegisterContextUnwind has a fallback UnwindPlan, it will switch to
+ // that and return true. Subsequent calls to TryFallbackUnwindPlan() will
+ // return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) {
+ // TryFallbackUnwindPlan for prev_frame succeeded and updated
+ // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame
+ // still needs to be updated. Hence updating it.
+ if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa)))
+ return nullptr;
+
+ return GetOneMoreFrame(abi);
+ }
+
+ LLDB_LOGF(log,
+ "%*sFrame %d did not get CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa)) {
+ // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not
+ // have its (constructed) CFA aligned correctly -- don't do the abi
+ // alignment check for these.
+ if (!reg_ctx_sp->IsTrapHandlerFrame()) {
+ // See if we can find a fallback unwind plan for THIS frame. It may be
+ // that the UnwindPlan we're using for THIS frame was bad and gave us a
+ // bad CFA. If that's not it, then see if we can change the UnwindPlan
+ // for the frame below us ("NEXT") -- see if using that other UnwindPlan
+ // gets us a better unwind state.
+ if (!reg_ctx_sp->TryFallbackUnwindPlan() ||
+ !reg_ctx_sp->GetCFA(cursor_sp->cfa) ||
+ !abi->CallFrameAddressIsValid(cursor_sp->cfa)) {
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) {
+ // TryFallbackUnwindPlan for prev_frame succeeded and updated
+ // reg_ctx_lldb_sp field of prev_frame. However, cfa field of
+ // prev_frame still needs to be updated. Hence updating it.
+ if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa)))
+ return nullptr;
+
+ return GetOneMoreFrame(abi);
+ }
+
+ LLDB_LOGF(log,
+ "%*sFrame %d did not get a valid CFA for this frame, "
+ "stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ } else {
+ LLDB_LOGF(log,
+ "%*sFrame %d had a bad CFA value but we switched the "
+ "UnwindPlan being used and got one that looks more "
+ "realistic.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ }
+ }
+ if (!reg_ctx_sp->ReadPC(cursor_sp->start_pc)) {
+ // If the RegisterContextUnwind has a fallback UnwindPlan, it will switch to
+ // that and return true. Subsequent calls to TryFallbackUnwindPlan() will
+ // return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) {
+ // TryFallbackUnwindPlan for prev_frame succeeded and updated
+ // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame
+ // still needs to be updated. Hence updating it.
+ if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa)))
+ return nullptr;
+
+ return GetOneMoreFrame(abi);
+ }
+
+ LLDB_LOGF(log,
+ "%*sFrame %d did not get PC for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ if (abi && !abi->CodeAddressIsValid(cursor_sp->start_pc)) {
+ // If the RegisterContextUnwind has a fallback UnwindPlan, it will switch to
+ // that and return true. Subsequent calls to TryFallbackUnwindPlan() will
+ // return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) {
+ // TryFallbackUnwindPlan for prev_frame succeeded and updated
+ // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame
+ // still needs to be updated. Hence updating it.
+ if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa)))
+ return nullptr;
+
+ return GetOneMoreFrame(abi);
+ }
+
+ LLDB_LOGF(log, "%*sFrame %d did not get a valid PC, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ // Infinite loop where the current cursor is the same as the previous one...
+ if (prev_frame->start_pc == cursor_sp->start_pc &&
+ prev_frame->cfa == cursor_sp->cfa) {
+ LLDB_LOGF(log,
+ "th%d pc of this frame is the same as the previous frame and "
+ "CFAs for both frames are identical -- stopping unwind",
+ m_thread.GetIndexID());
+ return nullptr;
+ }
+
+ cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ return cursor_sp;
+}
+
+void UnwindLLDB::UpdateUnwindPlanForFirstFrameIfInvalid(ABI *abi) {
+ // This function is called for First Frame only.
+ assert(m_frames.size() == 1 && "No. of cursor frames are not 1");
+
+ bool old_m_unwind_complete = m_unwind_complete;
+ CursorSP old_m_candidate_frame = m_candidate_frame;
+
+ // Try to unwind 2 more frames using the Unwinder. It uses Full UnwindPlan
+ // and if Full UnwindPlan fails, then uses FallBack UnwindPlan. Also update
+ // the cfa of Frame 0 (if required).
+ AddOneMoreFrame(abi);
+
+ // Remove all the frames added by above function as the purpose of using
+ // above function was just to check whether Unwinder of Frame 0 works or not.
+ for (uint32_t i = 1; i < m_frames.size(); i++)
+ m_frames.pop_back();
+
+ // Restore status after calling AddOneMoreFrame
+ m_unwind_complete = old_m_unwind_complete;
+ m_candidate_frame = old_m_candidate_frame;
+ return;
+}
+
+bool UnwindLLDB::AddOneMoreFrame(ABI *abi) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
+
+ // Frame zero is a little different
+ if (m_frames.empty())
+ return false;
+
+ // If we've already gotten to the end of the stack, don't bother to try
+ // again...
+ if (m_unwind_complete)
+ return false;
+
+ CursorSP new_frame = m_candidate_frame;
+ if (new_frame == nullptr)
+ new_frame = GetOneMoreFrame(abi);
+
+ if (new_frame == nullptr) {
+ LLDB_LOGF(log, "th%d Unwind of this thread is complete.",
+ m_thread.GetIndexID());
+ m_unwind_complete = true;
+ return false;
+ }
+
+ m_frames.push_back(new_frame);
+
+ // If we can get one more frame further then accept that we get back a
+ // correct frame.
+ m_candidate_frame = GetOneMoreFrame(abi);
+ if (m_candidate_frame)
+ return true;
+
+ // We can't go further from the frame returned by GetOneMore frame. Lets try
+ // to get a different frame with using the fallback unwind plan.
+ if (!m_frames[m_frames.size() - 2]
+ ->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) {
+ // We don't have a valid fallback unwind plan. Accept the frame as it is.
+ // This is a valid situation when we are at the bottom of the stack.
+ return true;
+ }
+
+ // Remove the possibly incorrect frame from the frame list and try to add a
+ // different one with the newly selected fallback unwind plan.
+ m_frames.pop_back();
+ CursorSP new_frame_v2 = GetOneMoreFrame(abi);
+ if (new_frame_v2 == nullptr) {
+ // We haven't got a new frame from the fallback unwind plan. Accept the
+ // frame from the original unwind plan. This is a valid situation when we
+ // are at the bottom of the stack.
+ m_frames.push_back(new_frame);
+ return true;
+ }
+
+ // Push the new frame to the list and try to continue from this frame. If we
+ // can get a new frame then accept it as the correct one.
+ m_frames.push_back(new_frame_v2);
+ m_candidate_frame = GetOneMoreFrame(abi);
+ if (m_candidate_frame) {
+ // If control reached here then TryFallbackUnwindPlan had succeeded for
+ // Cursor::m_frames[m_frames.size() - 2]. It also succeeded to Unwind next
+ // 2 frames i.e. m_frames[m_frames.size() - 1] and a frame after that. For
+ // Cursor::m_frames[m_frames.size() - 2], reg_ctx_lldb_sp field was already
+ // updated during TryFallbackUnwindPlan call above. However, cfa field
+ // still needs to be updated. Hence updating it here and then returning.
+ return m_frames[m_frames.size() - 2]->reg_ctx_lldb_sp->GetCFA(
+ m_frames[m_frames.size() - 2]->cfa);
+ }
+
+ // The new frame hasn't helped in unwinding. Fall back to the original one as
+ // the default unwind plan is usually more reliable then the fallback one.
+ m_frames.pop_back();
+ m_frames.push_back(new_frame);
+ return true;
+}
+
+bool UnwindLLDB::DoGetFrameInfoAtIndex(uint32_t idx, addr_t &cfa, addr_t &pc,
+ bool &behaves_like_zeroth_frame) {
+ if (m_frames.size() == 0) {
+ if (!AddFirstFrame())
+ return false;
+ }
+
+ ProcessSP process_sp(m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr;
+
+ while (idx >= m_frames.size() && AddOneMoreFrame(abi))
+ ;
+
+ if (idx < m_frames.size()) {
+ cfa = m_frames[idx]->cfa;
+ pc = m_frames[idx]->start_pc;
+ if (idx == 0) {
+ // Frame zero always behaves like it.
+ behaves_like_zeroth_frame = true;
+ } else if (m_frames[idx - 1]->reg_ctx_lldb_sp->IsTrapHandlerFrame()) {
+ // This could be an asynchronous signal, thus the
+ // pc might point to the interrupted instruction rather
+ // than a post-call instruction
+ behaves_like_zeroth_frame = true;
+ } else if (m_frames[idx]->reg_ctx_lldb_sp->IsTrapHandlerFrame()) {
+ // This frame may result from signal processing installing
+ // a pointer to the first byte of a signal-return trampoline
+ // in the return address slot of the frame below, so this
+ // too behaves like the zeroth frame (i.e. the pc might not
+ // be pointing just past a call in it)
+ behaves_like_zeroth_frame = true;
+ } else {
+ behaves_like_zeroth_frame = false;
+ }
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindLLDB::DoCreateRegisterContextForFrame(StackFrame *frame) {
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t idx = frame->GetConcreteFrameIndex();
+
+ if (idx == 0) {
+ return m_thread.GetRegisterContext();
+ }
+
+ if (m_frames.size() == 0) {
+ if (!AddFirstFrame())
+ return reg_ctx_sp;
+ }
+
+ ProcessSP process_sp(m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr;
+
+ while (idx >= m_frames.size()) {
+ if (!AddOneMoreFrame(abi))
+ break;
+ }
+
+ const uint32_t num_frames = m_frames.size();
+ if (idx < num_frames) {
+ Cursor *frame_cursor = m_frames[idx].get();
+ reg_ctx_sp = frame_cursor->reg_ctx_lldb_sp;
+ }
+ return reg_ctx_sp;
+}
+
+UnwindLLDB::RegisterContextLLDBSP
+UnwindLLDB::GetRegisterContextForFrameNum(uint32_t frame_num) {
+ RegisterContextLLDBSP reg_ctx_sp;
+ if (frame_num < m_frames.size())
+ reg_ctx_sp = m_frames[frame_num]->reg_ctx_lldb_sp;
+ return reg_ctx_sp;
+}
+
+bool UnwindLLDB::SearchForSavedLocationForRegister(
+ uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc,
+ uint32_t starting_frame_num, bool pc_reg) {
+ int64_t frame_num = starting_frame_num;
+ if (static_cast<size_t>(frame_num) >= m_frames.size())
+ return false;
+
+ // Never interrogate more than one level while looking for the saved pc
+ // value. If the value isn't saved by frame_num, none of the frames lower on
+ // the stack will have a useful value.
+ if (pc_reg) {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister(
+ lldb_regnum, regloc);
+ return result == UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ while (frame_num >= 0) {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister(
+ lldb_regnum, regloc);
+
+ // We descended down to the live register context aka stack frame 0 and are
+ // reading the value out of a live register.
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound &&
+ regloc.type ==
+ UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext) {
+ return true;
+ }
+
+ // If we have unwind instructions saying that register N is saved in
+ // register M in the middle of the stack (and N can equal M here, meaning
+ // the register was not used in this function), then change the register
+ // number we're looking for to M and keep looking for a concrete location
+ // down the stack, or an actual value from a live RegisterContext at frame
+ // 0.
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound &&
+ regloc.type == UnwindLLDB::RegisterLocation::eRegisterInRegister &&
+ frame_num > 0) {
+ result = UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ lldb_regnum = regloc.location.register_number;
+ }
+
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile)
+ return false;
+ frame_num--;
+ }
+ return false;
+}