summaryrefslogtreecommitdiff
path: root/lldb/source
diff options
context:
space:
mode:
authorKoakuma <koachan@protonmail.com>2024-07-08 19:19:54 +0700
committerKoakuma <koachan@protonmail.com>2024-07-08 19:19:54 +0700
commit5c4fdc2fd5898ebd9e89999a4f4b8aa289ca637f (patch)
treef3b92a07f3dfc6e70f36d1000605f36a3c15af46 /lldb/source
parentdbda8e2f2cd8764e0badd983915d62a2c3377f4d (diff)
parente9b8cd0c806db00f0981fb36717077c941426302 (diff)
Created using spr 1.3.5 [skip ci]
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/SBAddressRange.cpp29
-rw-r--r--lldb/source/API/SBAddressRangeList.cpp17
-rw-r--r--lldb/source/API/SBDebugger.cpp4
-rw-r--r--lldb/source/API/SBProcess.cpp58
-rw-r--r--lldb/source/API/SBStatisticsOptions.cpp35
-rw-r--r--lldb/source/API/SBTarget.cpp10
-rw-r--r--lldb/source/API/SBValue.cpp32
-rw-r--r--lldb/source/Breakpoint/BreakpointOptions.cpp18
-rw-r--r--lldb/source/Breakpoint/Watchpoint.cpp8
-rw-r--r--lldb/source/Commands/CommandObjectDWIMPrint.cpp63
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp6
-rw-r--r--lldb/source/Commands/CommandObjectFrame.cpp18
-rw-r--r--lldb/source/Commands/CommandObjectMemory.cpp5
-rw-r--r--lldb/source/Commands/CommandObjectStats.cpp25
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp3
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp16
-rw-r--r--lldb/source/Commands/CommandObjectThreadUtil.h1
-rw-r--r--lldb/source/Commands/Options.td24
-rw-r--r--lldb/source/Core/DumpRegisterInfo.cpp7
-rw-r--r--lldb/source/Core/DumpRegisterValue.cpp3
-rw-r--r--lldb/source/Core/FormatEntity.cpp11
-rw-r--r--lldb/source/Core/ValueObject.cpp640
-rw-r--r--lldb/source/DataFormatters/ValueObjectPrinter.cpp91
-rw-r--r--lldb/source/Expression/CMakeLists.txt1
-rw-r--r--lldb/source/Expression/ExpressionParser.cpp72
-rw-r--r--lldb/source/Host/linux/Host.cpp32
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp48
-rw-r--r--lldb/source/Interpreter/OptionArgParser.cpp14
-rw-r--r--lldb/source/Interpreter/Options.cpp21
-rw-r--r--lldb/source/Interpreter/ScriptInterpreter.cpp13
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp2
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp46
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h23
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp15
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp5
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp13
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h6
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp58
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h6
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp18
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h6
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp21
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h6
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp8
-rw-r--r--lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp684
-rw-r--r--lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h116
-rw-r--r--lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp67
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp75
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h4
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp65
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h4
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp2
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp11
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h6
-rw-r--r--lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp5
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp5
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp5
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp200
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h5
-rw-r--r--lldb/source/Plugins/REPL/Clang/ClangREPL.cpp4
-rw-r--r--lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp40
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp2
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp27
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp34
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h29
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp105
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h48
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp28
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h22
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp122
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h28
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp844
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h55
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp98
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h5
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp3
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp73
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h9
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp18
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h18
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp3
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp98
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h30
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp7
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h7
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp349
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h16
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp11
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp10
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h5
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp231
-rw-r--r--lldb/source/Symbol/DWARFCallFrameInfo.cpp3
-rw-r--r--lldb/source/Symbol/LineEntry.cpp6
-rw-r--r--lldb/source/Symbol/Type.cpp25
-rw-r--r--lldb/source/Symbol/TypeSystem.cpp11
-rw-r--r--lldb/source/Target/InstrumentationRuntime.cpp2
-rw-r--r--lldb/source/Target/Platform.cpp48
-rw-r--r--lldb/source/Target/Process.cpp127
-rw-r--r--lldb/source/Target/RegisterFlags.cpp218
-rw-r--r--lldb/source/Target/RemoteAwarePlatform.cpp138
-rw-r--r--lldb/source/Target/Statistics.cpp35
-rw-r--r--lldb/source/Target/ThreadPlanPython.cpp101
-rw-r--r--lldb/source/Utility/CMakeLists.txt1
-rw-r--r--lldb/source/Utility/ErrorMessages.cpp40
-rw-r--r--lldb/source/Utility/ProcessInfo.cpp7
-rw-r--r--lldb/source/Utility/RegularExpression.cpp5
-rw-r--r--lldb/source/Utility/Scalar.cpp4
113 files changed, 3849 insertions, 2126 deletions
diff --git a/lldb/source/API/SBAddressRange.cpp b/lldb/source/API/SBAddressRange.cpp
index 9b1affdade43..5834ebe5e63c 100644
--- a/lldb/source/API/SBAddressRange.cpp
+++ b/lldb/source/API/SBAddressRange.cpp
@@ -50,9 +50,7 @@ const SBAddressRange &SBAddressRange::operator=(const SBAddressRange &rhs) {
bool SBAddressRange::operator==(const SBAddressRange &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
- if (!IsValid() || !rhs.IsValid())
- return false;
- return m_opaque_up->operator==(*(rhs.m_opaque_up));
+ return ref().operator==(rhs.ref());
}
bool SBAddressRange::operator!=(const SBAddressRange &rhs) {
@@ -64,40 +62,35 @@ bool SBAddressRange::operator!=(const SBAddressRange &rhs) {
void SBAddressRange::Clear() {
LLDB_INSTRUMENT_VA(this);
- m_opaque_up.reset();
+ ref().Clear();
}
bool SBAddressRange::IsValid() const {
LLDB_INSTRUMENT_VA(this);
- return m_opaque_up && m_opaque_up->IsValid();
+ return ref().IsValid();
}
lldb::SBAddress SBAddressRange::GetBaseAddress() const {
LLDB_INSTRUMENT_VA(this);
- if (!IsValid())
- return lldb::SBAddress();
- return lldb::SBAddress(m_opaque_up->GetBaseAddress());
+ return lldb::SBAddress(ref().GetBaseAddress());
}
lldb::addr_t SBAddressRange::GetByteSize() const {
LLDB_INSTRUMENT_VA(this);
- if (!IsValid())
- return 0;
- return m_opaque_up->GetByteSize();
+ return ref().GetByteSize();
}
bool SBAddressRange::GetDescription(SBStream &description,
const SBTarget target) {
LLDB_INSTRUMENT_VA(this, description, target);
- Stream &stream = description.ref();
- if (!IsValid()) {
- stream << "<invalid>";
- return true;
- }
- m_opaque_up->GetDescription(&stream, target.GetSP().get());
- return true;
+ return ref().GetDescription(&description.ref(), target.GetSP().get());
+}
+
+lldb_private::AddressRange &SBAddressRange::ref() const {
+ assert(m_opaque_up && "opaque pointer must always be valid");
+ return *m_opaque_up;
}
diff --git a/lldb/source/API/SBAddressRangeList.cpp b/lldb/source/API/SBAddressRangeList.cpp
index 20660b3ff208..957155d5125e 100644
--- a/lldb/source/API/SBAddressRangeList.cpp
+++ b/lldb/source/API/SBAddressRangeList.cpp
@@ -37,40 +37,40 @@ SBAddressRangeList::operator=(const SBAddressRangeList &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
if (this != &rhs)
- *m_opaque_up = *rhs.m_opaque_up;
+ ref() = rhs.ref();
return *this;
}
uint32_t SBAddressRangeList::GetSize() const {
LLDB_INSTRUMENT_VA(this);
- return m_opaque_up->GetSize();
+ return ref().GetSize();
}
SBAddressRange SBAddressRangeList::GetAddressRangeAtIndex(uint64_t idx) {
LLDB_INSTRUMENT_VA(this, idx);
SBAddressRange sb_addr_range;
- (*sb_addr_range.m_opaque_up) = m_opaque_up->GetAddressRangeAtIndex(idx);
+ (*sb_addr_range.m_opaque_up) = ref().GetAddressRangeAtIndex(idx);
return sb_addr_range;
}
void SBAddressRangeList::Clear() {
LLDB_INSTRUMENT_VA(this);
- m_opaque_up->Clear();
+ ref().Clear();
}
void SBAddressRangeList::Append(const SBAddressRange &sb_addr_range) {
LLDB_INSTRUMENT_VA(this, sb_addr_range);
- m_opaque_up->Append(*sb_addr_range.m_opaque_up);
+ ref().Append(*sb_addr_range.m_opaque_up);
}
void SBAddressRangeList::Append(const SBAddressRangeList &sb_addr_range_list) {
LLDB_INSTRUMENT_VA(this, sb_addr_range_list);
- m_opaque_up->Append(*sb_addr_range_list.m_opaque_up);
+ ref().Append(*sb_addr_range_list.m_opaque_up);
}
bool SBAddressRangeList::GetDescription(SBStream &description,
@@ -92,3 +92,8 @@ bool SBAddressRangeList::GetDescription(SBStream &description,
stream << "]";
return true;
}
+
+lldb_private::AddressRangeListImpl &SBAddressRangeList::ref() const {
+ assert(m_opaque_up && "opaque pointer must always be valid");
+ return *m_opaque_up;
+}
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 7ef0d6efd4aa..29da7d33dd80 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -1742,3 +1742,7 @@ bool SBDebugger::InterruptRequested() {
return m_opaque_sp->InterruptRequested();
return false;
}
+
+bool SBDebugger::SupportsLanguage(lldb::LanguageType language) {
+ return TypeSystem::SupportsLanguageStatic(language);
+}
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index c37c111c5a58..efb3c8def279 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -14,6 +14,7 @@
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
+#include "lldb/Core/AddressRangeListImpl.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
@@ -26,6 +27,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/Args.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Stream.h"
@@ -320,8 +322,8 @@ void SBProcess::ReportEventState(const SBEvent &event, FileSP out) const {
if (process_sp) {
StreamFile stream(out);
const StateType event_state = SBProcess::GetStateFromEvent(event);
- stream.Printf("Process %" PRIu64 " %s\n",
- process_sp->GetID(), SBDebugger::StateAsCString(event_state));
+ stream.Printf("Process %" PRIu64 " %s\n", process_sp->GetID(),
+ SBDebugger::StateAsCString(event_state));
}
}
@@ -378,7 +380,6 @@ bool SBProcess::SetSelectedThreadByIndexID(uint32_t index_id) {
ret_val = process_sp->GetThreadList().SetSelectedThreadByIndexID(index_id);
}
-
return ret_val;
}
@@ -546,7 +547,6 @@ ByteOrder SBProcess::GetByteOrder() const {
if (process_sp)
byteOrder = process_sp->GetTarget().GetArchitecture().GetByteOrder();
-
return byteOrder;
}
@@ -558,7 +558,6 @@ uint32_t SBProcess::GetAddressByteSize() const {
if (process_sp)
size = process_sp->GetTarget().GetArchitecture().GetAddressByteSize();
-
return size;
}
@@ -810,6 +809,55 @@ const char *SBProcess::GetBroadcasterClass() {
return ConstString(Process::GetStaticBroadcasterClass()).AsCString();
}
+lldb::SBAddressRangeList SBProcess::FindRangesInMemory(
+ const void *buf, uint64_t size, const SBAddressRangeList &ranges,
+ uint32_t alignment, uint32_t max_matches, SBError &error) {
+ LLDB_INSTRUMENT_VA(this, buf, size, ranges, alignment, max_matches, error);
+
+ lldb::SBAddressRangeList matches;
+
+ ProcessSP process_sp(GetSP());
+ if (!process_sp) {
+ error.SetErrorString("SBProcess is invalid");
+ return matches;
+ }
+ Process::StopLocker stop_locker;
+ if (!stop_locker.TryLock(&process_sp->GetRunLock())) {
+ error.SetErrorString("process is running");
+ return matches;
+ }
+ std::lock_guard<std::recursive_mutex> guard(
+ process_sp->GetTarget().GetAPIMutex());
+ matches.m_opaque_up->ref() = process_sp->FindRangesInMemory(
+ reinterpret_cast<const uint8_t *>(buf), size, ranges.ref().ref(),
+ alignment, max_matches, error.ref());
+ return matches;
+}
+
+lldb::addr_t SBProcess::FindInMemory(const void *buf, uint64_t size,
+ const SBAddressRange &range,
+ uint32_t alignment, SBError &error) {
+ LLDB_INSTRUMENT_VA(this, buf, size, range, alignment, error);
+
+ ProcessSP process_sp(GetSP());
+
+ if (!process_sp) {
+ error.SetErrorString("SBProcess is invalid");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ Process::StopLocker stop_locker;
+ if (!stop_locker.TryLock(&process_sp->GetRunLock())) {
+ error.SetErrorString("process is running");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ std::lock_guard<std::recursive_mutex> guard(
+ process_sp->GetTarget().GetAPIMutex());
+ return process_sp->FindInMemory(reinterpret_cast<const uint8_t *>(buf), size,
+ range.ref(), alignment, error.ref());
+}
+
size_t SBProcess::ReadMemory(addr_t addr, void *dst, size_t dst_len,
SBError &sb_error) {
LLDB_INSTRUMENT_VA(this, addr, dst, dst_len, sb_error);
diff --git a/lldb/source/API/SBStatisticsOptions.cpp b/lldb/source/API/SBStatisticsOptions.cpp
index 7e826c4c93eb..71d4048573b5 100644
--- a/lldb/source/API/SBStatisticsOptions.cpp
+++ b/lldb/source/API/SBStatisticsOptions.cpp
@@ -18,7 +18,6 @@ using namespace lldb_private;
SBStatisticsOptions::SBStatisticsOptions()
: m_opaque_up(new StatisticsOptions()) {
LLDB_INSTRUMENT_VA(this);
- m_opaque_up->summary_only = false;
}
SBStatisticsOptions::SBStatisticsOptions(const SBStatisticsOptions &rhs) {
@@ -39,17 +38,43 @@ SBStatisticsOptions::operator=(const SBStatisticsOptions &rhs) {
}
void SBStatisticsOptions::SetSummaryOnly(bool b) {
- m_opaque_up->summary_only = b;
+ m_opaque_up->SetSummaryOnly(b);
}
-bool SBStatisticsOptions::GetSummaryOnly() { return m_opaque_up->summary_only; }
+bool SBStatisticsOptions::GetSummaryOnly() {
+ return m_opaque_up->GetSummaryOnly();
+}
+
+void SBStatisticsOptions::SetIncludeTargets(bool b) {
+ m_opaque_up->SetIncludeTargets(b);
+}
+
+bool SBStatisticsOptions::GetIncludeTargets() const {
+ return m_opaque_up->GetIncludeTargets();
+}
+
+void SBStatisticsOptions::SetIncludeModules(bool b) {
+ m_opaque_up->SetIncludeModules(b);
+}
+
+bool SBStatisticsOptions::GetIncludeModules() const {
+ return m_opaque_up->GetIncludeModules();
+}
+
+void SBStatisticsOptions::SetIncludeTranscript(bool b) {
+ m_opaque_up->SetIncludeTranscript(b);
+}
+
+bool SBStatisticsOptions::GetIncludeTranscript() const {
+ return m_opaque_up->GetIncludeTranscript();
+}
void SBStatisticsOptions::SetReportAllAvailableDebugInfo(bool b) {
- m_opaque_up->load_all_debug_info = b;
+ m_opaque_up->SetLoadAllDebugInfo(b);
}
bool SBStatisticsOptions::GetReportAllAvailableDebugInfo() {
- return m_opaque_up->load_all_debug_info;
+ return m_opaque_up->GetLoadAllDebugInfo();
}
const lldb_private::StatisticsOptions &SBStatisticsOptions::ref() const {
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index adb9e645610b..2c336296f0b8 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1789,6 +1789,11 @@ lldb::SBSymbolContextList SBTarget::FindGlobalFunctions(const char *name,
target_sp->GetImages().FindFunctions(RegularExpression(name_ref),
function_options, *sb_sc_list);
break;
+ case eMatchTypeRegexInsensitive:
+ target_sp->GetImages().FindFunctions(
+ RegularExpression(name_ref, llvm::Regex::RegexFlags::IgnoreCase),
+ function_options, *sb_sc_list);
+ break;
case eMatchTypeStartsWith:
regexstr = llvm::Regex::escape(name) + ".*";
target_sp->GetImages().FindFunctions(RegularExpression(regexstr),
@@ -1936,6 +1941,11 @@ SBValueList SBTarget::FindGlobalVariables(const char *name,
target_sp->GetImages().FindGlobalVariables(RegularExpression(name_ref),
max_matches, variable_list);
break;
+ case eMatchTypeRegexInsensitive:
+ target_sp->GetImages().FindGlobalVariables(
+ RegularExpression(name_ref, llvm::Regex::IgnoreCase), max_matches,
+ variable_list);
+ break;
case eMatchTypeStartsWith:
regexstr = "^" + llvm::Regex::escape(name) + ".*";
target_sp->GetImages().FindGlobalVariables(RegularExpression(regexstr),
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index c53ec5a74648..10a691c40341 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -379,7 +379,10 @@ const char *SBValue::GetObjectDescription() {
if (!value_sp)
return nullptr;
- return ConstString(value_sp->GetObjectDescription()).GetCString();
+ llvm::Expected<std::string> str = value_sp->GetObjectDescription();
+ if (!str)
+ return ConstString("error: " + toString(str.takeError())).AsCString();
+ return ConstString(*str).AsCString();
}
SBType SBValue::GetType() {
@@ -1233,7 +1236,10 @@ bool SBValue::GetDescription(SBStream &description) {
DumpValueObjectOptions options;
options.SetUseDynamicType(m_opaque_sp->GetUseDynamic());
options.SetUseSyntheticValue(m_opaque_sp->GetUseSynthetic());
- value_sp->Dump(strm, options);
+ if (llvm::Error error = value_sp->Dump(strm, options)) {
+ strm << "error: " << toString(std::move(error));
+ return false;
+ }
} else {
strm.PutCString("No value");
}
@@ -1281,26 +1287,8 @@ lldb::addr_t SBValue::GetLoadAddress() {
lldb::addr_t value = LLDB_INVALID_ADDRESS;
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
- if (value_sp) {
- TargetSP target_sp(value_sp->GetTargetSP());
- if (target_sp) {
- const bool scalar_is_load_address = true;
- AddressType addr_type;
- value = value_sp->GetAddressOf(scalar_is_load_address, &addr_type);
- if (addr_type == eAddressTypeFile) {
- ModuleSP module_sp(value_sp->GetModule());
- if (!module_sp)
- value = LLDB_INVALID_ADDRESS;
- else {
- Address addr;
- module_sp->ResolveFileAddress(value, addr);
- value = addr.GetLoadAddress(target_sp.get());
- }
- } else if (addr_type == eAddressTypeHost ||
- addr_type == eAddressTypeInvalid)
- value = LLDB_INVALID_ADDRESS;
- }
- }
+ if (value_sp)
+ return value_sp->GetLoadAddress();
return value;
}
diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp
index 6c6037dd9edd..1db840169811 100644
--- a/lldb/source/Breakpoint/BreakpointOptions.cpp
+++ b/lldb/source/Breakpoint/BreakpointOptions.cpp
@@ -102,19 +102,11 @@ const char *BreakpointOptions::g_option_names[(
"ConditionText", "IgnoreCount",
"EnabledState", "OneShotState", "AutoContinue"};
-bool BreakpointOptions::NullCallback(void *baton,
- StoppointCallbackContext *context,
- lldb::user_id_t break_id,
- lldb::user_id_t break_loc_id) {
- return true;
-}
-
// BreakpointOptions constructor
BreakpointOptions::BreakpointOptions(bool all_flags_set)
- : m_callback(BreakpointOptions::NullCallback),
- m_baton_is_command_baton(false), m_callback_is_synchronous(false),
- m_enabled(true), m_one_shot(false), m_ignore_count(0),
- m_condition_text_hash(0), m_inject_condition(false),
+ : m_callback(nullptr), m_baton_is_command_baton(false),
+ m_callback_is_synchronous(false), m_enabled(true), m_one_shot(false),
+ m_ignore_count(0), m_condition_text_hash(0), m_inject_condition(false),
m_auto_continue(false), m_set_flags(0) {
if (all_flags_set)
m_set_flags.Set(~((Flags::ValueType)0));
@@ -420,7 +412,7 @@ void BreakpointOptions::SetCallback(
}
void BreakpointOptions::ClearCallback() {
- m_callback = BreakpointOptions::NullCallback;
+ m_callback = nullptr;
m_callback_is_synchronous = false;
m_callback_baton_sp.reset();
m_baton_is_command_baton = false;
@@ -449,7 +441,7 @@ bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context,
}
bool BreakpointOptions::HasCallback() const {
- return m_callback != BreakpointOptions::NullCallback;
+ return static_cast<bool>(m_callback);
}
bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index edb1a0e93460..715e83c76697 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -299,7 +299,9 @@ bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
.SetHideRootType(true)
.SetHideRootName(true)
.SetHideName(true);
- m_old_value_sp->Dump(strm, options);
+ if (llvm::Error error = m_old_value_sp->Dump(strm, options))
+ strm << "error: " << toString(std::move(error));
+
if (strm.GetData())
values_ss.Printf("old value: %s", strm.GetData());
}
@@ -322,7 +324,9 @@ bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
.SetHideRootType(true)
.SetHideRootName(true)
.SetHideName(true);
- m_new_value_sp->Dump(strm, options);
+ if (llvm::Error error = m_new_value_sp->Dump(strm, options))
+ strm << "error: " << toString(std::move(error));
+
if (strm.GetData())
values_ss.Printf("new value: %s", strm.GetData());
}
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index 57a372a762e1..b7cd955e0020 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -133,13 +133,22 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
auto dump_val_object = [&](ValueObject &valobj) {
if (is_po) {
StreamString temp_result_stream;
- valobj.Dump(temp_result_stream, dump_options);
+ if (llvm::Error error = valobj.Dump(temp_result_stream, dump_options)) {
+ result.AppendError(toString(std::move(error)));
+ return;
+ }
llvm::StringRef output = temp_result_stream.GetString();
maybe_add_hint(output);
result.GetOutputStream() << output;
} else {
- valobj.Dump(result.GetOutputStream(), dump_options);
+ llvm::Error error =
+ valobj.Dump(result.GetOutputStream(), dump_options);
+ if (error) {
+ result.AppendError(toString(std::move(error)));
+ return;
+ }
}
+ result.SetStatus(eReturnStatusSuccessFinishResult);
};
// First, try `expr` as the name of a frame variable.
@@ -160,7 +169,6 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
}
dump_val_object(*valobj_sp);
- result.SetStatus(eReturnStatusSuccessFinishResult);
return;
}
}
@@ -171,7 +179,6 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
if (auto var_sp = state->GetVariable(expr))
if (auto valobj_sp = var_sp->GetValueObject()) {
dump_val_object(*valobj_sp);
- result.SetStatus(eReturnStatusSuccessFinishResult);
return;
}
@@ -192,34 +199,36 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
error_stream << " " << fixed_expression << "\n";
}
- if (expr_result == eExpressionCompleted) {
- if (verbosity != eDWIMPrintVerbosityNone) {
- StringRef flags;
- if (args.HasArgs())
- flags = args.GetArgStringWithDelimiter();
- result.AppendMessageWithFormatv("note: ran `expression {0}{1}`", flags,
- expr);
- }
-
- if (valobj_sp->GetError().GetError() != UserExpression::kNoResult)
- dump_val_object(*valobj_sp);
-
- if (suppress_result)
- if (auto result_var_sp =
- target.GetPersistentVariable(valobj_sp->GetName())) {
- auto language = valobj_sp->GetPreferredDisplayLanguage();
- if (auto *persistent_state =
- target.GetPersistentExpressionStateForLanguage(language))
- persistent_state->RemovePersistentVariable(result_var_sp);
- }
-
- result.SetStatus(eReturnStatusSuccessFinishResult);
- } else {
+ // If the expression failed, return an error.
+ if (expr_result != eExpressionCompleted) {
if (valobj_sp)
result.SetError(valobj_sp->GetError());
else
result.AppendErrorWithFormatv(
"unknown error evaluating expression `{0}`", expr);
+ return;
+ }
+
+ if (verbosity != eDWIMPrintVerbosityNone) {
+ StringRef flags;
+ if (args.HasArgs())
+ flags = args.GetArgStringWithDelimiter();
+ result.AppendMessageWithFormatv("note: ran `expression {0}{1}`", flags,
+ expr);
}
+
+ if (valobj_sp->GetError().GetError() != UserExpression::kNoResult)
+ dump_val_object(*valobj_sp);
+ else
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+
+ if (suppress_result)
+ if (auto result_var_sp =
+ target.GetPersistentVariable(valobj_sp->GetName())) {
+ auto language = valobj_sp->GetPreferredDisplayLanguage();
+ if (auto *persistent_state =
+ target.GetPersistentExpressionStateForLanguage(language))
+ persistent_state->RemovePersistentVariable(result_var_sp);
+ }
}
}
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index 2319ddd3c80a..eb76753d98ef 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -461,7 +461,11 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
options.SetVariableFormatDisplayLanguage(
result_valobj_sp->GetPreferredDisplayLanguage());
- result_valobj_sp->Dump(output_stream, options);
+ if (llvm::Error error =
+ result_valobj_sp->Dump(output_stream, options)) {
+ result.AppendError(toString(std::move(error)));
+ return false;
+ }
if (suppress_result)
if (auto result_var_sp =
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index b1d060b3c6cf..3f4178c1a959 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -170,7 +170,8 @@ protected:
assert(valobj_sp.get() && "Must have a valid ValueObject to print");
ValueObjectPrinter printer(*valobj_sp, &result.GetOutputStream(),
options);
- printer.PrintValueObject();
+ if (llvm::Error error = printer.PrintValueObject())
+ result.AppendError(toString(std::move(error)));
}
CommandOptions m_options;
@@ -555,7 +556,9 @@ protected:
show_module))
s.PutCString(": ");
}
- valobj_sp->Dump(result.GetOutputStream(), options);
+ auto &strm = result.GetOutputStream();
+ if (llvm::Error error = valobj_sp->Dump(strm, options))
+ result.AppendError(toString(std::move(error)));
}
}
} else {
@@ -597,7 +600,8 @@ protected:
Stream &output_stream = result.GetOutputStream();
options.SetRootValueObjectName(
valobj_sp->GetParent() ? entry.c_str() : nullptr);
- valobj_sp->Dump(output_stream, options);
+ if (llvm::Error error = valobj_sp->Dump(output_stream, options))
+ result.AppendError(toString(std::move(error)));
} else {
if (auto error_cstr = error.AsCString(nullptr))
result.AppendError(error_cstr);
@@ -648,7 +652,9 @@ protected:
valobj_sp->GetPreferredDisplayLanguage());
options.SetRootValueObjectName(
var_sp ? var_sp->GetName().AsCString() : nullptr);
- valobj_sp->Dump(result.GetOutputStream(), options);
+ if (llvm::Error error =
+ valobj_sp->Dump(result.GetOutputStream(), options))
+ result.AppendError(toString(std::move(error)));
}
}
}
@@ -669,7 +675,9 @@ protected:
options.SetVariableFormatDisplayLanguage(
rec_value_sp->GetPreferredDisplayLanguage());
options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
- rec_value_sp->Dump(result.GetOutputStream(), options);
+ if (llvm::Error error =
+ rec_value_sp->Dump(result.GetOutputStream(), options))
+ result.AppendError(toString(std::move(error)));
}
}
}
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
index 1c13484dede6..137b1ad98107 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -815,7 +815,10 @@ protected:
DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
eLanguageRuntimeDescriptionDisplayVerbosityFull, format));
- valobj_sp->Dump(*output_stream_p, options);
+ if (llvm::Error error = valobj_sp->Dump(*output_stream_p, options)) {
+ result.AppendError(toString(std::move(error)));
+ return;
+ }
} else {
result.AppendErrorWithFormat(
"failed to create a value object for: (%s) %s\n",
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index 1935b0fdfadf..53855e7d0316 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -11,6 +11,7 @@
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Target/Target.h"
using namespace lldb;
@@ -76,13 +77,31 @@ class CommandObjectStatsDump : public CommandObjectParsed {
m_all_targets = true;
break;
case 's':
- m_stats_options.summary_only = true;
+ m_stats_options.SetSummaryOnly(true);
break;
case 'f':
- m_stats_options.load_all_debug_info = true;
+ m_stats_options.SetLoadAllDebugInfo(true);
+ break;
+ case 'r':
+ if (llvm::Expected<bool> bool_or_error =
+ OptionArgParser::ToBoolean("--targets", option_arg))
+ m_stats_options.SetIncludeTargets(*bool_or_error);
+ else
+ error = bool_or_error.takeError();
+ break;
+ case 'm':
+ if (llvm::Expected<bool> bool_or_error =
+ OptionArgParser::ToBoolean("--modules", option_arg))
+ m_stats_options.SetIncludeModules(*bool_or_error);
+ else
+ error = bool_or_error.takeError();
break;
case 't':
- m_stats_options.include_transcript = true;
+ if (llvm::Expected<bool> bool_or_error =
+ OptionArgParser::ToBoolean("--transcript", option_arg))
+ m_stats_options.SetIncludeTranscript(*bool_or_error);
+ else
+ error = bool_or_error.takeError();
break;
default:
llvm_unreachable("Unimplemented option");
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index ae6c6d5479a1..80181a9b3cb7 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -784,7 +784,8 @@ public:
options.SetRootValueObjectName(root_name);
- valobj_sp->Dump(s, options);
+ if (llvm::Error error = valobj_sp->Dump(s, options))
+ s << "error: " << toString(std::move(error));
}
static size_t GetVariableCallback(void *baton, const char *name,
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index db96ee2cec38..5e64dd2f8f08 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -383,7 +383,7 @@ public:
eCommandProcessMustBePaused),
m_step_type(step_type), m_step_scope(step_scope),
m_class_options("scripted step") {
- AddSimpleArgumentList(eArgTypeThreadID, eArgRepeatOptional);
+ AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional);
if (step_type == eStepTypeScripted) {
m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
@@ -1386,7 +1386,10 @@ public:
Stream &strm = result.GetOutputStream();
ValueObjectSP exception_object_sp = thread_sp->GetCurrentException();
if (exception_object_sp) {
- exception_object_sp->Dump(strm);
+ if (llvm::Error error = exception_object_sp->Dump(strm)) {
+ result.AppendError(toString(std::move(error)));
+ return false;
+ }
}
ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace();
@@ -1438,9 +1441,12 @@ public:
return false;
}
ValueObjectSP exception_object_sp = thread_sp->GetSiginfoValue();
- if (exception_object_sp)
- exception_object_sp->Dump(strm);
- else
+ if (exception_object_sp) {
+ if (llvm::Error error = exception_object_sp->Dump(strm)) {
+ result.AppendError(toString(std::move(error)));
+ return false;
+ }
+ } else
strm.Printf("(no siginfo)\n");
strm.PutChar('\n');
diff --git a/lldb/source/Commands/CommandObjectThreadUtil.h b/lldb/source/Commands/CommandObjectThreadUtil.h
index 74d1136bab7f..3fc28efe8cf7 100644
--- a/lldb/source/Commands/CommandObjectThreadUtil.h
+++ b/lldb/source/Commands/CommandObjectThreadUtil.h
@@ -10,6 +10,7 @@
#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H
#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include <stack>
namespace lldb_private {
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index cee5a81d3796..ba256e5ab917 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1425,8 +1425,28 @@ let Command = "statistics dump" in {
Desc<"Dump the total possible debug info statistics. "
"Force loading all the debug information if not yet loaded, and collect "
"statistics with those.">;
+ def statistics_dump_targets: Option<"targets", "r">, Group<1>,
+ Arg<"Boolean">,
+ Desc<"Dump statistics for the targets, including breakpoints, expression "
+ "evaluations, frame variables, etc. "
+ "Defaults to true, unless the '--summary' mode is enabled, in which case "
+ "this is turned off unless specified. "
+ "If both the '--targets' and the '--modules' options are 'true', a list "
+ "of module identifiers will be added to the 'targets' section.">;
+ def statistics_dump_modules: Option<"modules", "m">, Group<1>,
+ Arg<"Boolean">,
+ Desc<"Dump statistics for the modules, including time and size of various "
+ "aspects of the module and debug information, type system, path, etc. "
+ "Defaults to true, unless the '--summary' mode is enabled, in which case "
+ "this is turned off unless specified. "
+ "If both the '--targets' and the '--modules' options are 'true', a list "
+ "of module identifiers will be added to the 'targets' section.">;
def statistics_dump_transcript: Option<"transcript", "t">, Group<1>,
+ Arg<"Boolean">,
Desc<"If the setting interpreter.save-transcript is enabled and this "
- "option is specified, include a JSON array with all commands the user and/"
- "or scripts executed during a debug session.">;
+ "option is 'true', include a JSON array with all commands the user and/or "
+ "scripts executed during a debug session. "
+ "Defaults to true, unless the '--summary' mode is enabled, in which case "
+ "this is turned off unless specified.">;
+
}
diff --git a/lldb/source/Core/DumpRegisterInfo.cpp b/lldb/source/Core/DumpRegisterInfo.cpp
index 833479541690..eccc6784cd49 100644
--- a/lldb/source/Core/DumpRegisterInfo.cpp
+++ b/lldb/source/Core/DumpRegisterInfo.cpp
@@ -111,6 +111,11 @@ void lldb_private::DoDumpRegisterInfo(
};
DumpList(strm, " In sets: ", in_sets, emit_set);
- if (flags_type)
+ if (flags_type) {
strm.Printf("\n\n%s", flags_type->AsTable(terminal_width).c_str());
+
+ std::string enumerators = flags_type->DumpEnums(terminal_width);
+ if (enumerators.size())
+ strm << "\n\n" << enumerators;
+ }
}
diff --git a/lldb/source/Core/DumpRegisterValue.cpp b/lldb/source/Core/DumpRegisterValue.cpp
index 463aa5926772..90b31fd0e865 100644
--- a/lldb/source/Core/DumpRegisterValue.cpp
+++ b/lldb/source/Core/DumpRegisterValue.cpp
@@ -54,7 +54,8 @@ static void dump_type_value(lldb_private::CompilerType &fields_type, T value,
};
dump_options.SetChildPrintingDecider(decider).SetHideRootType(true);
- vobj_sp->Dump(strm, dump_options);
+ if (llvm::Error error = vobj_sp->Dump(strm, dump_options))
+ strm << "error: " << toString(std::move(error));
}
void lldb_private::DumpRegisterValue(const RegisterValue &reg_val, Stream &s,
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 1c3a4cb1062f..fe95858f35c9 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -1401,7 +1401,10 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
ValueObjectSP return_valobj_sp =
StopInfo::GetReturnValueObject(stop_info_sp);
if (return_valobj_sp) {
- return_valobj_sp->Dump(s);
+ if (llvm::Error error = return_valobj_sp->Dump(s)) {
+ s << "error: " << toString(std::move(error));
+ return false;
+ }
return true;
}
}
@@ -1418,7 +1421,11 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
ExpressionVariableSP expression_var_sp =
StopInfo::GetExpressionVariable(stop_info_sp);
if (expression_var_sp && expression_var_sp->GetValueObject()) {
- expression_var_sp->GetValueObject()->Dump(s);
+ if (llvm::Error error =
+ expression_var_sp->GetValueObject()->Dump(s)) {
+ s << "error: " << toString(std::move(error));
+ return false;
+ }
return true;
}
}
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index f32cb82faa00..8f72efc2299b 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -989,41 +989,46 @@ ValueObject::ReadPointedString(lldb::WritableDataBufferSP &buffer_sp,
return {total_bytes_read, was_capped};
}
-const char *ValueObject::GetObjectDescription() {
+llvm::Expected<std::string> ValueObject::GetObjectDescription() {
if (!UpdateValueIfNeeded(true))
- return nullptr;
+ return llvm::createStringError("could not update value");
// Return cached value.
if (!m_object_desc_str.empty())
- return m_object_desc_str.c_str();
+ return m_object_desc_str;
ExecutionContext exe_ctx(GetExecutionContextRef());
Process *process = exe_ctx.GetProcessPtr();
if (!process)
- return nullptr;
+ return llvm::createStringError("no process");
// Returns the object description produced by one language runtime.
- auto get_object_description = [&](LanguageType language) -> const char * {
+ auto get_object_description =
+ [&](LanguageType language) -> llvm::Expected<std::string> {
if (LanguageRuntime *runtime = process->GetLanguageRuntime(language)) {
StreamString s;
- if (runtime->GetObjectDescription(s, *this)) {
- m_object_desc_str.append(std::string(s.GetString()));
- return m_object_desc_str.c_str();
- }
+ if (llvm::Error error = runtime->GetObjectDescription(s, *this))
+ return error;
+ m_object_desc_str = s.GetString();
+ return m_object_desc_str;
}
- return nullptr;
+ return llvm::createStringError("no native language runtime");
};
// Try the native language runtime first.
LanguageType native_language = GetObjectRuntimeLanguage();
- if (const char *desc = get_object_description(native_language))
+ llvm::Expected<std::string> desc = get_object_description(native_language);
+ if (desc)
return desc;
// Try the Objective-C language runtime. This fallback is necessary
// for Objective-C++ and mixed Objective-C / C++ programs.
- if (Language::LanguageIsCFamily(native_language))
+ if (Language::LanguageIsCFamily(native_language)) {
+ // We're going to try again, so let's drop the first error.
+ llvm::consumeError(desc.takeError());
return get_object_description(eLanguageTypeObjC);
- return nullptr;
+ }
+ return desc;
}
bool ValueObject::GetValueAsCString(const lldb_private::TypeFormatImpl &format,
@@ -1116,6 +1121,153 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) {
return fail_value;
}
+llvm::Expected<llvm::APSInt> ValueObject::GetValueAsAPSInt() {
+ // Make sure the type can be converted to an APSInt.
+ if (!GetCompilerType().IsInteger() &&
+ !GetCompilerType().IsScopedEnumerationType() &&
+ !GetCompilerType().IsEnumerationType() &&
+ !GetCompilerType().IsPointerType() &&
+ !GetCompilerType().IsNullPtrType() &&
+ !GetCompilerType().IsReferenceType() && !GetCompilerType().IsBoolean())
+ return llvm::make_error<llvm::StringError>(
+ "type cannot be converted to APSInt", llvm::inconvertibleErrorCode());
+
+ if (CanProvideValue()) {
+ Scalar scalar;
+ if (ResolveValue(scalar))
+ return scalar.GetAPSInt();
+ }
+
+ return llvm::make_error<llvm::StringError>(
+ "error occurred; unable to convert to APSInt",
+ llvm::inconvertibleErrorCode());
+}
+
+llvm::Expected<llvm::APFloat> ValueObject::GetValueAsAPFloat() {
+ if (!GetCompilerType().IsFloat())
+ return llvm::make_error<llvm::StringError>(
+ "type cannot be converted to APFloat", llvm::inconvertibleErrorCode());
+
+ if (CanProvideValue()) {
+ Scalar scalar;
+ if (ResolveValue(scalar))
+ return scalar.GetAPFloat();
+ }
+
+ return llvm::make_error<llvm::StringError>(
+ "error occurred; unable to convert to APFloat",
+ llvm::inconvertibleErrorCode());
+}
+
+llvm::Expected<bool> ValueObject::GetValueAsBool() {
+ CompilerType val_type = GetCompilerType();
+ if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() ||
+ val_type.IsPointerType()) {
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err)
+ return value_or_err->getBoolValue();
+ }
+ if (val_type.IsFloat()) {
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err)
+ return value_or_err->isNonZero();
+ }
+ if (val_type.IsArrayType())
+ return GetAddressOf() != 0;
+
+ return llvm::make_error<llvm::StringError>("type cannot be converted to bool",
+ llvm::inconvertibleErrorCode());
+}
+
+void ValueObject::SetValueFromInteger(const llvm::APInt &value, Status &error) {
+ // Verify the current object is an integer object
+ CompilerType val_type = GetCompilerType();
+ if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() &&
+ !val_type.IsFloat() && !val_type.IsPointerType() &&
+ !val_type.IsScalarType()) {
+ error.SetErrorString("current value object is not an integer objet");
+ return;
+ }
+
+ // Verify the current object is not actually associated with any program
+ // variable.
+ if (GetVariable()) {
+ error.SetErrorString("current value object is not a temporary object");
+ return;
+ }
+
+ // Verify the proposed new value is the right size.
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t byte_size = 0;
+ if (auto temp = GetCompilerType().GetByteSize(target.get()))
+ byte_size = temp.value();
+ if (value.getBitWidth() != byte_size * CHAR_BIT) {
+ error.SetErrorString(
+ "illegal argument: new value should be of the same size");
+ return;
+ }
+
+ lldb::DataExtractorSP data_sp;
+ data_sp->SetData(value.getRawData(), byte_size,
+ target->GetArchitecture().GetByteOrder());
+ data_sp->SetAddressByteSize(
+ static_cast<uint8_t>(target->GetArchitecture().GetAddressByteSize()));
+ SetData(*data_sp, error);
+}
+
+void ValueObject::SetValueFromInteger(lldb::ValueObjectSP new_val_sp,
+ Status &error) {
+ // Verify the current object is an integer object
+ CompilerType val_type = GetCompilerType();
+ if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() &&
+ !val_type.IsFloat() && !val_type.IsPointerType() &&
+ !val_type.IsScalarType()) {
+ error.SetErrorString("current value object is not an integer objet");
+ return;
+ }
+
+ // Verify the current object is not actually associated with any program
+ // variable.
+ if (GetVariable()) {
+ error.SetErrorString("current value object is not a temporary object");
+ return;
+ }
+
+ // Verify the proposed new value is the right type.
+ CompilerType new_val_type = new_val_sp->GetCompilerType();
+ if (!new_val_type.IsInteger() && !new_val_type.IsFloat() &&
+ !new_val_type.IsPointerType()) {
+ error.SetErrorString(
+ "illegal argument: new value should be of the same size");
+ return;
+ }
+
+ if (new_val_type.IsInteger()) {
+ auto value_or_err = new_val_sp->GetValueAsAPSInt();
+ if (value_or_err)
+ SetValueFromInteger(*value_or_err, error);
+ else
+ error.SetErrorString("error getting APSInt from new_val_sp");
+ } else if (new_val_type.IsFloat()) {
+ auto value_or_err = new_val_sp->GetValueAsAPFloat();
+ if (value_or_err)
+ SetValueFromInteger(value_or_err->bitcastToAPInt(), error);
+ else
+ error.SetErrorString("error getting APFloat from new_val_sp");
+ } else if (new_val_type.IsPointerType()) {
+ bool success = true;
+ uint64_t int_val = new_val_sp->GetValueAsUnsigned(0, &success);
+ if (success) {
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t num_bits = 0;
+ if (auto temp = new_val_sp->GetCompilerType().GetBitSize(target.get()))
+ num_bits = temp.value();
+ SetValueFromInteger(llvm::APInt(num_bits, int_val), error);
+ } else
+ error.SetErrorString("error converting new_val_sp to integer");
+ }
+}
+
// if any more "special cases" are added to
// ValueObject::DumpPrintableRepresentation() please keep this call up to date
// by returning true for your new special cases. We will eventually move to
@@ -1325,9 +1477,16 @@ bool ValueObject::DumpPrintableRepresentation(
str = GetSummaryAsCString();
break;
- case eValueObjectRepresentationStyleLanguageSpecific:
- str = GetObjectDescription();
- break;
+ case eValueObjectRepresentationStyleLanguageSpecific: {
+ llvm::Expected<std::string> desc = GetObjectDescription();
+ if (!desc) {
+ strm << "error: " << toString(desc.takeError());
+ str = strm.GetString();
+ } else {
+ strm << *desc;
+ str = strm.GetString();
+ }
+ } break;
case eValueObjectRepresentationStyleLocation:
str = GetLocationAsCString();
@@ -2566,11 +2725,14 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl(
}
}
-void ValueObject::Dump(Stream &s) { Dump(s, DumpValueObjectOptions(*this)); }
+llvm::Error ValueObject::Dump(Stream &s) {
+ return Dump(s, DumpValueObjectOptions(*this));
+}
-void ValueObject::Dump(Stream &s, const DumpValueObjectOptions &options) {
+llvm::Error ValueObject::Dump(Stream &s,
+ const DumpValueObjectOptions &options) {
ValueObjectPrinter printer(*this, &s, options);
- printer.PrintValueObject();
+ return printer.PrintValueObject();
}
ValueObjectSP ValueObject::CreateConstantValue(ConstString name) {
@@ -2843,6 +3005,374 @@ ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) {
return valobj_sp;
}
+lldb::addr_t ValueObject::GetLoadAddress() {
+ lldb::addr_t addr_value = LLDB_INVALID_ADDRESS;
+ if (auto target_sp = GetTargetSP()) {
+ const bool scalar_is_load_address = true;
+ AddressType addr_type;
+ addr_value = GetAddressOf(scalar_is_load_address, &addr_type);
+ if (addr_type == eAddressTypeFile) {
+ lldb::ModuleSP module_sp(GetModule());
+ if (!module_sp)
+ addr_value = LLDB_INVALID_ADDRESS;
+ else {
+ Address tmp_addr;
+ module_sp->ResolveFileAddress(addr_value, tmp_addr);
+ addr_value = tmp_addr.GetLoadAddress(target_sp.get());
+ }
+ } else if (addr_type == eAddressTypeHost ||
+ addr_type == eAddressTypeInvalid)
+ addr_value = LLDB_INVALID_ADDRESS;
+ }
+ return addr_value;
+}
+
+llvm::Expected<lldb::ValueObjectSP> ValueObject::CastDerivedToBaseType(
+ CompilerType type, const llvm::ArrayRef<uint32_t> &base_type_indices) {
+ // Make sure the starting type and the target type are both valid for this
+ // type of cast; otherwise return the shared pointer to the original
+ // (unchanged) ValueObject.
+ if (!type.IsPointerType() && !type.IsReferenceType())
+ return llvm::make_error<llvm::StringError>(
+ "Invalid target type: should be a pointer or a reference",
+ llvm::inconvertibleErrorCode());
+
+ CompilerType start_type = GetCompilerType();
+ if (start_type.IsReferenceType())
+ start_type = start_type.GetNonReferenceType();
+
+ auto target_record_type =
+ type.IsPointerType() ? type.GetPointeeType() : type.GetNonReferenceType();
+ auto start_record_type =
+ start_type.IsPointerType() ? start_type.GetPointeeType() : start_type;
+
+ if (!target_record_type.IsRecordType() || !start_record_type.IsRecordType())
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be record types",
+ llvm::inconvertibleErrorCode());
+
+ if (target_record_type.CompareTypes(start_record_type))
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be different",
+ llvm::inconvertibleErrorCode());
+
+ if (base_type_indices.empty())
+ return llvm::make_error<llvm::StringError>(
+ "Children sequence must be non-empty", llvm::inconvertibleErrorCode());
+
+ // Both the starting & target types are valid for the cast, and the list of
+ // base class indices is non-empty, so we can proceed with the cast.
+
+ lldb::TargetSP target = GetTargetSP();
+ // The `value` can be a pointer, but GetChildAtIndex works for pointers too.
+ lldb::ValueObjectSP inner_value = GetSP();
+
+ for (const uint32_t i : base_type_indices)
+ // Create synthetic value if needed.
+ inner_value =
+ inner_value->GetChildAtIndex(i, /*can_create_synthetic*/ true);
+
+ // At this point type of `inner_value` should be the dereferenced target
+ // type.
+ CompilerType inner_value_type = inner_value->GetCompilerType();
+ if (type.IsPointerType()) {
+ if (!inner_value_type.CompareTypes(type.GetPointeeType()))
+ return llvm::make_error<llvm::StringError>(
+ "casted value doesn't match the desired type",
+ llvm::inconvertibleErrorCode());
+
+ uintptr_t addr = inner_value->GetLoadAddress();
+ llvm::StringRef name = "";
+ ExecutionContext exe_ctx(target.get(), false);
+ return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx, type,
+ /* do deref */ false);
+ }
+
+ // At this point the target type should be a reference.
+ if (!inner_value_type.CompareTypes(type.GetNonReferenceType()))
+ return llvm::make_error<llvm::StringError>(
+ "casted value doesn't match the desired type",
+ llvm::inconvertibleErrorCode());
+
+ return lldb::ValueObjectSP(inner_value->Cast(type.GetNonReferenceType()));
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+ValueObject::CastBaseToDerivedType(CompilerType type, uint64_t offset) {
+ // Make sure the starting type and the target type are both valid for this
+ // type of cast; otherwise return the shared pointer to the original
+ // (unchanged) ValueObject.
+ if (!type.IsPointerType() && !type.IsReferenceType())
+ return llvm::make_error<llvm::StringError>(
+ "Invalid target type: should be a pointer or a reference",
+ llvm::inconvertibleErrorCode());
+
+ CompilerType start_type = GetCompilerType();
+ if (start_type.IsReferenceType())
+ start_type = start_type.GetNonReferenceType();
+
+ auto target_record_type =
+ type.IsPointerType() ? type.GetPointeeType() : type.GetNonReferenceType();
+ auto start_record_type =
+ start_type.IsPointerType() ? start_type.GetPointeeType() : start_type;
+
+ if (!target_record_type.IsRecordType() || !start_record_type.IsRecordType())
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be record types",
+ llvm::inconvertibleErrorCode());
+
+ if (target_record_type.CompareTypes(start_record_type))
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be different",
+ llvm::inconvertibleErrorCode());
+
+ CompilerType virtual_base;
+ if (target_record_type.IsVirtualBase(start_record_type, &virtual_base)) {
+ if (!virtual_base.IsValid())
+ return llvm::make_error<llvm::StringError>(
+ "virtual base should be valid", llvm::inconvertibleErrorCode());
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("cannot cast " + start_type.TypeDescription() + " to " +
+ type.TypeDescription() + " via virtual base " +
+ virtual_base.TypeDescription()),
+ llvm::inconvertibleErrorCode());
+ }
+
+ // Both the starting & target types are valid for the cast, so we can
+ // proceed with the cast.
+
+ lldb::TargetSP target = GetTargetSP();
+ auto pointer_type =
+ type.IsPointerType() ? type : type.GetNonReferenceType().GetPointerType();
+
+ uintptr_t addr =
+ type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress();
+
+ llvm::StringRef name = "";
+ ExecutionContext exe_ctx(target.get(), false);
+ lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromAddress(
+ name, addr - offset, exe_ctx, pointer_type, /* do_deref */ false);
+
+ if (type.IsPointerType())
+ return value;
+
+ // At this point the target type is a reference. Since `value` is a pointer,
+ // it has to be dereferenced.
+ Status error;
+ return value->Dereference(error);
+}
+
+lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
+ bool is_scalar = GetCompilerType().IsScalarType();
+ bool is_enum = GetCompilerType().IsEnumerationType();
+ bool is_pointer =
+ GetCompilerType().IsPointerType() || GetCompilerType().IsNullPtrType();
+ bool is_float = GetCompilerType().IsFloat();
+ bool is_integer = GetCompilerType().IsInteger();
+
+ if (!type.IsScalarType()) {
+ m_error.SetErrorString("target type must be a scalar");
+ return GetSP();
+ }
+
+ if (!is_scalar && !is_enum && !is_pointer) {
+ m_error.SetErrorString("argument must be a scalar, enum, or pointer");
+ return GetSP();
+ }
+
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t type_byte_size = 0;
+ uint64_t val_byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ type_byte_size = temp.value();
+ if (auto temp = GetCompilerType().GetByteSize(target.get()))
+ val_byte_size = temp.value();
+
+ if (is_pointer) {
+ if (!type.IsInteger() && !type.IsBoolean()) {
+ m_error.SetErrorString("target type must be an integer or boolean");
+ return GetSP();
+ }
+ if (!type.IsBoolean() && type_byte_size < val_byte_size) {
+ m_error.SetErrorString(
+ "target type cannot be smaller than the pointer type");
+ return GetSP();
+ }
+ }
+
+ if (type.IsBoolean()) {
+ if (!is_scalar || is_integer)
+ return ValueObject::CreateValueObjectFromBool(
+ target, GetValueAsUnsigned(0) != 0, "result");
+ else if (is_scalar && is_float) {
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err)
+ return ValueObject::CreateValueObjectFromBool(
+ target, !float_value_or_err->isZero(), "result");
+ else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APFloat: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ }
+ }
+
+ if (type.IsInteger()) {
+ if (!is_scalar || is_integer) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ // Get the value as APSInt and extend or truncate it to the requested
+ // size.
+ llvm::APSInt ext =
+ int_value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
+ ;
+ return GetSP();
+ }
+ } else if (is_scalar && is_float) {
+ llvm::APSInt integer(type_byte_size * CHAR_BIT, !type.IsSigned());
+ bool is_exact;
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err) {
+ llvm::APFloatBase::opStatus status =
+ float_value_or_err->convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+ // Casting floating point values that are out of bounds of the target
+ // type is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ m_error.SetErrorStringWithFormat(
+ "invalid type cast detected: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+ "result");
+ }
+ }
+ }
+
+ if (type.IsFloat()) {
+ if (!is_scalar) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ llvm::APSInt ext =
+ int_value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
+ Scalar scalar_int(ext);
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ } else {
+ if (is_integer) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ Scalar scalar_int(*int_value_or_err);
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ }
+ if (is_float) {
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err) {
+ Scalar scalar_float(*float_value_or_err);
+ llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APFloat: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ }
+ }
+ }
+
+ m_error.SetErrorString("Unable to perform requested cast");
+ return GetSP();
+}
+
+lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) {
+ bool is_enum = GetCompilerType().IsEnumerationType();
+ bool is_integer = GetCompilerType().IsInteger();
+ bool is_float = GetCompilerType().IsFloat();
+
+ if (!is_enum && !is_integer && !is_float) {
+ m_error.SetErrorString("argument must be an integer, a float, or an enum");
+ return GetSP();
+ }
+
+ if (!type.IsEnumerationType()) {
+ m_error.SetErrorString("target type must be an enum");
+ return GetSP();
+ }
+
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+
+ if (is_float) {
+ llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
+ bool is_exact;
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err) {
+ llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+ // Casting floating point values that are out of bounds of the target
+ // type is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ m_error.SetErrorStringWithFormat(
+ "invalid type cast detected: %s",
+ llvm::toString(value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+ "result");
+ } else {
+ m_error.SetErrorString("cannot get value as APFloat");
+ return GetSP();
+ }
+ } else {
+ // Get the value as APSInt and extend or truncate it to the requested size.
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err) {
+ llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ }
+ m_error.SetErrorString("Cannot perform requested cast");
+ return GetSP();
+}
+
ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {}
ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope,
@@ -3028,9 +3558,11 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression(
lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
- CompilerType type) {
+ CompilerType type, bool do_deref) {
if (type) {
CompilerType pointer_type(type.GetPointerType());
+ if (!do_deref)
+ pointer_type = type;
if (pointer_type) {
lldb::DataBufferSP buffer(
new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t)));
@@ -3039,10 +3571,12 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
ConstString(name), buffer, exe_ctx.GetByteOrder(),
exe_ctx.GetAddressByteSize()));
if (ptr_result_valobj_sp) {
- ptr_result_valobj_sp->GetValue().SetValueType(
- Value::ValueType::LoadAddress);
+ if (do_deref)
+ ptr_result_valobj_sp->GetValue().SetValueType(
+ Value::ValueType::LoadAddress);
Status err;
- ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
+ if (do_deref)
+ ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
if (ptr_result_valobj_sp && !name.empty())
ptr_result_valobj_sp->SetName(ConstString(name));
}
@@ -3065,6 +3599,66 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
return new_value_sp;
}
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromAPInt(lldb::TargetSP target,
+ const llvm::APInt &v, CompilerType type,
+ llvm::StringRef name) {
+ ExecutionContext exe_ctx(target.get(), false);
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ reinterpret_cast<const void *>(v.getRawData()), byte_size,
+ exe_ctx.GetByteOrder(), exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
+ lldb::TargetSP target, const llvm::APFloat &v, CompilerType type,
+ llvm::StringRef name) {
+ return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type, name);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value,
+ llvm::StringRef name) {
+ CompilerType target_type;
+ if (target) {
+ for (auto type_system_sp : target->GetScratchTypeSystems())
+ if (auto compiler_type =
+ type_system_sp->GetBasicTypeFromAST(lldb::eBasicTypeBool)) {
+ target_type = compiler_type;
+ break;
+ }
+ }
+ ExecutionContext exe_ctx(target.get(), false);
+ uint64_t byte_size = 0;
+ if (auto temp = target_type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ reinterpret_cast<const void *>(&value), byte_size, exe_ctx.GetByteOrder(),
+ exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx,
+ target_type);
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromNullptr(
+ lldb::TargetSP target, CompilerType type, llvm::StringRef name) {
+ if (!type.IsNullPtrType()) {
+ lldb::ValueObjectSP ret_val;
+ return ret_val;
+ }
+ uintptr_t zero = 0;
+ ExecutionContext exe_ctx(target.get(), false);
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ reinterpret_cast<const void *>(zero), byte_size, exe_ctx.GetByteOrder(),
+ exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
+}
+
ModuleSP ValueObject::GetModule() {
ValueObject *root(GetRoot());
if (root != this)
diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
index c2933d857458..ce24a7866e53 100644
--- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
@@ -69,15 +69,13 @@ void ValueObjectPrinter::Init(
SetupMostSpecializedValue();
}
-bool ValueObjectPrinter::PrintValueObject() {
+llvm::Error ValueObjectPrinter::PrintValueObject() {
// If the incoming ValueObject is in an error state, the best we're going to
// get out of it is its type. But if we don't even have that, just print
// the error and exit early.
if (m_orig_valobj.GetError().Fail() &&
- !m_orig_valobj.GetCompilerType().IsValid()) {
- m_stream->Printf("Error: '%s'", m_orig_valobj.GetError().AsCString());
- return true;
- }
+ !m_orig_valobj.GetCompilerType().IsValid())
+ return m_orig_valobj.GetError().ToError();
if (ShouldPrintValueObject()) {
PrintLocationIfNeeded();
@@ -93,11 +91,10 @@ bool ValueObjectPrinter::PrintValueObject() {
PrintValueAndSummaryIfNeeded(value_printed, summary_printed);
if (m_val_summary_ok)
- PrintChildrenIfNeeded(value_printed, summary_printed);
- else
- m_stream->EOL();
+ return PrintChildrenIfNeeded(value_printed, summary_printed);
+ m_stream->EOL();
- return true;
+ return llvm::Error::success();
}
ValueObject &ValueObjectPrinter::GetMostSpecializedValue() {
@@ -147,13 +144,21 @@ void ValueObjectPrinter::SetupMostSpecializedValue() {
"SetupMostSpecialized value must compute a valid ValueObject");
}
-const char *ValueObjectPrinter::GetDescriptionForDisplay() {
+llvm::Expected<std::string> ValueObjectPrinter::GetDescriptionForDisplay() {
ValueObject &valobj = GetMostSpecializedValue();
- const char *str = valobj.GetObjectDescription();
+ llvm::Expected<std::string> maybe_str = valobj.GetObjectDescription();
+ if (maybe_str)
+ return maybe_str;
+
+ const char *str = nullptr;
if (!str)
str = valobj.GetSummaryAsCString();
if (!str)
str = valobj.GetValueAsCString();
+
+ if (!str)
+ return maybe_str;
+ llvm::consumeError(maybe_str.takeError());
return str;
}
@@ -463,34 +468,38 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,
return !error_printed;
}
-bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
- bool summary_printed) {
+llvm::Error
+ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
+ bool summary_printed) {
if (ShouldPrintValueObject()) {
// let's avoid the overly verbose no description error for a nil thing
if (m_options.m_use_objc && !IsNil() && !IsUninitialized() &&
(!m_options.m_pointer_as_array)) {
if (!m_options.m_hide_value || ShouldShowName())
- m_stream->Printf(" ");
- const char *object_desc = nullptr;
- if (value_printed || summary_printed)
- object_desc = GetMostSpecializedValue().GetObjectDescription();
- else
- object_desc = GetDescriptionForDisplay();
- if (object_desc && *object_desc) {
+ *m_stream << ' ';
+ llvm::Expected<std::string> object_desc =
+ (value_printed || summary_printed)
+ ? GetMostSpecializedValue().GetObjectDescription()
+ : GetDescriptionForDisplay();
+ if (!object_desc) {
+ // If no value or summary was printed, surface the error.
+ if (!value_printed && !summary_printed)
+ return object_desc.takeError();
+ // Otherwise gently nudge the user that they should have used
+ // `p` instead of `po`. Unfortunately we cannot be more direct
+ // about this, because we don't actually know what the user did.
+ *m_stream << "warning: no object description available\n";
+ llvm::consumeError(object_desc.takeError());
+ } else {
+ *m_stream << *object_desc;
// If the description already ends with a \n don't add another one.
- size_t object_end = strlen(object_desc) - 1;
- if (object_desc[object_end] == '\n')
- m_stream->Printf("%s", object_desc);
- else
- m_stream->Printf("%s\n", object_desc);
- return true;
- } else if (!value_printed && !summary_printed)
- return true;
- else
- return false;
+ if (object_desc->empty() || object_desc->back() != '\n')
+ *m_stream << '\n';
+ }
+ return llvm::Error::success();
}
}
- return true;
+ return llvm::Error::success();
}
bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {
@@ -619,7 +628,13 @@ void ValueObjectPrinter::PrintChild(
ValueObjectPrinter child_printer(*(child_sp.get()), m_stream, child_options,
ptr_depth, m_curr_depth + 1,
m_printed_instance_pointers);
- child_printer.PrintValueObject();
+ llvm::Error error = child_printer.PrintValueObject();
+ if (error) {
+ if (m_stream)
+ *m_stream << "error: " << toString(std::move(error));
+ else
+ llvm::consumeError(std::move(error));
+ }
}
}
@@ -808,9 +823,12 @@ bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
return true;
}
-void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
- bool summary_printed) {
- PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
+llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
+ bool summary_printed) {
+ auto error = PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
+ if (error)
+ return error;
+
ValueObject &valobj = GetMostSpecializedValue();
DumpValueObjectOptions::PointerDepth curr_ptr_depth = m_ptr_depth;
@@ -826,7 +844,7 @@ void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
if (m_printed_instance_pointers->count(instance_ptr_value)) {
// We already printed this instance-is-pointer thing, so don't expand it.
m_stream->PutCString(" {...}\n");
- return;
+ return llvm::Error::success();
} else {
// Remember this guy for future reference.
m_printed_instance_pointers->emplace(instance_ptr_value);
@@ -854,6 +872,7 @@ void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
.SetReachedMaximumDepth();
} else
m_stream->EOL();
+ return llvm::Error::success();
}
bool ValueObjectPrinter::HasReachedMaximumDepth() {
diff --git a/lldb/source/Expression/CMakeLists.txt b/lldb/source/Expression/CMakeLists.txt
index 9ba5fefc09b6..be1e132f7aaa 100644
--- a/lldb/source/Expression/CMakeLists.txt
+++ b/lldb/source/Expression/CMakeLists.txt
@@ -3,6 +3,7 @@ add_lldb_library(lldbExpression NO_PLUGIN_DEPENDENCIES
DWARFExpression.cpp
DWARFExpressionList.cpp
Expression.cpp
+ ExpressionParser.cpp
ExpressionTypeSystemHelper.cpp
ExpressionVariable.cpp
FunctionCaller.cpp
diff --git a/lldb/source/Expression/ExpressionParser.cpp b/lldb/source/Expression/ExpressionParser.cpp
new file mode 100644
index 000000000000..e9f7121c2499
--- /dev/null
+++ b/lldb/source/Expression/ExpressionParser.cpp
@@ -0,0 +1,72 @@
+//===-- ExpressionParser.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/Expression/ExpressionParser.h"
+#include "lldb/Expression/DiagnosticManager.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Status ExpressionParser::PrepareForExecution(
+ addr_t &func_addr, addr_t &func_end,
+ std::shared_ptr<IRExecutionUnit> &execution_unit_sp,
+ ExecutionContext &exe_ctx, bool &can_interpret,
+ ExecutionPolicy execution_policy) {
+ Status status =
+ DoPrepareForExecution(func_addr, func_end, execution_unit_sp, exe_ctx,
+ can_interpret, execution_policy);
+ if (status.Success() && exe_ctx.GetProcessPtr() && exe_ctx.HasThreadScope())
+ status = RunStaticInitializers(execution_unit_sp, exe_ctx);
+
+ return status;
+}
+
+Status
+ExpressionParser::RunStaticInitializers(IRExecutionUnitSP &execution_unit_sp,
+ ExecutionContext &exe_ctx) {
+ Status err;
+
+ if (!execution_unit_sp.get()) {
+ err.SetErrorString(
+ "can't run static initializers for a NULL execution unit");
+ return err;
+ }
+
+ if (!exe_ctx.HasThreadScope()) {
+ err.SetErrorString("can't run static initializers without a thread");
+ return err;
+ }
+
+ std::vector<addr_t> static_initializers;
+
+ execution_unit_sp->GetStaticInitializers(static_initializers);
+
+ for (addr_t static_initializer : static_initializers) {
+ EvaluateExpressionOptions options;
+
+ ThreadPlanSP call_static_initializer(new ThreadPlanCallFunction(
+ exe_ctx.GetThreadRef(), Address(static_initializer), CompilerType(),
+ llvm::ArrayRef<addr_t>(), options));
+
+ DiagnosticManager execution_errors;
+ ExpressionResults results =
+ exe_ctx.GetThreadRef().GetProcess()->RunThreadPlan(
+ exe_ctx, call_static_initializer, options, execution_errors);
+
+ if (results != eExpressionCompleted) {
+ err.SetErrorStringWithFormat("couldn't run static initializer: %s",
+ execution_errors.GetString().c_str());
+ return err;
+ }
+ }
+
+ return err;
+}
diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp
index c6490f2fc9e2..5545f9ef4d70 100644
--- a/lldb/source/Host/linux/Host.cpp
+++ b/lldb/source/Host/linux/Host.cpp
@@ -37,6 +37,7 @@ using namespace lldb;
using namespace lldb_private;
namespace {
+
enum class ProcessState {
Unknown,
Dead,
@@ -70,6 +71,12 @@ struct StatFields {
long unsigned stime;
long cutime;
long cstime;
+ // In proc_pid_stat(5) this field is specified as priority
+ // but documented as realtime priority. To keep with the adopted
+ // nomenclature in ProcessInstanceInfo, we adopt the documented
+ // naming here.
+ long realtime_priority;
+ long priority;
// .... other things. We don't need them below
};
}
@@ -91,14 +98,16 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
if (Rest.empty())
return false;
StatFields stat_fields;
- if (sscanf(Rest.data(),
- "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld",
- &stat_fields.pid, stat_fields.comm, &stat_fields.state,
- &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
- &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
- &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
- &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
- &stat_fields.cutime, &stat_fields.cstime) < 0) {
+ if (sscanf(
+ Rest.data(),
+ "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld",
+ &stat_fields.pid, stat_fields.comm, &stat_fields.state,
+ &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
+ &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
+ &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
+ &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
+ &stat_fields.cutime, &stat_fields.cstime,
+ &stat_fields.realtime_priority, &stat_fields.priority) < 0) {
return false;
}
@@ -115,6 +124,11 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
return ts;
};
+ // Priority (nice) values run from 19 to -20 inclusive (in linux). In the
+ // prpsinfo struct pr_nice is a char.
+ auto priority_value = static_cast<int8_t>(
+ (stat_fields.priority < 0 ? 0x80 : 0x00) | (stat_fields.priority & 0x7f));
+
ProcessInfo.SetParentProcessID(stat_fields.ppid);
ProcessInfo.SetProcessGroupID(stat_fields.pgrp);
ProcessInfo.SetProcessSessionID(stat_fields.session);
@@ -122,6 +136,7 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
ProcessInfo.SetSystemTime(convert(stat_fields.stime));
ProcessInfo.SetCumulativeUserTime(convert(stat_fields.cutime));
ProcessInfo.SetCumulativeSystemTime(convert(stat_fields.cstime));
+ ProcessInfo.SetPriorityValue(priority_value);
switch (stat_fields.state) {
case 'R':
State = ProcessState::Running;
@@ -156,6 +171,7 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
State = ProcessState::Unknown;
break;
}
+ ProcessInfo.SetIsZombie(State == ProcessState::Zombie);
if (State == ProcessState::Unknown) {
LLDB_LOG(log, "Unknown process state {0}", stat_fields.state);
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index da995de1407c..40c915b2c94f 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -48,6 +48,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/StreamFile.h"
+#include "lldb/Utility/ErrorMessages.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/State.h"
@@ -1817,51 +1818,8 @@ CommandInterpreter::PreprocessToken(std::string &expr_str) {
error = expr_result_valobj_sp->GetError();
if (error.Success()) {
- switch (expr_result) {
- case eExpressionSetupError:
- error.SetErrorStringWithFormat(
- "expression setup error for the expression '%s'", expr_str.c_str());
- break;
- case eExpressionParseError:
- error.SetErrorStringWithFormat(
- "expression parse error for the expression '%s'", expr_str.c_str());
- break;
- case eExpressionResultUnavailable:
- error.SetErrorStringWithFormat(
- "expression error fetching result for the expression '%s'",
- expr_str.c_str());
- break;
- case eExpressionCompleted:
- break;
- case eExpressionDiscarded:
- error.SetErrorStringWithFormat(
- "expression discarded for the expression '%s'", expr_str.c_str());
- break;
- case eExpressionInterrupted:
- error.SetErrorStringWithFormat(
- "expression interrupted for the expression '%s'", expr_str.c_str());
- break;
- case eExpressionHitBreakpoint:
- error.SetErrorStringWithFormat(
- "expression hit breakpoint for the expression '%s'",
- expr_str.c_str());
- break;
- case eExpressionTimedOut:
- error.SetErrorStringWithFormat(
- "expression timed out for the expression '%s'", expr_str.c_str());
- break;
- case eExpressionStoppedForDebug:
- error.SetErrorStringWithFormat("expression stop at entry point "
- "for debugging for the "
- "expression '%s'",
- expr_str.c_str());
- break;
- case eExpressionThreadVanished:
- error.SetErrorStringWithFormat(
- "expression thread vanished for the expression '%s'",
- expr_str.c_str());
- break;
- }
+ std::string result = lldb_private::toString(expr_result);
+ error.SetErrorString(result + "for the expression '" + expr_str + "'");
}
return error;
}
diff --git a/lldb/source/Interpreter/OptionArgParser.cpp b/lldb/source/Interpreter/OptionArgParser.cpp
index 9a8275128ede..105d4846da14 100644
--- a/lldb/source/Interpreter/OptionArgParser.cpp
+++ b/lldb/source/Interpreter/OptionArgParser.cpp
@@ -35,6 +35,20 @@ bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value,
return fail_value;
}
+llvm::Expected<bool> OptionArgParser::ToBoolean(llvm::StringRef option_name,
+ llvm::StringRef option_arg) {
+ bool parse_success;
+ const bool option_value =
+ ToBoolean(option_arg, false /* doesn't matter */, &parse_success);
+ if (parse_success)
+ return option_value;
+ else
+ return llvm::createStringError(
+ "Invalid boolean value for option '%s': '%s'",
+ option_name.str().c_str(),
+ option_arg.empty() ? "<null>" : option_arg.str().c_str());
+}
+
char OptionArgParser::ToChar(llvm::StringRef s, char fail_value,
bool *success_ptr) {
if (success_ptr)
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index 4e7d074ace1b..c5e75e0b9dce 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -1197,21 +1197,12 @@ OptionElementVector Options::ParseForCompletion(const Args &args,
}
break;
case OptionParser::eOptionalArgument:
- if (OptionParser::GetOptionArgument() != nullptr) {
- option_element_vector.push_back(OptionArgElement(
- opt_defs_index,
- FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
- args),
- FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
- args)));
- } else {
- option_element_vector.push_back(OptionArgElement(
- opt_defs_index,
- FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
- args),
- FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
- args)));
- }
+ option_element_vector.push_back(OptionArgElement(
+ opt_defs_index,
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
+ args),
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
+ args)));
break;
default:
// The options table is messed up. Here we'll just continue
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 8dd499ce819a..75b2a39a8d11 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -101,6 +101,19 @@ ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
return Status();
}
+Event *
+ScriptInterpreter::GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const {
+ return event.m_opaque_ptr;
+}
+
+Stream *ScriptInterpreter::GetOpaqueTypeFromSBStream(
+ const lldb::SBStream &stream) const {
+ if (stream.m_opaque_up)
+ return const_cast<lldb::SBStream &>(stream).m_opaque_up.get();
+
+ return nullptr;
+}
+
std::optional<MemoryRegionInfo>
ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
const lldb::SBMemoryRegionInfo &mem_region) const {
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 82a7a2cc3f1e..1fdd272dcbec 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -637,7 +637,7 @@ void ClangASTSource::FindExternalVisibleDecls(
FindDeclInModules(context, name);
}
- if (!context.m_found_type) {
+ if (!context.m_found_type && m_ast_context->getLangOpts().ObjC) {
FindDeclInObjCRuntime(context, name);
}
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 1dd98567f8d6..303e88feea20 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -1296,7 +1296,7 @@ static bool FindFunctionInModule(ConstString &mangled_name,
return false;
}
-lldb_private::Status ClangExpressionParser::PrepareForExecution(
+lldb_private::Status ClangExpressionParser::DoPrepareForExecution(
lldb::addr_t &func_addr, lldb::addr_t &func_end,
lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx,
bool &can_interpret, ExecutionPolicy execution_policy) {
@@ -1472,47 +1472,3 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution(
return err;
}
-
-lldb_private::Status ClangExpressionParser::RunStaticInitializers(
- lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx) {
- lldb_private::Status err;
-
- lldbassert(execution_unit_sp.get());
- lldbassert(exe_ctx.HasThreadScope());
-
- if (!execution_unit_sp.get()) {
- err.SetErrorString(
- "can't run static initializers for a NULL execution unit");
- return err;
- }
-
- if (!exe_ctx.HasThreadScope()) {
- err.SetErrorString("can't run static initializers without a thread");
- return err;
- }
-
- std::vector<lldb::addr_t> static_initializers;
-
- execution_unit_sp->GetStaticInitializers(static_initializers);
-
- for (lldb::addr_t static_initializer : static_initializers) {
- EvaluateExpressionOptions options;
-
- lldb::ThreadPlanSP call_static_initializer(new ThreadPlanCallFunction(
- exe_ctx.GetThreadRef(), Address(static_initializer), CompilerType(),
- llvm::ArrayRef<lldb::addr_t>(), options));
-
- DiagnosticManager execution_errors;
- lldb::ExpressionResults results =
- exe_ctx.GetThreadRef().GetProcess()->RunThreadPlan(
- exe_ctx, call_static_initializer, options, execution_errors);
-
- if (results != lldb::eExpressionCompleted) {
- err.SetErrorStringWithFormat("couldn't run static initializer: %s",
- execution_errors.GetString().c_str());
- return err;
- }
- }
-
- return err;
-}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
index 185a5a381f23..0852e928a9d4 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -113,24 +113,11 @@ public:
/// \return
/// An error code indicating the success or failure of the operation.
/// Test with Success().
- Status
- PrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end,
- lldb::IRExecutionUnitSP &execution_unit_sp,
- ExecutionContext &exe_ctx, bool &can_interpret,
- lldb_private::ExecutionPolicy execution_policy) override;
-
- /// Run all static initializers for an execution unit.
- ///
- /// \param[in] execution_unit_sp
- /// The execution unit.
- ///
- /// \param[in] exe_ctx
- /// The execution context to use when running them. Thread can't be null.
- ///
- /// \return
- /// The error code indicating the
- Status RunStaticInitializers(lldb::IRExecutionUnitSP &execution_unit_sp,
- ExecutionContext &exe_ctx);
+ Status DoPrepareForExecution(
+ lldb::addr_t &func_addr, lldb::addr_t &func_end,
+ lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx,
+ bool &can_interpret,
+ lldb_private::ExecutionPolicy execution_policy) override;
/// Returns a string representing current ABI.
///
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index c7e98d12590d..35038a56440d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -698,21 +698,6 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
if (!parse_success)
return false;
- if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) {
- Status static_init_error =
- m_parser->RunStaticInitializers(m_execution_unit_sp, exe_ctx);
-
- if (!static_init_error.Success()) {
- const char *error_cstr = static_init_error.AsCString();
- if (error_cstr && error_cstr[0])
- diagnostic_manager.Printf(lldb::eSeverityError, "%s\n", error_cstr);
- else
- diagnostic_manager.PutString(lldb::eSeverityError,
- "couldn't run static initializers\n");
- return false;
- }
- }
-
if (m_execution_unit_sp) {
bool register_execution_unit = false;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index b0e6fb7d6f5a..0f9f93b727ce 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -808,6 +808,9 @@ ExtractLibcxxStringInfo(ValueObject &valobj) {
size = (layout == StringLayout::DSC) ? size_mode_value
: ((size_mode_value >> 1) % 256);
+ if (!location_sp)
+ return {};
+
// When the small-string optimization takes place, the data must fit in the
// inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's
// likely that the string isn't initialized and we're reading garbage.
@@ -815,7 +818,7 @@ ExtractLibcxxStringInfo(ValueObject &valobj) {
const std::optional<uint64_t> max_bytes =
location_sp->GetCompilerType().GetByteSize(
exe_ctx.GetBestExecutionContextScope());
- if (!max_bytes || size > *max_bytes || !location_sp)
+ if (!max_bytes || size > *max_bytes)
return {};
return std::make_pair(size, location_sp);
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
index 300ecc8e8ed5..c7202a47d015 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
@@ -47,16 +47,17 @@ bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
return name == g_this || name == g_promise || name == g_coro_frame;
}
-bool CPPLanguageRuntime::GetObjectDescription(Stream &str,
- ValueObject &object) {
+llvm::Error CPPLanguageRuntime::GetObjectDescription(Stream &str,
+ ValueObject &object) {
// C++ has no generic way to do this.
- return false;
+ return llvm::createStringError("C++ does not support object descriptions");
}
-bool CPPLanguageRuntime::GetObjectDescription(
- Stream &str, Value &value, ExecutionContextScope *exe_scope) {
+llvm::Error
+CPPLanguageRuntime::GetObjectDescription(Stream &str, Value &value,
+ ExecutionContextScope *exe_scope) {
// C++ has no generic way to do this.
- return false;
+ return llvm::createStringError("C++ does not support object descriptions");
}
bool contains_lambda_identifier(llvm::StringRef &str_ref) {
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h
index 1be58b7bf9ea..57cfe2824580 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h
@@ -59,10 +59,10 @@ public:
process.GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus));
}
- bool GetObjectDescription(Stream &str, ValueObject &object) override;
+ llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override;
- bool GetObjectDescription(Stream &str, Value &value,
- ExecutionContextScope *exe_scope) override;
+ llvm::Error GetObjectDescription(Stream &str, Value &value,
+ ExecutionContextScope *exe_scope) override;
/// Obtain a ThreadPlan to get us into C++ constructs such as std::function.
///
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
index 9434376f7d9e..5ff267720629 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -31,6 +31,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/ErrorMessages.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Scalar.h"
@@ -67,20 +68,21 @@ void AppleObjCRuntime::Terminate() {
AppleObjCRuntimeV1::Terminate();
}
-bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) {
+llvm::Error AppleObjCRuntime::GetObjectDescription(Stream &str,
+ ValueObject &valobj) {
CompilerType compiler_type(valobj.GetCompilerType());
bool is_signed;
// ObjC objects can only be pointers (or numbers that actually represents
// pointers but haven't been typecast, because reasons..)
if (!compiler_type.IsIntegerType(is_signed) && !compiler_type.IsPointerType())
- return false;
+ return llvm::createStringError("not a pointer type");
// Make the argument list: we pass one arg, the address of our pointer, to
// the print function.
Value val;
if (!valobj.ResolveValue(val.GetScalar()))
- return false;
+ return llvm::createStringError("pointer value could not be resolved");
// Value Objects may not have a process in their ExecutionContextRef. But we
// need to have one in the ref we pass down to eventually call description.
@@ -91,20 +93,22 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) {
} else {
exe_ctx.SetContext(valobj.GetTargetSP(), true);
if (!exe_ctx.HasProcessScope())
- return false;
+ return llvm::createStringError("no process");
}
return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope());
}
-bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
- ExecutionContextScope *exe_scope) {
+
+llvm::Error
+AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
+ ExecutionContextScope *exe_scope) {
if (!m_read_objc_library)
- return false;
+ return llvm::createStringError("Objective-C runtime not loaded");
ExecutionContext exe_ctx;
exe_scope->CalculateExecutionContext(exe_ctx);
Process *process = exe_ctx.GetProcessPtr();
if (!process)
- return false;
+ return llvm::createStringError("no process");
// We need other parts of the exe_ctx, but the processes have to match.
assert(m_process == process);
@@ -112,25 +116,25 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
// Get the function address for the print function.
const Address *function_address = GetPrintForDebuggerAddr();
if (!function_address)
- return false;
+ return llvm::createStringError("no print function");
Target *target = exe_ctx.GetTargetPtr();
CompilerType compiler_type = value.GetCompilerType();
if (compiler_type) {
- if (!TypeSystemClang::IsObjCObjectPointerType(compiler_type)) {
- strm.Printf("Value doesn't point to an ObjC object.\n");
- return false;
- }
+ if (!TypeSystemClang::IsObjCObjectPointerType(compiler_type))
+ return llvm::createStringError(
+ "Value doesn't point to an ObjC object.\n");
} else {
// If it is not a pointer, see if we can make it into a pointer.
TypeSystemClangSP scratch_ts_sp =
ScratchTypeSystemClang::GetForTarget(*target);
if (!scratch_ts_sp)
- return false;
+ return llvm::createStringError("no scratch type system");
CompilerType opaque_type = scratch_ts_sp->GetBasicType(eBasicTypeObjCID);
if (!opaque_type)
- opaque_type = scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
+ opaque_type =
+ scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
// value.SetContext(Value::eContextTypeClangType, opaque_type_ptr);
value.SetCompilerType(opaque_type);
}
@@ -142,14 +146,14 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
TypeSystemClangSP scratch_ts_sp =
ScratchTypeSystemClang::GetForTarget(*target);
if (!scratch_ts_sp)
- return false;
+ return llvm::createStringError("no scratch type system");
CompilerType return_compiler_type = scratch_ts_sp->GetCStringType(true);
Value ret;
// ret.SetContext(Value::eContextTypeClangType, return_compiler_type);
ret.SetCompilerType(return_compiler_type);
- if (exe_ctx.GetFramePtr() == nullptr) {
+ if (!exe_ctx.GetFramePtr()) {
Thread *thread = exe_ctx.GetThreadPtr();
if (thread == nullptr) {
exe_ctx.SetThreadSP(process->GetThreadList().GetSelectedThread());
@@ -173,10 +177,11 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
arg_value_list, "objc-object-description", error));
if (error.Fail()) {
m_print_object_caller_up.reset();
- strm.Printf("Could not get function runner to call print for debugger "
- "function: %s.",
- error.AsCString());
- return false;
+ return llvm::createStringError(
+ llvm::Twine(
+ "could not get function runner to call print for debugger "
+ "function: ") +
+ error.AsCString());
}
m_print_object_caller_up->InsertFunction(exe_ctx, wrapper_struct_addr,
diagnostics);
@@ -195,10 +200,9 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
ExpressionResults results = m_print_object_caller_up->ExecuteFunction(
exe_ctx, &wrapper_struct_addr, options, diagnostics, ret);
- if (results != eExpressionCompleted) {
- strm.Printf("Error evaluating Print Object function: %d.\n", results);
- return false;
- }
+ if (results != eExpressionCompleted)
+ return llvm::createStringError(
+ "could not evaluate print object function: " + toString(results));
addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
@@ -213,7 +217,9 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
strm.Write(buf, curr_len);
cstr_len += curr_len;
}
- return cstr_len > 0;
+ if (cstr_len > 0)
+ return llvm::Error::success();
+ return llvm::createStringError("empty object description");
}
lldb::ModuleSP AppleObjCRuntime::GetObjCModule() {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
index cfeec3d679be..da58d44db19a 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
@@ -44,10 +44,10 @@ public:
}
// These are generic runtime functions:
- bool GetObjectDescription(Stream &str, Value &value,
- ExecutionContextScope *exe_scope) override;
+ llvm::Error GetObjectDescription(Stream &str, Value &value,
+ ExecutionContextScope *exe_scope) override;
- bool GetObjectDescription(Stream &str, ValueObject &object) override;
+ llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override;
bool CouldHaveDynamicValue(ValueObject &in_value) override;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
index 39b3e816f4be..58b838752be5 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
@@ -104,15 +104,17 @@ GNUstepObjCRuntime::GNUstepObjCRuntime(Process *process)
ReadObjCLibraryIfNeeded(process->GetTarget().GetImages());
}
-bool GNUstepObjCRuntime::GetObjectDescription(Stream &str,
- ValueObject &valobj) {
- // TODO: ObjC has a generic way to do this
- return false;
+llvm::Error GNUstepObjCRuntime::GetObjectDescription(Stream &str,
+ ValueObject &valobj) {
+ return llvm::createStringError(
+ "LLDB's GNUStep runtime does not support object description");
}
-bool GNUstepObjCRuntime::GetObjectDescription(
- Stream &strm, Value &value, ExecutionContextScope *exe_scope) {
- // TODO: ObjC has a generic way to do this
- return false;
+
+llvm::Error
+GNUstepObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
+ ExecutionContextScope *exe_scope) {
+ return llvm::createStringError(
+ "LLDB's GNUStep runtime does not support object description");
}
bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
index b22088807f97..de24466ebb00 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
@@ -57,10 +57,10 @@ public:
//
// LanguageRuntime implementation
//
- bool GetObjectDescription(Stream &str, Value &value,
- ExecutionContextScope *exe_scope) override;
+ llvm::Error GetObjectDescription(Stream &str, Value &value,
+ ExecutionContextScope *exe_scope) override;
- bool GetObjectDescription(Stream &str, ValueObject &object) override;
+ llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override;
bool CouldHaveDynamicValue(ValueObject &in_value) override;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
index ba52444f0c2f..a812ffba7a64 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
@@ -350,18 +350,17 @@ ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {
return nullptr;
}
-bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type,
- uint64_t &size) {
+std::optional<uint64_t>
+ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type) {
void *opaque_ptr = compiler_type.GetOpaqueQualType();
- size = m_type_size_cache.Lookup(opaque_ptr);
- // an ObjC object will at least have an ISA, so 0 is definitely not OK
- if (size > 0)
- return true;
+ uint64_t cached_size = m_type_size_cache.Lookup(opaque_ptr);
+ if (cached_size > 0)
+ return cached_size;
ClassDescriptorSP class_descriptor_sp =
GetClassDescriptorFromClassName(compiler_type.GetTypeName());
if (!class_descriptor_sp)
- return false;
+ return {};
int32_t max_offset = INT32_MIN;
uint64_t sizeof_max = 0;
@@ -377,11 +376,13 @@ bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type,
}
}
- size = 8 * (max_offset + sizeof_max);
- if (found)
+ uint64_t size = 8 * (max_offset + sizeof_max);
+ if (found && size > 0) {
m_type_size_cache.Insert(opaque_ptr, size);
+ return size;
+ }
- return found;
+ return {};
}
lldb::BreakpointPreconditionSP
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
index 0a8b6e8d56ed..ffe9725fa682 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
@@ -107,7 +107,7 @@ public:
int64_t *value_bits = nullptr,
uint64_t *payload = nullptr) = 0;
/// @}
-
+
virtual uint64_t GetInstanceSize() = 0;
// use to implement version-specific additional constraints on pointers
@@ -321,8 +321,8 @@ public:
m_negative_complete_class_cache.clear();
}
- bool GetTypeBitSize(const CompilerType &compiler_type,
- uint64_t &size) override;
+ std::optional<uint64_t>
+ GetTypeBitSize(const CompilerType &compiler_type) override;
/// Check whether the name is "self" or "_cmd" and should show up in
/// "frame variable".
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 4dd23bb1e4db..2979bf69bf76 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -5140,12 +5140,20 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
case LC_LOADFVMLIB:
case LC_LOAD_UPWARD_DYLIB: {
uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ // For LC_LOAD_DYLIB there is an alternate encoding
+ // which adds a uint32_t `flags` field for `DYLD_USE_*`
+ // flags. This can be detected by a timestamp field with
+ // the `DYLIB_USE_MARKER` constant value.
bool is_delayed_init = false;
uint32_t use_command_marker = m_data.GetU32(&offset);
if (use_command_marker == 0x1a741800 /* DYLIB_USE_MARKER */) {
offset += 4; /* uint32_t current_version */
offset += 4; /* uint32_t compat_version */
uint32_t flags = m_data.GetU32(&offset);
+ // If this LC_LOAD_DYLIB is marked delay-init,
+ // don't report it as a dependent library -- it
+ // may be loaded in the process at some point,
+ // but will most likely not be load at launch.
if (flags & 0x08 /* DYLIB_USE_DELAYED_INIT */)
is_delayed_init = true;
}
diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
index 7231433619ff..de212c6b20da 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
@@ -20,25 +20,100 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/ThreadList.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RangeMap.h"
#include "lldb/Utility/RegisterValue.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Minidump.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
+#include "llvm/TargetParser/Triple.h"
#include "Plugins/Process/minidump/MinidumpTypes.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+#include <algorithm>
#include <cinttypes>
+#include <climits>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <iostream>
+#include <set>
+#include <utility>
+#include <vector>
using namespace lldb;
using namespace lldb_private;
using namespace llvm::minidump;
-void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {
+Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() {
+ // First set the offset on the file, and on the bytes saved
+ m_saved_data_size = HEADER_SIZE;
+ // We know we will have at least Misc, SystemInfo, Modules, and ThreadList
+ // (corresponding memory list for stacks) And an additional memory list for
+ // non-stacks.
+ lldb_private::Target &target = m_process_sp->GetTarget();
+ m_expected_directories = 6;
+ // Check if OS is linux and reserve directory space for all linux specific
+ // breakpad extension directories.
+ if (target.GetArchitecture().GetTriple().getOS() ==
+ llvm::Triple::OSType::Linux)
+ m_expected_directories += 9;
+
+ // Go through all of the threads and check for exceptions.
+ lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
+ const uint32_t num_threads = thread_list.GetSize();
+ for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
+ ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
+ StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
+ if (stop_info_sp) {
+ const StopReason &stop_reason = stop_info_sp->GetStopReason();
+ if (stop_reason == StopReason::eStopReasonException ||
+ stop_reason == StopReason::eStopReasonSignal)
+ m_expected_directories++;
+ }
+ }
+
+ m_saved_data_size +=
+ m_expected_directories * sizeof(llvm::minidump::Directory);
+ Status error;
+ offset_t new_offset = m_core_file->SeekFromStart(m_saved_data_size);
+ if (new_offset != m_saved_data_size)
+ error.SetErrorStringWithFormat("Failed to fill in header and directory "
+ "sections. Written / Expected (%" PRIx64
+ " / %" PRIx64 ")",
+ new_offset, m_saved_data_size);
+
+ return error;
+}
+
+Status MinidumpFileBuilder::AddDirectory(StreamType type,
+ uint64_t stream_size) {
+ // We explicitly cast type, an 32b enum, to uint32_t to avoid warnings.
+ Status error;
+ if (GetCurrentDataEndOffset() > UINT32_MAX) {
+ error.SetErrorStringWithFormat("Unable to add directory for stream type "
+ "%x, offset is greater then 32 bit limit.",
+ (uint32_t)type);
+ return error;
+ }
+
+ if (m_directories.size() + 1 > m_expected_directories) {
+ error.SetErrorStringWithFormat(
+ "Unable to add directory for stream type %x, exceeded expected number "
+ "of directories %zu.",
+ (uint32_t)type, m_expected_directories);
+ return error;
+ }
+
LocationDescriptor loc;
loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
// Stream will begin at the current end of data section
@@ -49,11 +124,17 @@ void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {
dir.Location = loc;
m_directories.push_back(dir);
+ return error;
}
-Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) {
+Status MinidumpFileBuilder::AddSystemInfo() {
Status error;
- AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
+ const llvm::Triple &target_triple =
+ m_process_sp->GetTarget().GetArchitecture().GetTriple();
+ error =
+ AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
+ if (error.Fail())
+ return error;
llvm::minidump::ProcessorArchitecture arch;
switch (target_triple.getArch()) {
@@ -165,7 +246,6 @@ llvm::Expected<uint64_t> getModuleFileSize(Target &target,
}
return SizeOfImage;
}
-
SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
if (!sect_sp) {
@@ -203,10 +283,11 @@ llvm::Expected<uint64_t> getModuleFileSize(Target &target,
// single module. Additional data of variable length, such as module's names,
// are stored just after the ModuleList stream. The llvm::minidump::Module
// structures point to this helper data by global offset.
-Status MinidumpFileBuilder::AddModuleList(Target &target) {
+Status MinidumpFileBuilder::AddModuleList() {
constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
Status error;
+ lldb_private::Target &target = m_process_sp->GetTarget();
const ModuleList &modules = target.GetImages();
llvm::support::ulittle32_t modules_count =
static_cast<llvm::support::ulittle32_t>(modules.GetSize());
@@ -223,7 +304,9 @@ Status MinidumpFileBuilder::AddModuleList(Target &target) {
sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
// Adding directory describing this stream.
- AddDirectory(StreamType::ModuleList, module_stream_size);
+ error = AddDirectory(StreamType::ModuleList, module_stream_size);
+ if (error.Fail())
+ return error;
m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
@@ -480,42 +563,32 @@ public:
}
};
-// Function returns start and size of the memory region that contains
-// memory location pointed to by the current stack pointer.
-llvm::Expected<std::pair<addr_t, addr_t>>
-findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {
- MemoryRegionInfo range_info;
- Status error = process_sp->GetMemoryRegionInfo(rsp, range_info);
- // Skip failed memory region requests or any regions with no permissions.
- if (error.Fail() || range_info.GetLLDBPermissions() == 0)
- return llvm::createStringError(
- std::errc::not_supported,
- "unable to load stack segment of the process");
-
- // This is a duplicate of the logic in
- // Process::SaveOffRegionsWithStackPointers but ultimately, we need to only
- // save up from the start of the stack down to the stack pointer
- const addr_t range_end = range_info.GetRange().GetRangeEnd();
- const addr_t red_zone = process_sp->GetABI()->GetRedZoneSize();
- const addr_t stack_head = rsp - red_zone;
- if (stack_head > range_info.GetRange().GetRangeEnd()) {
- range_info.GetRange().SetRangeBase(stack_head);
- range_info.GetRange().SetByteSize(range_end - stack_head);
- }
-
- const addr_t addr = range_info.GetRange().GetRangeBase();
- const addr_t size = range_info.GetRange().GetByteSize();
-
- if (size == 0)
- return llvm::createStringError(std::errc::not_supported,
- "stack segment of the process is empty");
-
- return std::make_pair(addr, size);
+Status MinidumpFileBuilder::FixThreadStacks() {
+ Status error;
+ // If we have anything in the heap flush it.
+ FlushBufferToDisk();
+ m_core_file->SeekFromStart(m_thread_list_start);
+ for (auto &pair : m_thread_by_range_end) {
+ // The thread objects will get a new memory descriptor added
+ // When we are emitting the memory list and then we write it here
+ const llvm::minidump::Thread &thread = pair.second;
+ size_t bytes_to_write = sizeof(llvm::minidump::Thread);
+ size_t bytes_written = bytes_to_write;
+ error = m_core_file->Write(&thread, bytes_written);
+ if (error.Fail() || bytes_to_write != bytes_written) {
+ error.SetErrorStringWithFormat(
+ "Wrote incorrect number of bytes to minidump file. (written %zd/%zd)",
+ bytes_written, bytes_to_write);
+ return error;
+ }
+ }
+
+ return error;
}
-Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
+Status MinidumpFileBuilder::AddThreadList() {
constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
- lldb_private::ThreadList thread_list = process_sp->GetThreadList();
+ lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
// size of the entire thread stream consists of:
// number of threads and threads array
@@ -523,28 +596,31 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
thread_list.GetSize() * minidump_thread_size;
// save for the ability to set up RVA
size_t size_before = GetCurrentDataEndOffset();
-
- AddDirectory(StreamType::ThreadList, thread_stream_size);
+ Status error;
+ error = AddDirectory(StreamType::ThreadList, thread_stream_size);
+ if (error.Fail())
+ return error;
llvm::support::ulittle32_t thread_count =
static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
+ // Take the offset after the thread count.
+ m_thread_list_start = GetCurrentDataEndOffset();
DataBufferHeap helper_data;
const uint32_t num_threads = thread_list.GetSize();
-
+ Log *log = GetLog(LLDBLog::Object);
for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
- Status error;
if (!reg_ctx_sp) {
error.SetErrorString("Unable to get the register context.");
return error;
}
RegisterContext *reg_ctx = reg_ctx_sp.get();
- Target &target = process_sp->GetTarget();
+ Target &target = m_process_sp->GetTarget();
const ArchSpec &arch = target.GetArchitecture();
ArchThreadContexts thread_context(arch.GetMachine());
if (!thread_context.prepareRegisterContext(reg_ctx)) {
@@ -553,38 +629,18 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
arch.GetTriple().getArchName().str().c_str());
return error;
}
- uint64_t sp = reg_ctx->GetSP();
- auto expected_address_range = findStackHelper(process_sp, sp);
- if (!expected_address_range) {
- consumeError(expected_address_range.takeError());
- error.SetErrorString("Unable to get the stack address.");
- return error;
- }
-
- std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);
- uint64_t addr = range.first;
- uint64_t size = range.second;
-
- auto data_up = std::make_unique<DataBufferHeap>(size, 0);
- const size_t stack_bytes_read =
- process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
-
- if (error.Fail())
- return error;
-
- LocationDescriptor stack_memory;
- stack_memory.DataSize =
- static_cast<llvm::support::ulittle32_t>(stack_bytes_read);
- stack_memory.RVA = static_cast<llvm::support::ulittle32_t>(
- size_before + thread_stream_size + helper_data.GetByteSize());
+ uint64_t sp = reg_ctx->GetSP();
+ MemoryRegionInfo sp_region;
+ m_process_sp->GetMemoryRegionInfo(sp, sp_region);
+ // Emit a blank descriptor
MemoryDescriptor stack;
- stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr);
- stack.Memory = stack_memory;
-
- helper_data.AppendData(data_up->GetBytes(), stack_bytes_read);
-
+ LocationDescriptor empty_label;
+ empty_label.DataSize = 0;
+ empty_label.RVA = 0;
+ stack.Memory = empty_label;
+ stack.StartOfMemoryRange = 0;
LocationDescriptor thread_context_memory_locator;
thread_context_memory_locator.DataSize =
static_cast<llvm::support::ulittle32_t>(thread_context.size());
@@ -593,6 +649,8 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
// Cache thie thread context memory so we can reuse for exceptions.
m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;
+ LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes",
+ thread_idx, thread_context.size());
helper_data.AppendData(thread_context.data(), thread_context.size());
llvm::minidump::Thread t;
@@ -604,16 +662,20 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
t.Stack = stack, t.Context = thread_context_memory_locator;
+ // We save off the stack object so we can circle back and clean it up.
+ m_thread_by_range_end[sp_region.GetRange().GetRangeEnd()] = t;
m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
}
+ LLDB_LOGF(log, "AddThreadList(): total helper_data %" PRIx64 " bytes",
+ helper_data.GetByteSize());
m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
return Status();
}
-void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) {
- lldb_private::ThreadList thread_list = process_sp->GetThreadList();
-
+Status MinidumpFileBuilder::AddExceptions() {
+ lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
+ Status error;
const uint32_t num_threads = thread_list.GetSize();
for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
@@ -632,7 +694,10 @@ void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) {
if (add_exception) {
constexpr size_t minidump_exception_size =
sizeof(llvm::minidump::ExceptionStream);
- AddDirectory(StreamType::Exception, minidump_exception_size);
+ error = AddDirectory(StreamType::Exception, minidump_exception_size);
+ if (error.Fail())
+ return error;
+
StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
Exception exp_record = {};
@@ -660,69 +725,16 @@ void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) {
m_data.AppendData(&exp_stream, minidump_exception_size);
}
}
-}
-
-lldb_private::Status
-MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp,
- lldb::SaveCoreStyle core_style) {
- Status error;
- Process::CoreFileMemoryRanges core_ranges;
- error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges);
- if (error.Fail()) {
- error.SetErrorString("Process doesn't support getting memory region info.");
- return error;
- }
-
- DataBufferHeap helper_data;
- std::vector<MemoryDescriptor> mem_descriptors;
- for (const auto &core_range : core_ranges) {
- // Skip empty memory regions.
- if (core_range.range.empty())
- continue;
- const addr_t addr = core_range.range.start();
- const addr_t size = core_range.range.size();
- auto data_up = std::make_unique<DataBufferHeap>(size, 0);
- const size_t bytes_read =
- process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
- if (error.Fail()) {
- Log *log = GetLog(LLDBLog::Object);
- LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
- bytes_read, error.AsCString());
- error.Clear();
- }
- if (bytes_read == 0)
- continue;
- // We have a good memory region with valid bytes to store.
- LocationDescriptor memory_dump;
- memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read);
- memory_dump.RVA =
- static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
- MemoryDescriptor memory_desc;
- memory_desc.StartOfMemoryRange =
- static_cast<llvm::support::ulittle64_t>(addr);
- memory_desc.Memory = memory_dump;
- mem_descriptors.push_back(memory_desc);
- m_data.AppendData(data_up->GetBytes(), bytes_read);
- }
-
- AddDirectory(StreamType::MemoryList,
- sizeof(llvm::support::ulittle32_t) +
- mem_descriptors.size() *
- sizeof(llvm::minidump::MemoryDescriptor));
- llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());
-
- m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
- for (auto memory_descriptor : mem_descriptors) {
- m_data.AppendData(&memory_descriptor,
- sizeof(llvm::minidump::MemoryDescriptor));
- }
return error;
}
-void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
- AddDirectory(StreamType::MiscInfo,
- sizeof(lldb_private::minidump::MinidumpMiscInfo));
+lldb_private::Status MinidumpFileBuilder::AddMiscInfo() {
+ Status error;
+ error = AddDirectory(StreamType::MiscInfo,
+ sizeof(lldb_private::minidump::MinidumpMiscInfo));
+ if (error.Fail())
+ return error;
lldb_private::minidump::MinidumpMiscInfo misc_info;
misc_info.size = static_cast<llvm::support::ulittle32_t>(
@@ -732,7 +744,7 @@ void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
lldb_private::ProcessInstanceInfo process_info;
- process_sp->GetProcessInfo(process_info);
+ m_process_sp->GetProcessInfo(process_info);
if (process_info.ProcessIDIsValid()) {
// Set flags1 to reflect that PID is filled in
misc_info.flags1 =
@@ -744,6 +756,7 @@ void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
m_data.AppendData(&misc_info,
sizeof(lldb_private::minidump::MinidumpMiscInfo));
+ return error;
}
std::unique_ptr<llvm::MemoryBuffer>
@@ -754,15 +767,20 @@ getFileStreamHelper(const std::string &path) {
return std::move(maybe_stream.get());
}
-void MinidumpFileBuilder::AddLinuxFileStreams(
- const lldb::ProcessSP &process_sp) {
+Status MinidumpFileBuilder::AddLinuxFileStreams() {
+ Status error;
+ // No-op if we are not on linux.
+ if (m_process_sp->GetTarget().GetArchitecture().GetTriple().getOS() !=
+ llvm::Triple::Linux)
+ return error;
+
std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
{StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
{StreamType::LinuxLSBRelease, "/etc/lsb-release"},
};
lldb_private::ProcessInstanceInfo process_info;
- process_sp->GetProcessInfo(process_info);
+ m_process_sp->GetProcessInfo(process_info);
if (process_info.ProcessIDIsValid()) {
lldb::pid_t pid = process_info.GetProcessID();
std::string pid_str = std::to_string(pid);
@@ -791,16 +809,94 @@ void MinidumpFileBuilder::AddLinuxFileStreams(
size_t size = memory_buffer->getBufferSize();
if (size == 0)
continue;
- AddDirectory(stream, size);
+ error = AddDirectory(stream, size);
+ if (error.Fail())
+ return error;
m_data.AppendData(memory_buffer->getBufferStart(), size);
}
}
+
+ return error;
}
-Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
- constexpr size_t header_size = sizeof(llvm::minidump::Header);
- constexpr size_t directory_size = sizeof(llvm::minidump::Directory);
+Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) {
+ Status error;
+
+ // We first save the thread stacks to ensure they fit in the first UINT32_MAX
+ // bytes of the core file. Thread structures in minidump files can only use
+ // 32 bit memory descriptiors, so we emit them first to ensure the memory is
+ // in accessible with a 32 bit offset.
+ Process::CoreFileMemoryRanges ranges_32;
+ Process::CoreFileMemoryRanges ranges_64;
+ error = m_process_sp->CalculateCoreFileSaveRanges(
+ SaveCoreStyle::eSaveCoreStackOnly, ranges_32);
+ if (error.Fail())
+ return error;
+
+ // Calculate totalsize including the current offset.
+ uint64_t total_size = GetCurrentDataEndOffset();
+ total_size += ranges_32.size() * sizeof(llvm::minidump::MemoryDescriptor);
+ std::unordered_set<addr_t> stack_start_addresses;
+ for (const auto &core_range : ranges_32) {
+ stack_start_addresses.insert(core_range.range.start());
+ total_size += core_range.range.size();
+ }
+
+ if (total_size >= UINT32_MAX) {
+ error.SetErrorStringWithFormat("Unable to write minidump. Stack memory "
+ "exceeds 32b limit. (Num Stacks %zu)",
+ ranges_32.size());
+ return error;
+ }
+
+ Process::CoreFileMemoryRanges all_core_memory_ranges;
+ if (core_style != SaveCoreStyle::eSaveCoreStackOnly) {
+ error = m_process_sp->CalculateCoreFileSaveRanges(core_style,
+ all_core_memory_ranges);
+ if (error.Fail())
+ return error;
+ }
+
+ // After saving the stacks, we start packing as much as we can into 32b.
+ // We apply a generous padding here so that the Directory, MemoryList and
+ // Memory64List sections all begin in 32b addressable space.
+ // Then anything overflow extends into 64b addressable space.
+ // All core memeroy ranges will either container nothing on stacks only
+ // or all the memory ranges including stacks
+ if (!all_core_memory_ranges.empty())
+ total_size +=
+ 256 + (all_core_memory_ranges.size() - stack_start_addresses.size()) *
+ sizeof(llvm::minidump::MemoryDescriptor_64);
+
+ for (const auto &core_range : all_core_memory_ranges) {
+ const addr_t range_size = core_range.range.size();
+ if (stack_start_addresses.count(core_range.range.start()) > 0)
+ // Don't double save stacks.
+ continue;
+
+ if (total_size + range_size < UINT32_MAX) {
+ ranges_32.push_back(core_range);
+ total_size += range_size;
+ } else {
+ ranges_64.push_back(core_range);
+ }
+ }
+ error = AddMemoryList_32(ranges_32);
+ if (error.Fail())
+ return error;
+
+ // Add the remaining memory as a 64b range.
+ if (!ranges_64.empty()) {
+ error = AddMemoryList_64(ranges_64);
+ if (error.Fail())
+ return error;
+ }
+
+ return FixThreadStacks();
+}
+
+Status MinidumpFileBuilder::DumpHeader() const {
// write header
llvm::minidump::Header header;
header.Signature = static_cast<llvm::support::ulittle32_t>(
@@ -808,9 +904,10 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
header.Version = static_cast<llvm::support::ulittle32_t>(
llvm::minidump::Header::MagicVersion);
header.NumberOfStreams =
- static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum());
+ static_cast<llvm::support::ulittle32_t>(m_directories.size());
+ // We write the directories right after the header.
header.StreamDirectoryRVA =
- static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
+ static_cast<llvm::support::ulittle32_t>(HEADER_SIZE);
header.Checksum = static_cast<llvm::support::ulittle32_t>(
0u), // not used in most of the writers
header.TimeDateStamp =
@@ -821,36 +918,35 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
Status error;
size_t bytes_written;
- bytes_written = header_size;
- error = core_file->Write(&header, bytes_written);
- if (error.Fail() || bytes_written != header_size) {
- if (bytes_written != header_size)
+ m_core_file->SeekFromStart(0);
+ bytes_written = HEADER_SIZE;
+ error = m_core_file->Write(&header, bytes_written);
+ if (error.Fail() || bytes_written != HEADER_SIZE) {
+ if (bytes_written != HEADER_SIZE)
error.SetErrorStringWithFormat(
- "unable to write the header (written %zd/%zd)", bytes_written,
- header_size);
+ "Unable to write the minidump header (written %zd/%zd)",
+ bytes_written, HEADER_SIZE);
return error;
}
+ return error;
+}
- // write data
- bytes_written = m_data.GetByteSize();
- error = core_file->Write(m_data.GetBytes(), bytes_written);
- if (error.Fail() || bytes_written != m_data.GetByteSize()) {
- if (bytes_written != m_data.GetByteSize())
- error.SetErrorStringWithFormat(
- "unable to write the data (written %zd/%" PRIu64 ")", bytes_written,
- m_data.GetByteSize());
- return error;
- }
+offset_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
+ return m_data.GetByteSize() + m_saved_data_size;
+}
- // write directories
+Status MinidumpFileBuilder::DumpDirectories() const {
+ Status error;
+ size_t bytes_written;
+ m_core_file->SeekFromStart(HEADER_SIZE);
for (const Directory &dir : m_directories) {
- bytes_written = directory_size;
- error = core_file->Write(&dir, bytes_written);
- if (error.Fail() || bytes_written != directory_size) {
- if (bytes_written != directory_size)
+ bytes_written = DIRECTORY_SIZE;
+ error = m_core_file->Write(&dir, bytes_written);
+ if (error.Fail() || bytes_written != DIRECTORY_SIZE) {
+ if (bytes_written != DIRECTORY_SIZE)
error.SetErrorStringWithFormat(
"unable to write the directory (written %zd/%zd)", bytes_written,
- directory_size);
+ DIRECTORY_SIZE);
return error;
}
}
@@ -858,10 +954,254 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
return error;
}
-size_t MinidumpFileBuilder::GetDirectoriesNum() const {
- return m_directories.size();
+static uint64_t
+GetLargestRangeSize(const Process::CoreFileMemoryRanges &ranges) {
+ uint64_t max_size = 0;
+ for (const auto &core_range : ranges)
+ max_size = std::max(max_size, core_range.range.size());
+ return max_size;
+}
+
+Status
+MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) {
+ std::vector<MemoryDescriptor> descriptors;
+ Status error;
+ if (ranges.size() == 0)
+ return error;
+
+ Log *log = GetLog(LLDBLog::Object);
+ size_t region_index = 0;
+ auto data_up =
+ std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
+ for (const auto &core_range : ranges) {
+ // Take the offset before we write.
+ const offset_t offset_for_data = GetCurrentDataEndOffset();
+ const addr_t addr = core_range.range.start();
+ const addr_t size = core_range.range.size();
+ const addr_t end = core_range.range.end();
+
+ LLDB_LOGF(log,
+ "AddMemoryList %zu/%zu reading memory for region "
+ "(%" PRIx64 " bytes) [%" PRIx64 ", %" PRIx64 ")",
+ region_index, ranges.size(), size, addr, addr + size);
+ ++region_index;
+
+ const size_t bytes_read =
+ m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
+ if (error.Fail() || bytes_read == 0) {
+ LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
+ bytes_read, error.AsCString());
+ // Just skip sections with errors or zero bytes in 32b mode
+ continue;
+ } else if (bytes_read != size) {
+ LLDB_LOGF(
+ log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
+ addr, size);
+ }
+
+ MemoryDescriptor descriptor;
+ descriptor.StartOfMemoryRange =
+ static_cast<llvm::support::ulittle64_t>(addr);
+ descriptor.Memory.DataSize =
+ static_cast<llvm::support::ulittle32_t>(bytes_read);
+ descriptor.Memory.RVA =
+ static_cast<llvm::support::ulittle32_t>(offset_for_data);
+ descriptors.push_back(descriptor);
+ if (m_thread_by_range_end.count(end) > 0)
+ m_thread_by_range_end[end].Stack = descriptor;
+
+ // Add the data to the buffer, flush as needed.
+ error = AddData(data_up->GetBytes(), bytes_read);
+ if (error.Fail())
+ return error;
+ }
+
+ // Add a directory that references this list
+ // With a size of the number of ranges as a 32 bit num
+ // And then the size of all the ranges
+ error = AddDirectory(StreamType::MemoryList,
+ sizeof(llvm::support::ulittle32_t) +
+ descriptors.size() *
+ sizeof(llvm::minidump::MemoryDescriptor));
+ if (error.Fail())
+ return error;
+
+ llvm::support::ulittle32_t memory_ranges_num =
+ static_cast<llvm::support::ulittle32_t>(descriptors.size());
+ m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
+ // For 32b we can get away with writing off the descriptors after the data.
+ // This means no cleanup loop needed.
+ m_data.AppendData(descriptors.data(),
+ descriptors.size() * sizeof(MemoryDescriptor));
+
+ return error;
}
-size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
- return sizeof(llvm::minidump::Header) + m_data.GetByteSize();
+Status
+MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) {
+ Status error;
+ if (ranges.empty())
+ return error;
+
+ error = AddDirectory(StreamType::Memory64List,
+ (sizeof(llvm::support::ulittle64_t) * 2) +
+ ranges.size() *
+ sizeof(llvm::minidump::MemoryDescriptor_64));
+ if (error.Fail())
+ return error;
+
+ llvm::support::ulittle64_t memory_ranges_num =
+ static_cast<llvm::support::ulittle64_t>(ranges.size());
+ m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle64_t));
+ // Capture the starting offset for all the descriptors so we can clean them up
+ // if needed.
+ offset_t starting_offset =
+ GetCurrentDataEndOffset() + sizeof(llvm::support::ulittle64_t);
+ // The base_rva needs to start after the directories, which is right after
+ // this 8 byte variable.
+ offset_t base_rva =
+ starting_offset +
+ (ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64));
+ llvm::support::ulittle64_t memory_ranges_base_rva =
+ static_cast<llvm::support::ulittle64_t>(base_rva);
+ m_data.AppendData(&memory_ranges_base_rva,
+ sizeof(llvm::support::ulittle64_t));
+
+ bool cleanup_required = false;
+ std::vector<MemoryDescriptor_64> descriptors;
+ // Enumerate the ranges and create the memory descriptors so we can append
+ // them first
+ for (const auto core_range : ranges) {
+ // Add the space required to store the memory descriptor
+ MemoryDescriptor_64 memory_desc;
+ memory_desc.StartOfMemoryRange =
+ static_cast<llvm::support::ulittle64_t>(core_range.range.start());
+ memory_desc.DataSize =
+ static_cast<llvm::support::ulittle64_t>(core_range.range.size());
+ descriptors.push_back(memory_desc);
+ // Now write this memory descriptor to the buffer.
+ m_data.AppendData(&memory_desc, sizeof(MemoryDescriptor_64));
+ }
+
+ Log *log = GetLog(LLDBLog::Object);
+ size_t region_index = 0;
+ auto data_up =
+ std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
+ for (const auto &core_range : ranges) {
+ const addr_t addr = core_range.range.start();
+ const addr_t size = core_range.range.size();
+
+ LLDB_LOGF(log,
+ "AddMemoryList_64 %zu/%zu reading memory for region "
+ "(%" PRIx64 "bytes) "
+ "[%" PRIx64 ", %" PRIx64 ")",
+ region_index, ranges.size(), size, addr, addr + size);
+ ++region_index;
+
+ const size_t bytes_read =
+ m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
+ if (error.Fail()) {
+ LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
+ bytes_read, error.AsCString());
+ error.Clear();
+ cleanup_required = true;
+ descriptors[region_index].DataSize = 0;
+ }
+ if (bytes_read != size) {
+ LLDB_LOGF(
+ log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
+ addr, size);
+ cleanup_required = true;
+ descriptors[region_index].DataSize = bytes_read;
+ }
+
+ // Add the data to the buffer, flush as needed.
+ error = AddData(data_up->GetBytes(), bytes_read);
+ if (error.Fail())
+ return error;
+ }
+
+ // Early return if there is no cleanup needed.
+ if (!cleanup_required) {
+ return error;
+ } else {
+ // Flush to disk we can make the fixes in place.
+ FlushBufferToDisk();
+ // Fixup the descriptors that were not read correctly.
+ m_core_file->SeekFromStart(starting_offset);
+ size_t bytes_written = sizeof(MemoryDescriptor_64) * descriptors.size();
+ error = m_core_file->Write(descriptors.data(), bytes_written);
+ if (error.Fail() ||
+ bytes_written != sizeof(MemoryDescriptor_64) * descriptors.size()) {
+ error.SetErrorStringWithFormat(
+ "unable to write the memory descriptors (written %zd/%zd)",
+ bytes_written, sizeof(MemoryDescriptor_64) * descriptors.size());
+ }
+
+ return error;
+ }
+}
+
+Status MinidumpFileBuilder::AddData(const void *data, uint64_t size) {
+ // This should also get chunked, because worst case we copy over a big
+ // object / memory range, say 5gb. In that case, we'd have to allocate 10gb
+ // 5 gb for the buffer we're copying from, and then 5gb for the buffer we're
+ // copying to. Which will be short lived and immedaitely go to disk, the goal
+ // here is to limit the number of bytes we need to host in memory at any given
+ // time.
+ m_data.AppendData(data, size);
+ if (m_data.GetByteSize() > MAX_WRITE_CHUNK_SIZE)
+ return FlushBufferToDisk();
+
+ return Status();
+}
+
+Status MinidumpFileBuilder::FlushBufferToDisk() {
+ Status error;
+ // Set the stream to it's end.
+ m_core_file->SeekFromStart(m_saved_data_size);
+ addr_t starting_size = m_data.GetByteSize();
+ addr_t remaining_bytes = starting_size;
+ offset_t offset = 0;
+
+ while (remaining_bytes > 0) {
+ size_t bytes_written = remaining_bytes;
+ // We don't care how many bytes we wrote unless we got an error
+ // so just decrement the remaining bytes.
+ error = m_core_file->Write(m_data.GetBytes() + offset, bytes_written);
+ if (error.Fail()) {
+ error.SetErrorStringWithFormat(
+ "Wrote incorrect number of bytes to minidump file. (written %" PRIx64
+ "/%" PRIx64 ")",
+ starting_size - remaining_bytes, starting_size);
+ return error;
+ }
+
+ offset += bytes_written;
+ remaining_bytes -= bytes_written;
+ }
+
+ m_saved_data_size += starting_size;
+ m_data.Clear();
+ return error;
+}
+
+Status MinidumpFileBuilder::DumpFile() {
+ Status error;
+ // If anything is left unsaved, dump it.
+ error = FlushBufferToDisk();
+ if (error.Fail())
+ return error;
+
+ // Overwrite the header which we filled in earlier.
+ error = DumpHeader();
+ if (error.Fail())
+ return error;
+
+ // Overwrite the space saved for directories
+ error = DumpDirectories();
+ if (error.Fail())
+ return error;
+
+ return error;
}
diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
index b2e984191983..20564e0661f2 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
@@ -17,12 +17,20 @@
#define LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H
#include <cstddef>
+#include <cstdint>
#include <map>
+#include <unordered_map>
+#include <utility>
+#include <variant>
+#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/Status.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+#include "llvm/BinaryFormat/Minidump.h"
#include "llvm/Object/Minidump.h"
// Write std::string to minidump in the UTF16 format(with null termination char)
@@ -36,11 +44,39 @@ lldb_private::Status WriteString(const std::string &to_write,
/// Minidump writer for Linux
///
/// This class provides a Minidump writer that is able to
-/// snapshot the current process state. For the whole time, it stores all
-/// the data on heap.
+/// snapshot the current process state.
+///
+/// Minidumps are a Microsoft format for dumping process state.
+/// This class constructs the minidump on disk starting with
+/// Headers and Directories are written at the top of the file,
+/// with the amount of bytes being precalculates before any writing takes place
+/// Then the smaller data sections are written
+/// SystemInfo, ModuleList, Misc Info.
+/// Then Threads are emitted, threads are the first section that needs to be
+/// 'fixed up' this happens when later we emit the memory stream, we identify if
+/// that stream is the expected stack, and if so we update the stack with the
+/// current RVA. Lastly the Memory lists are added. For Memory List, this will
+/// contain everything that can fit within 4.2gb. MemoryList has it's
+/// descriptors written at the end so it cannot be allowed to overflow.
+///
+/// Memory64List is a special case where it has to be begin before 4.2gb but can
+/// expand forever The difference in Memory64List is there are no RVA's and all
+/// the addresses are figured out by starting at the base RVA, and adding the
+/// antecedent memory sections.
+///
+/// Because Memory64List can be arbitrarily large, this class has to write
+/// chunks to disk this means we have to precalculate the descriptors and write
+/// them first, and if we encounter any error, or are unable to read the same
+/// number of bytes we have to go back and update them on disk.
+///
+/// And as the last step, after all the directories have been added, we go back
+/// to the top of the file to fill in the header and the redirectory sections
+/// that we preallocated.
class MinidumpFileBuilder {
public:
- MinidumpFileBuilder() = default;
+ MinidumpFileBuilder(lldb::FileUP &&core_file,
+ const lldb::ProcessSP &process_sp)
+ : m_process_sp(process_sp), m_core_file(std::move(core_file)){};
MinidumpFileBuilder(const MinidumpFileBuilder &) = delete;
MinidumpFileBuilder &operator=(const MinidumpFileBuilder &) = delete;
@@ -50,48 +86,84 @@ public:
~MinidumpFileBuilder() = default;
+ // This method only calculates the amount of bytes the header and directories
+ // will take up. It does not write the directories or headers. This function
+ // must be called with a followup to fill in the data.
+ lldb_private::Status AddHeaderAndCalculateDirectories();
// Add SystemInfo stream, used for storing the most basic information
// about the system, platform etc...
- lldb_private::Status AddSystemInfo(const llvm::Triple &target_triple);
+ lldb_private::Status AddSystemInfo();
// Add ModuleList stream, containing information about all loaded modules
// at the time of saving minidump.
- lldb_private::Status AddModuleList(lldb_private::Target &target);
+ lldb_private::Status AddModuleList();
// Add ThreadList stream, containing information about all threads running
// at the moment of core saving. Contains information about thread
// contexts.
- lldb_private::Status AddThreadList(const lldb::ProcessSP &process_sp);
+ lldb_private::Status AddThreadList();
// Add Exception streams for any threads that stopped with exceptions.
- void AddExceptions(const lldb::ProcessSP &process_sp);
+ lldb_private::Status AddExceptions();
// Add MemoryList stream, containing dumps of important memory segments
- lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp,
- lldb::SaveCoreStyle core_style);
+ lldb_private::Status AddMemoryList(lldb::SaveCoreStyle core_style);
// Add MiscInfo stream, mainly providing ProcessId
- void AddMiscInfo(const lldb::ProcessSP &process_sp);
+ lldb_private::Status AddMiscInfo();
// Add informative files about a Linux process
- void AddLinuxFileStreams(const lldb::ProcessSP &process_sp);
- // Dump the prepared data into file. In case of the failure data are
- // intact.
- lldb_private::Status Dump(lldb::FileUP &core_file) const;
- // Returns the current number of directories(streams) that have been so far
- // created. This number of directories will be dumped when calling Dump()
- size_t GetDirectoriesNum() const;
+ lldb_private::Status AddLinuxFileStreams();
+
+ // Run cleanup and write all remaining bytes to file
+ lldb_private::Status DumpFile();
private:
+ // Add data to the end of the buffer, if the buffer exceeds the flush level,
+ // trigger a flush.
+ lldb_private::Status AddData(const void *data, uint64_t size);
+ // Add MemoryList stream, containing dumps of important memory segments
+ lldb_private::Status
+ AddMemoryList_64(lldb_private::Process::CoreFileMemoryRanges &ranges);
+ lldb_private::Status
+ AddMemoryList_32(lldb_private::Process::CoreFileMemoryRanges &ranges);
+ // Update the thread list on disk with the newly emitted stack RVAs.
+ lldb_private::Status FixThreadStacks();
+ lldb_private::Status FlushBufferToDisk();
+
+ lldb_private::Status DumpHeader() const;
+ lldb_private::Status DumpDirectories() const;
// Add directory of StreamType pointing to the current end of the prepared
// file with the specified size.
- void AddDirectory(llvm::minidump::StreamType type, size_t stream_size);
- size_t GetCurrentDataEndOffset() const;
-
- // Stores directories to later put them at the end of minidump file
+ lldb_private::Status AddDirectory(llvm::minidump::StreamType type,
+ uint64_t stream_size);
+ lldb::offset_t GetCurrentDataEndOffset() const;
+ // Stores directories to fill in later
std::vector<llvm::minidump::Directory> m_directories;
+ // When we write off the threads for the first time, we need to clean them up
+ // and give them the correct RVA once we write the stack memory list.
+ // We save by the end because we only take from the stack pointer up
+ // So the saved off range base can differ from the memory region the stack
+ // pointer is in.
+ std::unordered_map<lldb::addr_t, llvm::minidump::Thread>
+ m_thread_by_range_end;
// Main data buffer consisting of data without the minidump header and
// directories
lldb_private::DataBufferHeap m_data;
+ lldb::ProcessSP m_process_sp;
+
+ size_t m_expected_directories = 0;
+ uint64_t m_saved_data_size = 0;
+ lldb::offset_t m_thread_list_start = 0;
+ // We set the max write amount to 128 mb, this is arbitrary
+ // but we want to try to keep the size of m_data small
+ // and we will only exceed a 128 mb buffer if we get a memory region
+ // that is larger than 128 mb.
+ static constexpr size_t MAX_WRITE_CHUNK_SIZE = (1024 * 1024 * 128);
+
+ static constexpr size_t HEADER_SIZE = sizeof(llvm::minidump::Header);
+ static constexpr size_t DIRECTORY_SIZE = sizeof(llvm::minidump::Directory);
// More that one place can mention the register thread context locations,
// so when we emit the thread contents, remember where it is so we don't have
// to duplicate it in the exception data.
- std::map<lldb::tid_t, llvm::minidump::LocationDescriptor> m_tid_to_reg_ctx;
+ std::unordered_map<lldb::tid_t, llvm::minidump::LocationDescriptor>
+ m_tid_to_reg_ctx;
+ lldb::FileUP m_core_file;
};
#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H
diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
index 1af5d99f0b16..7c875aa3223e 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
+++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
@@ -15,6 +15,7 @@
#include "lldb/Core/Section.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
#include "llvm/Support/FileSystem.h"
@@ -65,56 +66,70 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp,
if (!process_sp)
return false;
- MinidumpFileBuilder builder;
-
- Target &target = process_sp->GetTarget();
+ llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open(
+ outfile, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate);
+ if (!maybe_core_file) {
+ error = maybe_core_file.takeError();
+ return false;
+ }
+ MinidumpFileBuilder builder(std::move(maybe_core_file.get()), process_sp);
Log *log = GetLog(LLDBLog::Object);
- error = builder.AddSystemInfo(target.GetArchitecture().GetTriple());
+ error = builder.AddHeaderAndCalculateDirectories();
if (error.Fail()) {
- LLDB_LOG(log, "AddSystemInfo failed: %s", error.AsCString());
+ LLDB_LOGF(log, "AddHeaderAndCalculateDirectories failed: %s",
+ error.AsCString());
+ return false;
+ };
+ error = builder.AddSystemInfo();
+ if (error.Fail()) {
+ LLDB_LOGF(log, "AddSystemInfo failed: %s", error.AsCString());
return false;
}
- error = builder.AddModuleList(target);
+ error = builder.AddModuleList();
if (error.Fail()) {
- LLDB_LOG(log, "AddModuleList failed: %s", error.AsCString());
+ LLDB_LOGF(log, "AddModuleList failed: %s", error.AsCString());
return false;
}
-
- builder.AddMiscInfo(process_sp);
-
- error = builder.AddThreadList(process_sp);
+ error = builder.AddMiscInfo();
if (error.Fail()) {
- LLDB_LOG(log, "AddThreadList failed: %s", error.AsCString());
+ LLDB_LOGF(log, "AddMiscInfo failed: %s", error.AsCString());
return false;
}
- // Add any exceptions but only if there are any in any threads.
- builder.AddExceptions(process_sp);
+ error = builder.AddThreadList();
+ if (error.Fail()) {
+ LLDB_LOGF(log, "AddThreadList failed: %s", error.AsCString());
+ return false;
+ }
- error = builder.AddMemoryList(process_sp, core_style);
+ error = builder.AddLinuxFileStreams();
if (error.Fail()) {
- LLDB_LOG(log, "AddMemoryList failed: %s", error.AsCString());
+ LLDB_LOGF(log, "AddLinuxFileStreams failed: %s", error.AsCString());
return false;
}
- if (target.GetArchitecture().GetTriple().getOS() ==
- llvm::Triple::OSType::Linux) {
- builder.AddLinuxFileStreams(process_sp);
+ // Add any exceptions but only if there are any in any threads.
+ error = builder.AddExceptions();
+ if (error.Fail()) {
+ LLDB_LOGF(log, "AddExceptions failed: %s", error.AsCString());
+ return false;
}
- llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open(
- outfile, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate);
- if (!maybe_core_file) {
- error = maybe_core_file.takeError();
+ // Note: add memory HAS to be the last thing we do. It can overflow into 64b
+ // land and many RVA's only support 32b
+ error = builder.AddMemoryList(core_style);
+ if (error.Fail()) {
+ LLDB_LOGF(log, "AddMemoryList failed: %s", error.AsCString());
return false;
}
- lldb::FileUP core_file = std::move(maybe_core_file.get());
- error = builder.Dump(core_file);
- if (error.Fail())
+ error = builder.DumpFile();
+ if (error.Fail()) {
+ LLDB_LOGF(log, "DumpFile failed: %s", error.AsCString());
return false;
+ }
return true;
}
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
index 0c4b566b7d53..c27a34b7201a 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
@@ -383,81 +383,6 @@ PlatformSP PlatformAppleSimulator::CreateInstance(
return PlatformSP();
}
-Status PlatformAppleSimulator::ResolveExecutable(
- const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) {
- Status error;
- // Nothing special to do here, just use the actual file and architecture
-
- ModuleSpec resolved_module_spec(module_spec);
-
- // If we have "ls" as the exe_file, resolve the executable loation based on
- // the current path variables
- // TODO: resolve bare executables in the Platform SDK
- // if (!resolved_exe_file.Exists())
- // resolved_exe_file.ResolveExecutableLocation ();
-
- // Resolve any executable within a bundle on MacOSX
- // TODO: verify that this handles shallow bundles, if not then implement one
- // ourselves
- Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
-
- if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
- if (resolved_module_spec.GetArchitecture().IsValid()) {
- error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- NULL, NULL, NULL);
-
- if (exe_module_sp && exe_module_sp->GetObjectFile())
- return error;
- exe_module_sp.reset();
- }
- // No valid architecture was specified or the exact ARM slice wasn't found
- // so 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;
- llvm::ListSeparator LS;
- ArchSpec platform_arch;
- for (const ArchSpec &arch : GetSupportedArchitectures({})) {
- resolved_module_spec.GetArchitecture() = arch;
-
- // Only match x86 with x86 and x86_64 with x86_64...
- if (!module_spec.GetArchitecture().IsValid() ||
- module_spec.GetArchitecture().GetCore() ==
- resolved_module_spec.GetArchitecture().GetCore()) {
- error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- NULL, NULL, NULL);
- // Did we find an executable using one of the
- if (error.Success()) {
- if (exe_module_sp && exe_module_sp->GetObjectFile())
- break;
- else
- error.SetErrorToGenericError();
- }
-
- arch_names << LS << platform_arch.GetArchitectureName();
- }
- }
-
- if (error.Fail() || !exe_module_sp) {
- if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) {
- error.SetErrorStringWithFormatv(
- "'{0}' doesn't contain any '{1}' platform architectures: {2}",
- resolved_module_spec.GetFileSpec(), GetPluginName(),
- arch_names.GetString());
- } else {
- error.SetErrorStringWithFormat(
- "'%s' is not readable",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
- }
- } else {
- error.SetErrorStringWithFormat("'%s' does not exist",
- module_spec.GetFileSpec().GetPath().c_str());
- }
-
- return error;
-}
-
Status PlatformAppleSimulator::GetSymbolFile(const FileSpec &platform_file,
const UUID *uuid_ptr,
FileSpec &local_file) {
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
index e17e7b6992ee..7fcf2c502ca6 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
@@ -87,10 +87,6 @@ public:
std::vector<ArchSpec>
GetSupportedArchitectures(const ArchSpec &process_host_arch) override;
- Status
- ResolveExecutable(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr) override;
-
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
const FileSpecList *module_search_paths_ptr,
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
index a244ee35976b..9323b66181c7 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
@@ -63,71 +63,6 @@ void PlatformRemoteDarwinDevice::GetStatus(Stream &strm) {
}
}
-Status PlatformRemoteDarwinDevice::ResolveExecutable(
- const ModuleSpec &ms, lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) {
- Status error;
- // Nothing special to do here, just use the actual file and architecture
-
- ModuleSpec resolved_module_spec(ms);
-
- // Resolve any executable within a bundle on MacOSX
- // TODO: verify that this handles shallow bundles, if not then implement one
- // ourselves
- Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
-
- if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
- if (resolved_module_spec.GetArchitecture().IsValid() ||
- resolved_module_spec.GetUUID().IsValid()) {
- error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- nullptr, nullptr, nullptr);
-
- if (exe_module_sp && exe_module_sp->GetObjectFile())
- return error;
- exe_module_sp.reset();
- }
- // No valid architecture was specified or the exact ARM slice wasn't found
- // so 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;
- llvm::ListSeparator LS;
- ArchSpec process_host_arch;
- for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) {
- resolved_module_spec.GetArchitecture() = arch;
- error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- nullptr, 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();
- }
-
- arch_names << LS << arch.GetArchitectureName();
- }
-
- if (error.Fail() || !exe_module_sp) {
- if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) {
- error.SetErrorStringWithFormatv(
- "'{0}' doesn't contain any '{1}' platform architectures: {2}",
- resolved_module_spec.GetFileSpec(), GetPluginName(),
- arch_names.GetData());
- } else {
- error.SetErrorStringWithFormat(
- "'%s' is not readable",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
- }
- } else {
- error.SetErrorStringWithFormat(
- "'%s' does not exist",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
-
- return error;
-}
-
bool PlatformRemoteDarwinDevice::GetFileInSDK(const char *platform_file_path,
uint32_t sdk_idx,
lldb_private::FileSpec &local_file) {
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
index c60486604099..557f4876e91a 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
@@ -40,10 +40,6 @@ public:
~PlatformRemoteDarwinDevice() override;
// Platform functions
- Status
- ResolveExecutable(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr) override;
-
void GetStatus(Stream &strm) override;
virtual Status GetSymbolFile(const FileSpec &platform_file,
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
index 5ad2f7a8e945..4668c25eab08 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -506,7 +506,7 @@ uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
return LLDB_INVALID_INDEX32;
else if (watch_mask <= 0x02)
size = 2;
- else if (watch_mask <= 0x04)
+ else
size = 4;
addr = addr & (~0x03);
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 9b5f7aef1efe..5397e90022f3 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -388,7 +388,7 @@ NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info,
return error;
}
- // ZA is part of the SME set but uses a seperate member buffer for
+ // ZA is part of the SME set but uses a separate member buffer for
// storage. Therefore its effective byte offset is always 0 even if it
// isn't 0 within the SME register set.
src = (uint8_t *)GetZABuffer() + GetZAHeaderSize();
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp
index 51553817921f..8ed75d700f22 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp
@@ -20,6 +20,7 @@
#define HWCAP2_BTI (1ULL << 17)
#define HWCAP2_MTE (1ULL << 18)
#define HWCAP2_AFP (1ULL << 20)
+#define HWCAP2_SME (1ULL << 23)
#define HWCAP2_EBF16 (1ULL << 32)
using namespace lldb_private;
@@ -27,7 +28,10 @@ using namespace lldb_private;
LinuxArm64RegisterFlags::Fields
LinuxArm64RegisterFlags::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
(void)hwcap;
- (void)hwcap2;
+
+ if (!(hwcap2 & HWCAP2_SME))
+ return {};
+
// Represents the pseudo register that lldb-server builds, which itself
// matches the architectural register SCVR. The fields match SVCR in the Arm
// manual.
@@ -40,7 +44,10 @@ LinuxArm64RegisterFlags::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
LinuxArm64RegisterFlags::Fields
LinuxArm64RegisterFlags::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2) {
(void)hwcap;
- (void)hwcap2;
+
+ if (!(hwcap2 & HWCAP2_MTE))
+ return {};
+
// Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
// to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
// used to build the value.
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h
index 660bef08700f..49b1d90db64f 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h
@@ -38,8 +38,8 @@ public:
/// For the registers listed in this class, detect which fields are
/// present. Must be called before UpdateRegisterInfos.
/// If called more than once, fields will be redetected each time from
- /// scratch. If you do not have access to hwcap, just pass 0 for each one, you
- /// will only get unconditional fields.
+ /// scratch. If the target would not have this register at all, the list of
+ /// fields will be left empty.
void DetectFields(uint64_t hwcap, uint64_t hwcap2);
/// Add the field information of any registers named in this class,
@@ -63,7 +63,7 @@ private:
struct RegisterEntry {
RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector)
- : m_name(name), m_flags(std::string(name) + "_flags", size, {{"", 0}}),
+ : m_name(name), m_flags(std::string(name) + "_flags", size, {}),
m_detector(detector) {}
llvm::StringRef m_name;
diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
index 75504323b4fd..25cee369d7ee 100644
--- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
+++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -92,9 +92,7 @@ bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) {
Target &target = *exe_ctx.GetTargetPtr();
Process &process = *exe_ctx.GetProcessPtr();
- ABISP abi_sp = process.GetABI();
const ArchSpec &arch = target.GetArchitecture();
- assert(abi_sp && "Missing ABI info");
// Check for a ptrauth-enabled target.
const bool ptrauth_enabled_target =
@@ -110,6 +108,9 @@ bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) {
strm.Printf("Note: Possible pointer authentication failure detected.\n");
};
+ ABISP abi_sp = process.GetABI();
+ assert(abi_sp && "Missing ABI info");
+
// Check if we have a "brk 0xc47x" trap, where the value that failed to
// authenticate is in x16.
Address current_address = current_frame->GetFrameCodeAddress();
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index eb0834b1159f..f383b3d40a4f 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -405,8 +405,7 @@ void ProcessWindows::RefreshStateAfterStop() {
"{1:x} with watchpoint {2}",
m_session_data->m_debugger->GetProcess().GetProcessId(), pc, id);
- stop_info = StopInfo::CreateStopReasonWithWatchpointID(
- *stop_thread, id, m_watchpoints[id].address);
+ stop_info = StopInfo::CreateStopReasonWithWatchpointID(*stop_thread, id);
stop_thread->SetStopInfo(stop_info);
return;
@@ -857,7 +856,7 @@ Status ProcessWindows::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
info.address = wp_sp->GetLoadAddress();
info.size = wp_sp->GetByteSize();
info.read = wp_sp->WatchpointRead();
- info.write = wp_sp->WatchpointWrite();
+ info.write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify();
for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 8a47eed3d7cb..187370eb36ca 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -539,9 +539,8 @@ bool GDBRemoteCommunication::DecompressPacket() {
else if (m_compression_type == CompressionType::ZlibDeflate)
scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_ZLIB);
else if (m_compression_type == CompressionType::LZMA)
- scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZMA);
- else if (m_compression_type == CompressionType::LZFSE)
- scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE);
+ scratchbuf_size =
+ compression_decode_scratch_buffer_size(COMPRESSION_LZMA);
if (scratchbuf_size > 0) {
m_decompression_scratch = (void*) malloc (scratchbuf_size);
m_decompression_scratch_type = m_compression_type;
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index a5a731981299..3195587eb567 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4179,21 +4179,134 @@ struct GdbServerTargetInfo {
RegisterSetMap reg_set_map;
};
-static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node,
- unsigned size) {
+static FieldEnum::Enumerators ParseEnumEvalues(const XMLNode &enum_node) {
+ Log *log(GetLog(GDBRLog::Process));
+ // We will use the last instance of each value. Also we preserve the order
+ // of declaration in the XML, as it may not be numerical.
+ // For example, hardware may intially release with two states that softwware
+ // can read from a register field:
+ // 0 = startup, 1 = running
+ // If in a future hardware release, the designers added a pre-startup state:
+ // 0 = startup, 1 = running, 2 = pre-startup
+ // Now it makes more sense to list them in this logical order as opposed to
+ // numerical order:
+ // 2 = pre-startup, 1 = startup, 0 = startup
+ // This only matters for "register info" but let's trust what the server
+ // chose regardless.
+ std::map<uint64_t, FieldEnum::Enumerator> enumerators;
+
+ enum_node.ForEachChildElementWithName(
+ "evalue", [&enumerators, &log](const XMLNode &enumerator_node) {
+ std::optional<llvm::StringRef> name;
+ std::optional<uint64_t> value;
+
+ enumerator_node.ForEachAttribute(
+ [&name, &value, &log](const llvm::StringRef &attr_name,
+ const llvm::StringRef &attr_value) {
+ if (attr_name == "name") {
+ if (attr_value.size())
+ name = attr_value;
+ else
+ LLDB_LOG(log, "ProcessGDBRemote::ParseEnumEvalues "
+ "Ignoring empty name in evalue");
+ } else if (attr_name == "value") {
+ uint64_t parsed_value = 0;
+ if (llvm::to_integer(attr_value, parsed_value))
+ value = parsed_value;
+ else
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseEnumEvalues "
+ "Invalid value \"{0}\" in "
+ "evalue",
+ attr_value.data());
+ } else
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseEnumEvalues Ignoring "
+ "unknown attribute "
+ "\"{0}\" in evalue",
+ attr_name.data());
+
+ // Keep walking attributes.
+ return true;
+ });
+
+ if (value && name)
+ enumerators.insert_or_assign(
+ *value, FieldEnum::Enumerator(*value, name->str()));
+
+ // Find all evalue elements.
+ return true;
+ });
+
+ FieldEnum::Enumerators final_enumerators;
+ for (auto [_, enumerator] : enumerators)
+ final_enumerators.push_back(enumerator);
+
+ return final_enumerators;
+}
+
+static void
+ParseEnums(XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {
+ Log *log(GetLog(GDBRLog::Process));
+
+ // The top level element is "<enum...".
+ feature_node.ForEachChildElementWithName(
+ "enum", [log, &registers_enum_types](const XMLNode &enum_node) {
+ std::string id;
+
+ enum_node.ForEachAttribute([&id](const llvm::StringRef &attr_name,
+ const llvm::StringRef &attr_value) {
+ if (attr_name == "id")
+ id = attr_value;
+
+ // There is also a "size" attribute that is supposed to be the size in
+ // bytes of the register this applies to. However:
+ // * LLDB doesn't need this information.
+ // * It is difficult to verify because you have to wait until the
+ // enum is applied to a field.
+ //
+ // So we will emit this attribute in XML for GDB's sake, but will not
+ // bother ingesting it.
+
+ // Walk all attributes.
+ return true;
+ });
+
+ if (!id.empty()) {
+ FieldEnum::Enumerators enumerators = ParseEnumEvalues(enum_node);
+ if (!enumerators.empty()) {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseEnums Found enum type \"{0}\"",
+ id);
+ registers_enum_types.insert_or_assign(
+ id, std::make_unique<FieldEnum>(id, enumerators));
+ }
+ }
+
+ // Find all <enum> elements.
+ return true;
+ });
+}
+
+static std::vector<RegisterFlags::Field> ParseFlagsFields(
+ XMLNode flags_node, unsigned size,
+ const llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {
Log *log(GetLog(GDBRLog::Process));
const unsigned max_start_bit = size * 8 - 1;
// Process the fields of this set of flags.
std::vector<RegisterFlags::Field> fields;
- flags_node.ForEachChildElementWithName("field", [&fields, max_start_bit,
- &log](const XMLNode
- &field_node) {
+ flags_node.ForEachChildElementWithName("field", [&fields, max_start_bit, &log,
+ &registers_enum_types](
+ const XMLNode
+ &field_node) {
std::optional<llvm::StringRef> name;
std::optional<unsigned> start;
std::optional<unsigned> end;
+ std::optional<llvm::StringRef> type;
- field_node.ForEachAttribute([&name, &start, &end, max_start_bit,
+ field_node.ForEachAttribute([&name, &start, &end, &type, max_start_bit,
&log](const llvm::StringRef &attr_name,
const llvm::StringRef &attr_value) {
// Note that XML in general requires that each of these attributes only
@@ -4240,8 +4353,7 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node,
attr_value.data());
}
} else if (attr_name == "type") {
- // Type is a known attribute but we do not currently use it and it is
- // not required.
+ type = attr_value;
} else {
LLDB_LOG(
log,
@@ -4254,14 +4366,55 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node,
});
if (name && start && end) {
- if (*start > *end) {
+ if (*start > *end)
LLDB_LOG(
log,
"ProcessGDBRemote::ParseFlagsFields Start {0} > end {1} in field "
"\"{2}\", ignoring",
*start, *end, name->data());
- } else {
- fields.push_back(RegisterFlags::Field(name->str(), *start, *end));
+ else {
+ if (RegisterFlags::Field::GetSizeInBits(*start, *end) > 64)
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlagsFields Ignoring field \"{2}\" "
+ "that has "
+ "size > 64 bits, this is not supported",
+ name->data());
+ else {
+ // A field's type may be set to the name of an enum type.
+ const FieldEnum *enum_type = nullptr;
+ if (type && !type->empty()) {
+ auto found = registers_enum_types.find(*type);
+ if (found != registers_enum_types.end()) {
+ enum_type = found->second.get();
+
+ // No enumerator can exceed the range of the field itself.
+ uint64_t max_value =
+ RegisterFlags::Field::GetMaxValue(*start, *end);
+ for (const auto &enumerator : enum_type->GetEnumerators()) {
+ if (enumerator.m_value > max_value) {
+ enum_type = nullptr;
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlagsFields In enum \"{0}\" "
+ "evalue \"{1}\" with value {2} exceeds the maximum value "
+ "of field \"{3}\" ({4}), ignoring enum",
+ type->data(), enumerator.m_name, enumerator.m_value,
+ name->data(), max_value);
+ break;
+ }
+ }
+ } else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlagsFields Could not find type "
+ "\"{0}\" "
+ "for field \"{1}\", ignoring",
+ type->data(), name->data());
+ }
+ }
+
+ fields.push_back(
+ RegisterFlags::Field(name->str(), *start, *end, enum_type));
+ }
}
}
@@ -4272,12 +4425,14 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node,
void ParseFlags(
XMLNode feature_node,
- llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types) {
+ llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types,
+ const llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {
Log *log(GetLog(GDBRLog::Process));
feature_node.ForEachChildElementWithName(
"flags",
- [&log, &registers_flags_types](const XMLNode &flags_node) -> bool {
+ [&log, &registers_flags_types,
+ &registers_enum_types](const XMLNode &flags_node) -> bool {
LLDB_LOG(log, "ProcessGDBRemote::ParseFlags Found flags node \"{0}\"",
flags_node.GetAttributeValue("id").c_str());
@@ -4310,7 +4465,7 @@ void ParseFlags(
if (id && size) {
// Process the fields of this set of flags.
std::vector<RegisterFlags::Field> fields =
- ParseFlagsFields(flags_node, *size);
+ ParseFlagsFields(flags_node, *size, registers_enum_types);
if (fields.size()) {
// Sort so that the fields with the MSBs are first.
std::sort(fields.rbegin(), fields.rend());
@@ -4375,15 +4530,21 @@ void ParseFlags(
bool ParseRegisters(
XMLNode feature_node, GdbServerTargetInfo &target_info,
std::vector<DynamicRegisterInfo::Register> &registers,
- llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types) {
+ llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types,
+ llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {
if (!feature_node)
return false;
Log *log(GetLog(GDBRLog::Process));
- ParseFlags(feature_node, registers_flags_types);
+ // Enums first because they are referenced by fields in the flags.
+ ParseEnums(feature_node, registers_enum_types);
+ for (const auto &enum_type : registers_enum_types)
+ enum_type.second->DumpToLog(log);
+
+ ParseFlags(feature_node, registers_flags_types, registers_enum_types);
for (const auto &flags : registers_flags_types)
- flags.second->log(log);
+ flags.second->DumpToLog(log);
feature_node.ForEachChildElementWithName(
"reg",
@@ -4643,7 +4804,7 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
if (arch_to_use.IsValid()) {
for (auto &feature_node : feature_nodes) {
ParseRegisters(feature_node, target_info, registers,
- m_registers_flags_types);
+ m_registers_flags_types, m_registers_enum_types);
}
for (const auto &include : target_info.includes) {
@@ -4708,13 +4869,14 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
if (!m_gdb_comm.GetQXferFeaturesReadSupported())
return false;
- // This holds register flags information for the whole of target.xml.
+ // These hold register type information for the whole of target.xml.
// target.xml may include further documents that
// GetGDBServerRegisterInfoXMLAndProcess will recurse to fetch and process.
// That's why we clear the cache here, and not in
// GetGDBServerRegisterInfoXMLAndProcess. To prevent it being cleared on every
// include read.
m_registers_flags_types.clear();
+ m_registers_enum_types.clear();
std::vector<DynamicRegisterInfo::Register> registers;
if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml",
registers))
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 610a1ee0b34d..b44ffefcd0d3 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -484,6 +484,11 @@ private:
// entries are added. Which would invalidate any pointers set in the register
// info up to that point.
llvm::StringMap<std::unique_ptr<RegisterFlags>> m_registers_flags_types;
+
+ // Enum types are referenced by register fields. This does not store the data
+ // directly because the map may reallocate. Pointers to these are contained
+ // within instances of RegisterFlags.
+ llvm::StringMap<std::unique_ptr<FieldEnum>> m_registers_enum_types;
};
} // namespace process_gdb_remote
diff --git a/lldb/source/Plugins/REPL/Clang/ClangREPL.cpp b/lldb/source/Plugins/REPL/Clang/ClangREPL.cpp
index 0aaddad53126..0fb5490defc6 100644
--- a/lldb/source/Plugins/REPL/Clang/ClangREPL.cpp
+++ b/lldb/source/Plugins/REPL/Clang/ClangREPL.cpp
@@ -95,7 +95,9 @@ bool ClangREPL::PrintOneVariable(Debugger &debugger,
if (m_implicit_expr_result_regex.Execute(var->GetName().GetStringRef()))
return true;
}
- valobj_sp->Dump(*output_sp);
+ if (llvm::Error error = valobj_sp->Dump(*output_sp))
+ *output_sp << "error: " << toString(std::move(error));
+
return true;
}
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index 067768537c06..a088a8742718 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -43,8 +43,7 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
ScratchTypeSystemClang::GetForTarget(m_target);
assert(type_system);
- std::string register_type_name = "__lldb_register_fields_";
- register_type_name += name;
+ std::string register_type_name = "__lldb_register_fields_" + name;
// See if we have made this type before and can reuse it.
CompilerType fields_type =
type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
@@ -67,8 +66,43 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
// We assume that RegisterFlags has padded and sorted the fields
// already.
for (const RegisterFlags::Field &field : flags.GetFields()) {
+ CompilerType field_type = field_uint_type;
+
+ if (const FieldEnum *enum_type = field.GetEnum()) {
+ const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators();
+ if (!enumerators.empty()) {
+ std::string enum_type_name =
+ "__lldb_register_fields_enum_" + enum_type->GetID();
+
+ // Enums can be used by mutiple fields and multiple registers, so we
+ // may have built this one already.
+ CompilerType field_enum_type =
+ type_system->GetTypeForIdentifier<clang::EnumDecl>(
+ enum_type_name);
+
+ if (field_enum_type)
+ field_type = field_enum_type;
+ else {
+ field_type = type_system->CreateEnumerationType(
+ enum_type_name, type_system->GetTranslationUnitDecl(),
+ OptionalClangModuleID(), Declaration(), field_uint_type, false);
+
+ type_system->StartTagDeclarationDefinition(field_type);
+
+ Declaration decl;
+ for (auto enumerator : enumerators) {
+ type_system->AddEnumerationValueToEnumerationType(
+ field_type, decl, enumerator.m_name.c_str(),
+ enumerator.m_value, byte_size * 8);
+ }
+
+ type_system->CompleteTagDeclarationDefinition(field_type);
+ }
+ }
+ }
+
type_system->AddFieldToRecordType(fields_type, field.GetName(),
- field_uint_type, lldb::eAccessPublic,
+ field_type, lldb::eAccessPublic,
field.GetSizeInBits());
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
index b22abc49c92a..c60e4bb503a3 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
@@ -24,6 +24,7 @@ add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces
ScriptedPythonInterface.cpp
ScriptedProcessPythonInterface.cpp
ScriptedThreadPythonInterface.cpp
+ ScriptedThreadPlanPythonInterface.cpp
ScriptedPlatformPythonInterface.cpp
LINK_LIBS
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp
index 9ba4731032bd..6e93bec80056 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp
@@ -20,6 +20,8 @@
#include "../ScriptInterpreterPythonImpl.h"
#include "ScriptedPlatformPythonInterface.h"
+#include "lldb/Target/ExecutionContext.h"
+
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::python;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp
index e86b34d6b930..313c597ce48f 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp
@@ -49,7 +49,8 @@ StructuredData::DictionarySP ScriptedProcessPythonInterface::GetCapabilities() {
StructuredData::DictionarySP dict =
Dispatch<StructuredData::DictionarySP>("get_capabilities", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
+ error))
return {};
return dict;
@@ -90,7 +91,8 @@ StructuredData::DictionarySP ScriptedProcessPythonInterface::GetThreadsInfo() {
StructuredData::DictionarySP dict =
Dispatch<StructuredData::DictionarySP>("get_threads_info", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
+ error))
return {};
return dict;
@@ -106,7 +108,8 @@ bool ScriptedProcessPythonInterface::CreateBreakpoint(lldb::addr_t addr,
if (py_error.Fail())
error = py_error;
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return {};
return obj->GetBooleanValue();
@@ -131,7 +134,8 @@ lldb::offset_t ScriptedProcessPythonInterface::WriteMemoryAtAddress(
StructuredData::ObjectSP obj =
Dispatch("write_memory_at_address", py_error, addr, data_sp, error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return LLDB_INVALID_OFFSET;
// If there was an error on the python call, surface it to the user.
@@ -146,7 +150,8 @@ StructuredData::ArraySP ScriptedProcessPythonInterface::GetLoadedImages() {
StructuredData::ArraySP array =
Dispatch<StructuredData::ArraySP>("get_loaded_images", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, array, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, array,
+ error))
return {};
return array;
@@ -156,7 +161,8 @@ lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() {
Status error;
StructuredData::ObjectSP obj = Dispatch("get_process_id", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return LLDB_INVALID_PROCESS_ID;
return obj->GetUnsignedIntegerValue(LLDB_INVALID_PROCESS_ID);
@@ -166,7 +172,8 @@ bool ScriptedProcessPythonInterface::IsAlive() {
Status error;
StructuredData::ObjectSP obj = Dispatch("is_alive", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return {};
return obj->GetBooleanValue();
@@ -177,7 +184,8 @@ ScriptedProcessPythonInterface::GetScriptedThreadPluginName() {
Status error;
StructuredData::ObjectSP obj = Dispatch("get_scripted_thread_plugin", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return {};
return obj->GetStringValue().str();
@@ -193,7 +201,8 @@ StructuredData::DictionarySP ScriptedProcessPythonInterface::GetMetadata() {
StructuredData::DictionarySP dict =
Dispatch<StructuredData::DictionarySP>("get_process_metadata", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
+ error))
return {};
return dict;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index 6f22503b279c..7d072212676e 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -27,6 +27,15 @@ ScriptedPythonInterface::ScriptedPythonInterface(
: ScriptedInterface(), m_interpreter(interpreter) {}
template <>
+void ScriptedPythonInterface::ReverseTransform(
+ lldb_private::Stream *&original_arg, python::PythonObject transformed_arg,
+ Status &error) {
+ Stream *s = ExtractValueFromPythonObject<Stream *>(transformed_arg, error);
+ *original_arg = *s;
+ original_arg->PutCString(static_cast<StreamString *>(s)->GetData());
+}
+
+template <>
StructuredData::ArraySP
ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
python::PythonObject &p, Status &error) {
@@ -48,13 +57,34 @@ Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
if (lldb::SBError *sb_error = reinterpret_cast<lldb::SBError *>(
python::LLDBSWIGPython_CastPyObjectToSBError(p.get())))
return m_interpreter.GetStatusFromSBError(*sb_error);
- else
- error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status.");
+ error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status.");
return {};
}
template <>
+Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
+ python::PythonObject &p, Status &error) {
+ if (lldb::SBEvent *sb_event = reinterpret_cast<lldb::SBEvent *>(
+ python::LLDBSWIGPython_CastPyObjectToSBEvent(p.get())))
+ return m_interpreter.GetOpaqueTypeFromSBEvent(*sb_event);
+ error.SetErrorString("Couldn't cast lldb::SBEvent to lldb_private::Event.");
+
+ return nullptr;
+}
+
+template <>
+Stream *ScriptedPythonInterface::ExtractValueFromPythonObject<Stream *>(
+ python::PythonObject &p, Status &error) {
+ if (lldb::SBStream *sb_stream = reinterpret_cast<lldb::SBStream *>(
+ python::LLDBSWIGPython_CastPyObjectToSBStream(p.get())))
+ return m_interpreter.GetOpaqueTypeFromSBStream(*sb_stream);
+ error.SetErrorString("Couldn't cast lldb::SBStream to lldb_private::Stream.");
+
+ return nullptr;
+}
+
+template <>
lldb::DataExtractorSP
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
python::PythonObject &p, Status &error) {
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index 163659234466..062bf1fcff4a 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -115,7 +115,7 @@ public:
PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
class_name, dict);
if (!init.IsAllocated())
- return create_error(llvm::formatv("Could not find script class: %s",
+ return create_error(llvm::formatv("Could not find script class: {0}",
class_name.data()));
std::tuple<Args...> original_args = std::forward_as_tuple(args...);
@@ -248,8 +248,11 @@ protected:
(PyObject *)m_object_instance_sp->GetValue());
if (!implementor.IsAllocated())
- return ErrorWithMessage<T>(caller_signature,
- "Python implementor not allocated.", error);
+ return llvm::is_contained(GetAbstractMethods(), method_name)
+ ? ErrorWithMessage<T>(caller_signature,
+ "Python implementor not allocated.",
+ error)
+ : T{};
std::tuple<Args...> original_args = std::forward_as_tuple(args...);
auto transformed_args = TransformArgs(original_args);
@@ -322,6 +325,10 @@ protected:
return python::SWIGBridge::ToSWIGWrapper(arg);
}
+ python::PythonObject Transform(lldb::ThreadPlanSP arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) {
return python::SWIGBridge::ToSWIGWrapper(arg);
}
@@ -330,6 +337,14 @@ protected:
return python::SWIGBridge::ToSWIGWrapper(arg);
}
+ python::PythonObject Transform(Event *arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
+ python::PythonObject Transform(Stream *arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
python::PythonObject Transform(lldb::DataExtractorSP arg) {
return python::SWIGBridge::ToSWIGWrapper(arg);
}
@@ -428,6 +443,14 @@ Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
python::PythonObject &p, Status &error);
template <>
+Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
+ python::PythonObject &p, Status &error);
+
+template <>
+Stream *ScriptedPythonInterface::ExtractValueFromPythonObject<Stream *>(
+ python::PythonObject &p, Status &error);
+
+template <>
lldb::BreakpointSP
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
python::PythonObject &p, Status &error);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp
new file mode 100644
index 000000000000..b7e475812f22
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp
@@ -0,0 +1,105 @@
+//===-- ScriptedThreadPlanPythonInterface.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/Host/Config.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/lldb-enumerations.h"
+
+#if LLDB_ENABLE_PYTHON
+
+// LLDB Python header must be included first
+#include "../lldb-python.h"
+
+#include "../SWIGPythonBridge.h"
+#include "../ScriptInterpreterPythonImpl.h"
+#include "ScriptedThreadPlanPythonInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+
+ScriptedThreadPlanPythonInterface::ScriptedThreadPlanPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedThreadPlanInterface(), ScriptedPythonInterface(interpreter) {}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedThreadPlanPythonInterface::CreatePluginObject(
+ const llvm::StringRef class_name, lldb::ThreadPlanSP thread_plan_sp,
+ const StructuredDataImpl &args_sp) {
+ return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr,
+ thread_plan_sp, args_sp);
+}
+
+llvm::Expected<bool>
+ScriptedThreadPlanPythonInterface::ExplainsStop(Event *event) {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("explains_stop", error, event);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error)) {
+ if (!obj)
+ return false;
+ return error.ToError();
+ }
+
+ return obj->GetBooleanValue();
+}
+
+llvm::Expected<bool>
+ScriptedThreadPlanPythonInterface::ShouldStop(Event *event) {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("should_stop", error, event);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error)) {
+ if (!obj)
+ return false;
+ return error.ToError();
+ }
+
+ return obj->GetBooleanValue();
+}
+
+llvm::Expected<bool> ScriptedThreadPlanPythonInterface::IsStale() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_stale", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error)) {
+ if (!obj)
+ return false;
+ return error.ToError();
+ }
+
+ return obj->GetBooleanValue();
+}
+
+lldb::StateType ScriptedThreadPlanPythonInterface::GetRunState() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("should_step", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return lldb::eStateStepping;
+
+ return static_cast<lldb::StateType>(obj->GetUnsignedIntegerValue(
+ static_cast<uint32_t>(lldb::eStateStepping)));
+}
+
+llvm::Expected<bool>
+ScriptedThreadPlanPythonInterface::GetStopDescription(lldb_private::Stream *s) {
+ Status error;
+ Dispatch("stop_description", error, s);
+
+ if (error.Fail())
+ return error.ToError();
+
+ return true;
+}
+
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h
new file mode 100644
index 000000000000..33f086786c47
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h
@@ -0,0 +1,48 @@
+//===-- ScriptedThreadPlanPythonInterface.h ---------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPLANPYTHONINTERFACE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPLANPYTHONINTERFACE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "ScriptedPythonInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h"
+#include <optional>
+
+namespace lldb_private {
+class ScriptedThreadPlanPythonInterface : public ScriptedThreadPlanInterface,
+ public ScriptedPythonInterface {
+public:
+ ScriptedThreadPlanPythonInterface(ScriptInterpreterPythonImpl &interpreter);
+
+ llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(const llvm::StringRef class_name,
+ lldb::ThreadPlanSP thread_plan_sp,
+ const StructuredDataImpl &args_sp) override;
+
+ llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override {
+ return {};
+ }
+
+ llvm::Expected<bool> ExplainsStop(Event *event) override;
+
+ llvm::Expected<bool> ShouldStop(Event *event) override;
+
+ llvm::Expected<bool> IsStale() override;
+
+ lldb::StateType GetRunState() override;
+
+ llvm::Expected<bool> GetStopDescription(lldb_private::Stream *s) override;
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPLANPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
index 18e268527eb2..8af89d761764 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/Config.h"
+#include "lldb/Target/ExecutionContext.h"
#include "lldb/Utility/Log.h"
#include "lldb/lldb-enumerations.h"
@@ -44,7 +45,8 @@ lldb::tid_t ScriptedThreadPythonInterface::GetThreadID() {
Status error;
StructuredData::ObjectSP obj = Dispatch("get_thread_id", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return LLDB_INVALID_THREAD_ID;
return obj->GetUnsignedIntegerValue(LLDB_INVALID_THREAD_ID);
@@ -54,7 +56,8 @@ std::optional<std::string> ScriptedThreadPythonInterface::GetName() {
Status error;
StructuredData::ObjectSP obj = Dispatch("get_name", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return {};
return obj->GetStringValue().str();
@@ -64,7 +67,8 @@ lldb::StateType ScriptedThreadPythonInterface::GetState() {
Status error;
StructuredData::ObjectSP obj = Dispatch("get_state", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return eStateInvalid;
return static_cast<StateType>(obj->GetUnsignedIntegerValue(eStateInvalid));
@@ -74,7 +78,8 @@ std::optional<std::string> ScriptedThreadPythonInterface::GetQueue() {
Status error;
StructuredData::ObjectSP obj = Dispatch("get_queue", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return {};
return obj->GetStringValue().str();
@@ -85,7 +90,8 @@ StructuredData::DictionarySP ScriptedThreadPythonInterface::GetStopReason() {
StructuredData::DictionarySP dict =
Dispatch<StructuredData::DictionarySP>("get_stop_reason", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
+ error))
return {};
return dict;
@@ -96,7 +102,8 @@ StructuredData::ArraySP ScriptedThreadPythonInterface::GetStackFrames() {
StructuredData::ArraySP arr =
Dispatch<StructuredData::ArraySP>("get_stackframes", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr,
+ error))
return {};
return arr;
@@ -107,7 +114,8 @@ StructuredData::DictionarySP ScriptedThreadPythonInterface::GetRegisterInfo() {
StructuredData::DictionarySP dict =
Dispatch<StructuredData::DictionarySP>("get_register_info", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
+ error))
return {};
return dict;
@@ -117,7 +125,8 @@ std::optional<std::string> ScriptedThreadPythonInterface::GetRegisterContext() {
Status error;
StructuredData::ObjectSP obj = Dispatch("get_register_context", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
return {};
return obj->GetAsString()->GetValue().str();
@@ -128,7 +137,8 @@ StructuredData::ArraySP ScriptedThreadPythonInterface::GetExtendedInfo() {
StructuredData::ArraySP arr =
Dispatch<StructuredData::ArraySP>("get_extended_info", error);
- if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, error))
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr,
+ error))
return {};
return arr;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index c1a11b9134d6..95eb5a782097 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -97,12 +97,14 @@ public:
static PythonObject ToSWIGWrapper(lldb::ExecutionContextRefSP ctx_sp);
static PythonObject ToSWIGWrapper(const TypeSummaryOptions &summary_options);
static PythonObject ToSWIGWrapper(const SymbolContext &sym_ctx);
+ static PythonObject ToSWIGWrapper(const Stream *stream);
+ static PythonObject ToSWIGWrapper(std::shared_ptr<lldb::SBStream> stream_sb);
+ static PythonObject ToSWIGWrapper(Event *event);
static PythonObject ToSWIGWrapper(lldb::ProcessAttachInfoSP attach_info_sp);
static PythonObject ToSWIGWrapper(lldb::ProcessLaunchInfoSP launch_info_sp);
static PythonObject ToSWIGWrapper(lldb::DataExtractorSP data_extractor_sp);
- static PythonObject ToSWIGWrapper(std::unique_ptr<lldb::SBStream> stream_sb);
static PythonObject
ToSWIGWrapper(std::unique_ptr<lldb::SBStructuredData> data_sb);
static PythonObject
@@ -112,7 +114,6 @@ public:
static python::ScopedPythonObject<lldb::SBCommandReturnObject>
ToSWIGWrapper(CommandReturnObject &cmd_retobj);
- static python::ScopedPythonObject<lldb::SBEvent> ToSWIGWrapper(Event *event);
// These prototypes are the Pythonic implementations of the required
// callbacks. Although these are scripting-language specific, their definition
// depends on the public API.
@@ -147,21 +148,6 @@ public:
const char *session_dictionary_name,
lldb::DebuggerSP debugger_sp);
- static python::PythonObject LLDBSwigPythonCreateScriptedThreadPlan(
- const char *python_class_name, const char *session_dictionary_name,
- const StructuredDataImpl &args_data, std::string &error_string,
- const lldb::ThreadPlanSP &thread_plan_sp);
-
- static bool LLDBSWIGPythonCallThreadPlan(void *implementor,
- const char *method_name,
- lldb_private::Event *event_sp,
- bool &got_error);
-
- static bool LLDBSWIGPythonCallThreadPlan(void *implementor,
- const char *method_name,
- lldb_private::Stream *stream,
- bool &got_error);
-
static python::PythonObject LLDBSwigPythonCreateScriptedBreakpointResolver(
const char *python_class_name, const char *session_dictionary_name,
const StructuredDataImpl &args, const lldb::BreakpointSP &bkpt_sp);
@@ -269,6 +255,8 @@ void *LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data);
} // namespace python
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 6e676de146b3..70c9f9475441 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -17,6 +17,7 @@
#include "Interfaces/OperatingSystemPythonInterface.h"
#include "Interfaces/ScriptedPlatformPythonInterface.h"
#include "Interfaces/ScriptedProcessPythonInterface.h"
+#include "Interfaces/ScriptedThreadPlanPythonInterface.h"
#include "Interfaces/ScriptedThreadPythonInterface.h"
#include "PythonDataObjects.h"
#include "PythonReadline.h"
@@ -1537,6 +1538,11 @@ ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() {
return std::make_shared<ScriptedThreadPythonInterface>(*this);
}
+ScriptedThreadPlanInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedThreadPlanInterface() {
+ return std::make_shared<ScriptedThreadPlanPythonInterface>(*this);
+}
+
OperatingSystemInterfaceSP
ScriptInterpreterPythonImpl::CreateOperatingSystemInterface() {
return std::make_shared<OperatingSystemPythonInterface>(*this);
@@ -1553,122 +1559,6 @@ ScriptInterpreterPythonImpl::CreateStructuredDataFromScriptObject(
return py_obj.CreateStructuredObject();
}
-StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan(
- const char *class_name, const StructuredDataImpl &args_data,
- std::string &error_str, lldb::ThreadPlanSP thread_plan_sp) {
- if (class_name == nullptr || class_name[0] == '\0')
- return StructuredData::ObjectSP();
-
- if (!thread_plan_sp.get())
- return {};
-
- Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger();
- ScriptInterpreterPythonImpl *python_interpreter =
- GetPythonInterpreter(debugger);
-
- if (!python_interpreter)
- return {};
-
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedThreadPlan(
- class_name, python_interpreter->m_dictionary_name.c_str(), args_data,
- error_str, thread_plan_sp);
- if (!ret_val)
- return {};
-
- return StructuredData::ObjectSP(
- new StructuredPythonObject(std::move(ret_val)));
-}
-
-bool ScriptInterpreterPythonImpl::ScriptedThreadPlanExplainsStop(
- StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) {
- bool explains_stop = true;
- StructuredData::Generic *generic = nullptr;
- if (implementor_sp)
- generic = implementor_sp->GetAsGeneric();
- if (generic) {
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- explains_stop = SWIGBridge::LLDBSWIGPythonCallThreadPlan(
- generic->GetValue(), "explains_stop", event, script_error);
- if (script_error)
- return true;
- }
- return explains_stop;
-}
-
-bool ScriptInterpreterPythonImpl::ScriptedThreadPlanShouldStop(
- StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) {
- bool should_stop = true;
- StructuredData::Generic *generic = nullptr;
- if (implementor_sp)
- generic = implementor_sp->GetAsGeneric();
- if (generic) {
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- should_stop = SWIGBridge::LLDBSWIGPythonCallThreadPlan(
- generic->GetValue(), "should_stop", event, script_error);
- if (script_error)
- return true;
- }
- return should_stop;
-}
-
-bool ScriptInterpreterPythonImpl::ScriptedThreadPlanIsStale(
- StructuredData::ObjectSP implementor_sp, bool &script_error) {
- bool is_stale = true;
- StructuredData::Generic *generic = nullptr;
- if (implementor_sp)
- generic = implementor_sp->GetAsGeneric();
- if (generic) {
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- is_stale = SWIGBridge::LLDBSWIGPythonCallThreadPlan(
- generic->GetValue(), "is_stale", (Event *)nullptr, script_error);
- if (script_error)
- return true;
- }
- return is_stale;
-}
-
-lldb::StateType ScriptInterpreterPythonImpl::ScriptedThreadPlanGetRunState(
- StructuredData::ObjectSP implementor_sp, bool &script_error) {
- bool should_step = false;
- StructuredData::Generic *generic = nullptr;
- if (implementor_sp)
- generic = implementor_sp->GetAsGeneric();
- if (generic) {
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- should_step = SWIGBridge::LLDBSWIGPythonCallThreadPlan(
- generic->GetValue(), "should_step", (Event *)nullptr, script_error);
- if (script_error)
- should_step = true;
- }
- if (should_step)
- return lldb::eStateStepping;
- return lldb::eStateRunning;
-}
-
-bool
-ScriptInterpreterPythonImpl::ScriptedThreadPlanGetStopDescription(
- StructuredData::ObjectSP implementor_sp, lldb_private::Stream *stream,
- bool &script_error) {
- StructuredData::Generic *generic = nullptr;
- if (implementor_sp)
- generic = implementor_sp->GetAsGeneric();
- if (!generic) {
- script_error = true;
- return false;
- }
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- return SWIGBridge::LLDBSWIGPythonCallThreadPlan(
- generic->GetValue(), "stop_description", stream, script_error);
-}
-
-
StructuredData::GenericSP
ScriptInterpreterPythonImpl::CreateScriptedBreakpointResolver(
const char *class_name, const StructuredDataImpl &args_data,
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index fcd21dff612b..fa2354053473 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -78,33 +78,8 @@ public:
CreateScriptCommandObject(const char *class_name) override;
StructuredData::ObjectSP
- CreateScriptedThreadPlan(const char *class_name,
- const StructuredDataImpl &args_data,
- std::string &error_str,
- lldb::ThreadPlanSP thread_plan) override;
-
- StructuredData::ObjectSP
CreateStructuredDataFromScriptObject(ScriptObject obj) override;
- bool ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp,
- Event *event,
- bool &script_error) override;
-
- bool ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp,
- Event *event, bool &script_error) override;
-
- bool ScriptedThreadPlanIsStale(StructuredData::ObjectSP implementor_sp,
- bool &script_error) override;
-
- lldb::StateType
- ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp,
- bool &script_error) override;
-
- bool
- ScriptedThreadPlanGetStopDescription(StructuredData::ObjectSP implementor_sp,
- lldb_private::Stream *s,
- bool &script_error) override;
-
StructuredData::GenericSP
CreateScriptedBreakpointResolver(const char *class_name,
const StructuredDataImpl &args_data,
@@ -136,6 +111,9 @@ public:
lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
+ lldb::ScriptedThreadPlanInterfaceSP
+ CreateScriptedThreadPlanInterface() override;
+
lldb::OperatingSystemInterfaceSP CreateOperatingSystemInterface() override;
StructuredData::ObjectSP
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
index 66db396279e0..abaeb2502cbb 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
@@ -58,7 +58,7 @@ public:
virtual void EnsureAllDIEsInDeclContextHaveBeenParsed(
CompilerDeclContext decl_context) = 0;
- virtual ConstString GetDIEClassTemplateParams(const DWARFDIE &die) = 0;
+ virtual std::string GetDIEClassTemplateParams(const DWARFDIE &die) = 0;
static std::optional<SymbolFile::ArrayInfo>
ParseChildArrayInfo(const DWARFDIE &parent_die,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 579a538af363..f36e2af9589b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -23,6 +23,7 @@
#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/Progress.h"
#include "lldb/Core/Value.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/CompileUnit.h"
@@ -38,10 +39,12 @@
#include "lldb/Utility/StreamString.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Type.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
#include <map>
@@ -222,7 +225,6 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid,
&pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward,
TypePayloadClang(GetOwningClangModule(die)));
- dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
clang::TagDecl *tag_decl = TypeSystemClang::GetAsTagDecl(type);
if (tag_decl) {
LinkDeclContextToDIE(tag_decl, die);
@@ -457,90 +459,78 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
DW_TAG_value_to_name(die.Tag()), die.Tag(), die.GetName());
}
- Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE());
- if (type_ptr == DIE_IS_BEING_PARSED)
- return nullptr;
- if (type_ptr)
- return type_ptr->shared_from_this();
// Set a bit that lets us know that we are currently parsing this
- dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED;
+ if (auto [it, inserted] =
+ dwarf->GetDIEToType().try_emplace(die.GetDIE(), DIE_IS_BEING_PARSED);
+ !inserted) {
+ if (it->getSecond() == nullptr || it->getSecond() == DIE_IS_BEING_PARSED)
+ return nullptr;
+ return it->getSecond()->shared_from_this();
+ }
ParsedDWARFTypeAttributes attrs(die);
+ TypeSP type_sp;
if (DWARFDIE signature_die = attrs.signature.Reference()) {
- if (TypeSP type_sp =
- ParseTypeFromDWARF(sc, signature_die, type_is_new_ptr)) {
- dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+ type_sp = ParseTypeFromDWARF(sc, signature_die, type_is_new_ptr);
+ if (type_sp) {
if (clang::DeclContext *decl_ctx =
GetCachedClangDeclContextForDIE(signature_die))
LinkDeclContextToDIE(decl_ctx, die);
- return type_sp;
}
- return nullptr;
- }
-
- if (type_is_new_ptr)
- *type_is_new_ptr = true;
-
- const dw_tag_t tag = die.Tag();
-
- TypeSP type_sp;
-
- switch (tag) {
- case DW_TAG_typedef:
- case DW_TAG_base_type:
- case DW_TAG_pointer_type:
- case DW_TAG_reference_type:
- case DW_TAG_rvalue_reference_type:
- case DW_TAG_const_type:
- case DW_TAG_restrict_type:
- case DW_TAG_volatile_type:
- case DW_TAG_LLVM_ptrauth_type:
- case DW_TAG_atomic_type:
- case DW_TAG_unspecified_type: {
- type_sp = ParseTypeModifier(sc, die, attrs);
- break;
- }
-
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_class_type: {
- type_sp = ParseStructureLikeDIE(sc, die, attrs);
- break;
- }
+ } else {
+ if (type_is_new_ptr)
+ *type_is_new_ptr = true;
- case DW_TAG_enumeration_type: {
- type_sp = ParseEnum(sc, die, attrs);
- break;
- }
+ const dw_tag_t tag = die.Tag();
- case DW_TAG_inlined_subroutine:
- case DW_TAG_subprogram:
- case DW_TAG_subroutine_type: {
- type_sp = ParseSubroutine(die, attrs);
- break;
- }
- case DW_TAG_array_type: {
- type_sp = ParseArrayType(die, attrs);
- break;
- }
- case DW_TAG_ptr_to_member_type: {
- type_sp = ParsePointerToMemberType(die, attrs);
- break;
+ switch (tag) {
+ case DW_TAG_typedef:
+ case DW_TAG_base_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_LLVM_ptrauth_type:
+ case DW_TAG_atomic_type:
+ case DW_TAG_unspecified_type:
+ type_sp = ParseTypeModifier(sc, die, attrs);
+ break;
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ type_sp = ParseStructureLikeDIE(sc, die, attrs);
+ break;
+ case DW_TAG_enumeration_type:
+ type_sp = ParseEnum(sc, die, attrs);
+ break;
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ type_sp = ParseSubroutine(die, attrs);
+ break;
+ case DW_TAG_array_type:
+ type_sp = ParseArrayType(die, attrs);
+ break;
+ case DW_TAG_ptr_to_member_type:
+ type_sp = ParsePointerToMemberType(die, attrs);
+ break;
+ default:
+ dwarf->GetObjectFile()->GetModule()->ReportError(
+ "[{0:x16}]: unhandled type tag {1:x4} ({2}), "
+ "please file a bug and "
+ "attach the file at the start of this error message",
+ die.GetOffset(), tag, DW_TAG_value_to_name(tag));
+ break;
+ }
+ UpdateSymbolContextScopeForType(sc, die, type_sp);
}
- default:
- dwarf->GetObjectFile()->GetModule()->ReportError(
- "[{0:x16}]: unhandled type tag {1:x4} ({2}), "
- "please file a bug and "
- "attach the file at the start of this error message",
- die.GetOffset(), tag, DW_TAG_value_to_name(tag));
- break;
+ if (type_sp) {
+ dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
}
-
- // TODO: We should consider making the switch above exhaustive to simplify
- // control flow in ParseTypeFromDWARF. Then, we could simply replace this
- // return statement with a call to llvm_unreachable.
- return UpdateSymbolContextScopeForType(sc, die, type_sp);
+ return type_sp;
}
static std::optional<uint32_t>
@@ -829,78 +819,68 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
}
}
- type_sp = dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr,
- attrs.type.Reference().GetID(), encoding_data_type,
- &attrs.decl, clang_type, resolve_state, payload);
-
- dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
- return type_sp;
+ return dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr,
+ attrs.type.Reference().GetID(), encoding_data_type,
+ &attrs.decl, clang_type, resolve_state, payload);
}
-ConstString
+std::string
DWARFASTParserClang::GetDIEClassTemplateParams(const DWARFDIE &die) {
if (llvm::StringRef(die.GetName()).contains("<"))
- return ConstString();
+ return {};
TypeSystemClang::TemplateParameterInfos template_param_infos;
- if (ParseTemplateParameterInfos(die, template_param_infos)) {
- return ConstString(m_ast.PrintTemplateParams(template_param_infos));
- }
- return ConstString();
+ if (ParseTemplateParameterInfos(die, template_param_infos))
+ return m_ast.PrintTemplateParams(template_param_infos);
+
+ return {};
}
TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc,
- const DWARFDIE &die,
+ const DWARFDIE &decl_die,
ParsedDWARFTypeAttributes &attrs) {
Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
- SymbolFileDWARF *dwarf = die.GetDWARF();
- const dw_tag_t tag = die.Tag();
- TypeSP type_sp;
+ SymbolFileDWARF *dwarf = decl_die.GetDWARF();
+ const dw_tag_t tag = decl_die.Tag();
+ DWARFDIE def_die;
if (attrs.is_forward_declaration) {
- type_sp = ParseTypeFromClangModule(sc, die, log);
- if (type_sp)
+ if (TypeSP type_sp = ParseTypeFromClangModule(sc, decl_die, log))
return type_sp;
- type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die);
+ def_die = dwarf->FindDefinitionDIE(decl_die);
- if (!type_sp) {
+ if (!def_die) {
SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile();
if (debug_map_symfile) {
// We weren't able to find a full declaration in this DWARF,
// see if we have a declaration anywhere else...
- type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext(die);
+ def_die = debug_map_symfile->FindDefinitionDIE(decl_die);
}
}
- if (type_sp) {
- if (log) {
- dwarf->GetObjectFile()->GetModule()->LogMessage(
- log,
- "SymbolFileDWARF({0:p}) - {1:x16}}: {2} ({3}) type \"{4}\" is a "
- "forward declaration, complete type is {5:x8}",
- static_cast<void *>(this), die.GetOffset(),
- DW_TAG_value_to_name(tag), tag, attrs.name.GetCString(),
- type_sp->GetID());
- }
-
- // We found a real definition for this type elsewhere so lets use
- // it and cache the fact that we found a complete type for this
- // die
- dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
- clang::DeclContext *defn_decl_ctx =
- GetCachedClangDeclContextForDIE(dwarf->GetDIE(type_sp->GetID()));
- if (defn_decl_ctx)
- LinkDeclContextToDIE(defn_decl_ctx, die);
- return type_sp;
+ if (log) {
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF({0:p}) - {1:x16}}: {2} ({3}) type \"{4}\" is a "
+ "forward declaration, complete DIE is {5}",
+ static_cast<void *>(this), decl_die.GetID(), DW_TAG_value_to_name(tag),
+ tag, attrs.name.GetCString(),
+ def_die ? llvm::utohexstr(def_die.GetID()) : "not found");
}
}
- DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
- DW_TAG_value_to_name(tag), type_name_cstr);
+ if (def_die) {
+ attrs = ParsedDWARFTypeAttributes(def_die);
+ } else {
+ // No definition found. Proceed with the declaration die. We can use it to
+ // create a forward-declared type.
+ def_die = decl_die;
+ }
CompilerType enumerator_clang_type;
if (attrs.type.IsValid()) {
- Type *enumerator_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true);
+ Type *enumerator_type =
+ dwarf->ResolveTypeUID(attrs.type.Reference(), true);
if (enumerator_type)
enumerator_clang_type = enumerator_type->GetFullCompilerType();
}
@@ -915,24 +895,31 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc,
}
CompilerType clang_type = m_ast.CreateEnumerationType(
- attrs.name.GetStringRef(), GetClangDeclContextContainingDIE(die, nullptr),
- GetOwningClangModule(die), attrs.decl, enumerator_clang_type,
+ attrs.name.GetStringRef(), GetClangDeclContextContainingDIE(def_die, nullptr),
+ GetOwningClangModule(def_die), attrs.decl, enumerator_clang_type,
attrs.is_scoped_enum);
-
- LinkDeclContextToDIE(TypeSystemClang::GetDeclContextForType(clang_type), die);
-
- type_sp =
- dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr,
+ TypeSP type_sp =
+ dwarf->MakeType(def_die.GetID(), attrs.name, attrs.byte_size, nullptr,
attrs.type.Reference().GetID(), Type::eEncodingIsUID,
&attrs.decl, clang_type, Type::ResolveState::Forward,
- TypePayloadClang(GetOwningClangModule(die)));
+ TypePayloadClang(GetOwningClangModule(def_die)));
+
+ clang::DeclContext *type_decl_ctx =
+ TypeSystemClang::GetDeclContextForType(clang_type);
+ LinkDeclContextToDIE(type_decl_ctx, decl_die);
+ if (decl_die != def_die) {
+ LinkDeclContextToDIE(type_decl_ctx, def_die);
+ dwarf->GetDIEToType()[def_die.GetDIE()] = type_sp.get();
+ // Declaration DIE is inserted into the type map in ParseTypeFromDWARF
+ }
+
if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) {
- if (die.HasChildren()) {
+ if (def_die.HasChildren()) {
bool is_signed = false;
enumerator_clang_type.IsIntegerType(is_signed);
ParseChildEnumerators(clang_type, is_signed,
- type_sp->GetByteSize(nullptr).value_or(0), die);
+ type_sp->GetByteSize(nullptr).value_or(0), def_die);
}
TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
} else {
@@ -940,7 +927,7 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc,
"DWARF DIE at {0:x16} named \"{1}\" was not able to start its "
"definition.\nPlease file a bug and attach the file at the "
"start of this error message",
- die.GetOffset(), attrs.name.GetCString());
+ def_die.GetOffset(), attrs.name.GetCString());
}
return type_sp;
}
@@ -975,6 +962,216 @@ ConvertDWARFCallingConventionToClang(const ParsedDWARFTypeAttributes &attrs) {
return clang::CC_C;
}
+bool DWARFASTParserClang::ParseObjCMethod(
+ const ObjCLanguage::MethodName &objc_method, const DWARFDIE &die,
+ CompilerType clang_type, const ParsedDWARFTypeAttributes &attrs,
+ bool is_variadic) {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ assert(dwarf);
+
+ const auto tag = die.Tag();
+ ConstString class_name(objc_method.GetClassName());
+ if (!class_name)
+ return false;
+
+ TypeSP complete_objc_class_type_sp =
+ dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(), class_name,
+ false);
+
+ if (!complete_objc_class_type_sp)
+ return false;
+
+ CompilerType type_clang_forward_type =
+ complete_objc_class_type_sp->GetForwardCompilerType();
+
+ if (!type_clang_forward_type)
+ return false;
+
+ if (!TypeSystemClang::IsObjCObjectOrInterfaceType(type_clang_forward_type))
+ return false;
+
+ clang::ObjCMethodDecl *objc_method_decl = m_ast.AddMethodToObjCObjectType(
+ type_clang_forward_type, attrs.name.GetCString(), clang_type,
+ attrs.is_artificial, is_variadic, attrs.is_objc_direct_call);
+
+ if (!objc_method_decl) {
+ dwarf->GetObjectFile()->GetModule()->ReportError(
+ "[{0:x16}]: invalid Objective-C method {1:x4} ({2}), "
+ "please file a bug and attach the file at the start of "
+ "this error message",
+ die.GetOffset(), tag, DW_TAG_value_to_name(tag));
+ return false;
+ }
+
+ LinkDeclContextToDIE(objc_method_decl, die);
+ m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID());
+
+ return true;
+}
+
+std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
+ const DWARFDIE &die, CompilerType clang_type,
+ const ParsedDWARFTypeAttributes &attrs, const DWARFDIE &decl_ctx_die,
+ bool is_static, bool &ignore_containing_context) {
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ assert(dwarf);
+
+ Type *class_type = dwarf->ResolveType(decl_ctx_die);
+ if (!class_type)
+ return {};
+
+ if (class_type->GetID() != decl_ctx_die.GetID() ||
+ IsClangModuleFwdDecl(decl_ctx_die)) {
+
+ // We uniqued the parent class of this function to another
+ // class so we now need to associate all dies under
+ // "decl_ctx_die" to DIEs in the DIE for "class_type"...
+ if (DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID())) {
+ std::vector<DWARFDIE> failures;
+
+ CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die, class_type,
+ failures);
+
+ // FIXME do something with these failures that's
+ // smarter than just dropping them on the ground.
+ // Unfortunately classes don't like having stuff added
+ // to them after their definitions are complete...
+
+ Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE());
+ if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
+ return {true, type_ptr->shared_from_this()};
+ }
+ }
+
+ if (attrs.specification.IsValid()) {
+ // We have a specification which we are going to base our
+ // function prototype off of, so we need this type to be
+ // completed so that the m_die_to_decl_ctx for the method in
+ // the specification has a valid clang decl context.
+ class_type->GetForwardCompilerType();
+ // If we have a specification, then the function type should
+ // have been made with the specification and not with this
+ // die.
+ DWARFDIE spec_die = attrs.specification.Reference();
+ clang::DeclContext *spec_clang_decl_ctx =
+ GetClangDeclContextForDIE(spec_die);
+ if (spec_clang_decl_ctx)
+ LinkDeclContextToDIE(spec_clang_decl_ctx, die);
+ else
+ dwarf->GetObjectFile()->GetModule()->ReportWarning(
+ "{0:x8}: DW_AT_specification({1:x16}"
+ ") has no decl\n",
+ die.GetID(), spec_die.GetOffset());
+
+ return {true, nullptr};
+ }
+
+ if (attrs.abstract_origin.IsValid()) {
+ // We have a specification which we are going to base our
+ // function prototype off of, so we need this type to be
+ // completed so that the m_die_to_decl_ctx for the method in
+ // the abstract origin has a valid clang decl context.
+ class_type->GetForwardCompilerType();
+
+ DWARFDIE abs_die = attrs.abstract_origin.Reference();
+ clang::DeclContext *abs_clang_decl_ctx = GetClangDeclContextForDIE(abs_die);
+ if (abs_clang_decl_ctx)
+ LinkDeclContextToDIE(abs_clang_decl_ctx, die);
+ else
+ dwarf->GetObjectFile()->GetModule()->ReportWarning(
+ "{0:x8}: DW_AT_abstract_origin({1:x16}"
+ ") has no decl\n",
+ die.GetID(), abs_die.GetOffset());
+
+ return {true, nullptr};
+ }
+
+ CompilerType class_opaque_type = class_type->GetForwardCompilerType();
+ if (!TypeSystemClang::IsCXXClassType(class_opaque_type))
+ return {};
+
+ if (class_opaque_type.IsBeingDefined()) {
+ // We have a C++ member function with no children (this
+ // pointer!) and clang will get mad if we try and make
+ // a function that isn't well formed in the DWARF, so
+ // we will just skip it...
+ if (!is_static && !die.HasChildren())
+ return {true, nullptr};
+
+ const bool is_attr_used = false;
+ // Neither GCC 4.2 nor clang++ currently set a valid
+ // accessibility in the DWARF for C++ methods...
+ // Default to public for now...
+ const auto accessibility = attrs.accessibility == eAccessNone
+ ? eAccessPublic
+ : attrs.accessibility;
+
+ clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
+ class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
+ attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
+ is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
+ attrs.is_artificial);
+
+ if (cxx_method_decl) {
+ LinkDeclContextToDIE(cxx_method_decl, die);
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(die.GetID());
+
+ char const *object_pointer_name =
+ attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr;
+ if (object_pointer_name) {
+ metadata.SetObjectPtrName(object_pointer_name);
+ LLDB_LOGF(log,
+ "Setting object pointer name: %s on method "
+ "object %p.\n",
+ object_pointer_name, static_cast<void *>(cxx_method_decl));
+ }
+ m_ast.SetMetadata(cxx_method_decl, metadata);
+ } else {
+ ignore_containing_context = true;
+ }
+
+ // Artificial methods are always handled even when we
+ // don't create a new declaration for them.
+ const bool type_handled = cxx_method_decl != nullptr || attrs.is_artificial;
+
+ return {type_handled, nullptr};
+ }
+
+ // We were asked to parse the type for a method in a
+ // class, yet the class hasn't been asked to complete
+ // itself through the clang::ExternalASTSource protocol,
+ // so we need to just have the class complete itself and
+ // do things the right way, then our
+ // DIE should then have an entry in the
+ // dwarf->GetDIEToType() map. First
+ // we need to modify the dwarf->GetDIEToType() so it
+ // doesn't think we are trying to parse this DIE
+ // anymore...
+ dwarf->GetDIEToType().erase(die.GetDIE());
+
+ // Now we get the full type to force our class type to
+ // complete itself using the clang::ExternalASTSource
+ // protocol which will parse all base classes and all
+ // methods (including the method for this DIE).
+ class_type->GetFullCompilerType();
+
+ // The type for this DIE should have been filled in the
+ // function call above.
+ Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE());
+ if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
+ return {true, type_ptr->shared_from_this()};
+
+ // The previous comment isn't actually true if the class wasn't
+ // resolved using the current method's parent DIE as source
+ // data. We need to ensure that we look up the method correctly
+ // in the class and then link the method's DIE to the unique
+ // CXXMethodDecl appropriately.
+ return {true, nullptr};
+}
+
TypeSP
DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
const ParsedDWARFTypeAttributes &attrs) {
@@ -989,13 +1186,6 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
unsigned type_quals = 0;
- std::string object_pointer_name;
- if (attrs.object_pointer) {
- const char *object_pointer_name_cstr = attrs.object_pointer.GetName();
- if (object_pointer_name_cstr)
- object_pointer_name = object_pointer_name_cstr;
- }
-
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
DW_TAG_value_to_name(tag), type_name_cstr);
@@ -1066,208 +1256,19 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
if (attrs.name) {
bool type_handled = false;
if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) {
- std::optional<const ObjCLanguage::MethodName> objc_method =
- ObjCLanguage::MethodName::Create(attrs.name.GetStringRef(), true);
- if (objc_method) {
- CompilerType class_opaque_type;
- ConstString class_name(objc_method->GetClassName());
- if (class_name) {
- TypeSP complete_objc_class_type_sp(
- dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(),
- class_name, false));
-
- if (complete_objc_class_type_sp) {
- CompilerType type_clang_forward_type =
- complete_objc_class_type_sp->GetForwardCompilerType();
- if (TypeSystemClang::IsObjCObjectOrInterfaceType(
- type_clang_forward_type))
- class_opaque_type = type_clang_forward_type;
- }
- }
-
- if (class_opaque_type) {
- clang::ObjCMethodDecl *objc_method_decl =
- m_ast.AddMethodToObjCObjectType(
- class_opaque_type, attrs.name.GetCString(), clang_type,
- attrs.is_artificial, is_variadic, attrs.is_objc_direct_call);
- type_handled = objc_method_decl != nullptr;
- if (type_handled) {
- LinkDeclContextToDIE(objc_method_decl, die);
- m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID());
- } else {
- dwarf->GetObjectFile()->GetModule()->ReportError(
- "[{0:x16}]: invalid Objective-C method {1:x4} ({2}), "
- "please file a bug and attach the file at the start of "
- "this error message",
- die.GetOffset(), tag, DW_TAG_value_to_name(tag));
- }
- }
+ if (std::optional<const ObjCLanguage::MethodName> objc_method =
+ ObjCLanguage::MethodName::Create(attrs.name.GetStringRef(),
+ true)) {
+ type_handled =
+ ParseObjCMethod(*objc_method, die, clang_type, attrs, is_variadic);
} else if (is_cxx_method) {
- // Look at the parent of this DIE and see if it is a class or
- // struct and see if this is actually a C++ method
- Type *class_type = dwarf->ResolveType(decl_ctx_die);
- if (class_type) {
- if (class_type->GetID() != decl_ctx_die.GetID() ||
- IsClangModuleFwdDecl(decl_ctx_die)) {
-
- // We uniqued the parent class of this function to another
- // class so we now need to associate all dies under
- // "decl_ctx_die" to DIEs in the DIE for "class_type"...
- DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID());
-
- if (class_type_die) {
- std::vector<DWARFDIE> failures;
-
- CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die,
- class_type, failures);
-
- // FIXME do something with these failures that's
- // smarter than just dropping them on the ground.
- // Unfortunately classes don't like having stuff added
- // to them after their definitions are complete...
-
- Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()];
- if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) {
- return type_ptr->shared_from_this();
- }
- }
- }
+ auto [handled, type_sp] =
+ ParseCXXMethod(die, clang_type, attrs, decl_ctx_die, is_static,
+ ignore_containing_context);
+ if (type_sp)
+ return type_sp;
- if (attrs.specification.IsValid()) {
- // We have a specification which we are going to base our
- // function prototype off of, so we need this type to be
- // completed so that the m_die_to_decl_ctx for the method in
- // the specification has a valid clang decl context.
- class_type->GetForwardCompilerType();
- // If we have a specification, then the function type should
- // have been made with the specification and not with this
- // die.
- DWARFDIE spec_die = attrs.specification.Reference();
- clang::DeclContext *spec_clang_decl_ctx =
- GetClangDeclContextForDIE(spec_die);
- if (spec_clang_decl_ctx) {
- LinkDeclContextToDIE(spec_clang_decl_ctx, die);
- } else {
- dwarf->GetObjectFile()->GetModule()->ReportWarning(
- "{0:x8}: DW_AT_specification({1:x16}"
- ") has no decl\n",
- die.GetID(), spec_die.GetOffset());
- }
- type_handled = true;
- } else if (attrs.abstract_origin.IsValid()) {
- // We have a specification which we are going to base our
- // function prototype off of, so we need this type to be
- // completed so that the m_die_to_decl_ctx for the method in
- // the abstract origin has a valid clang decl context.
- class_type->GetForwardCompilerType();
-
- DWARFDIE abs_die = attrs.abstract_origin.Reference();
- clang::DeclContext *abs_clang_decl_ctx =
- GetClangDeclContextForDIE(abs_die);
- if (abs_clang_decl_ctx) {
- LinkDeclContextToDIE(abs_clang_decl_ctx, die);
- } else {
- dwarf->GetObjectFile()->GetModule()->ReportWarning(
- "{0:x8}: DW_AT_abstract_origin({1:x16}"
- ") has no decl\n",
- die.GetID(), abs_die.GetOffset());
- }
- type_handled = true;
- } else {
- CompilerType class_opaque_type =
- class_type->GetForwardCompilerType();
- if (TypeSystemClang::IsCXXClassType(class_opaque_type)) {
- if (class_opaque_type.IsBeingDefined()) {
- if (!is_static && !die.HasChildren()) {
- // We have a C++ member function with no children (this
- // pointer!) and clang will get mad if we try and make
- // a function that isn't well formed in the DWARF, so
- // we will just skip it...
- type_handled = true;
- } else {
- llvm::PrettyStackTraceFormat stack_trace(
- "SymbolFileDWARF::ParseType() is adding a method "
- "%s to class %s in DIE 0x%8.8" PRIx64 " from %s",
- attrs.name.GetCString(),
- class_type->GetName().GetCString(), die.GetID(),
- dwarf->GetObjectFile()->GetFileSpec().GetPath().c_str());
-
- const bool is_attr_used = false;
- // Neither GCC 4.2 nor clang++ currently set a valid
- // accessibility in the DWARF for C++ methods...
- // Default to public for now...
- const auto accessibility = attrs.accessibility == eAccessNone
- ? eAccessPublic
- : attrs.accessibility;
-
- clang::CXXMethodDecl *cxx_method_decl =
- m_ast.AddMethodToCXXRecordType(
- class_opaque_type.GetOpaqueQualType(),
- attrs.name.GetCString(), attrs.mangled_name,
- clang_type, accessibility, attrs.is_virtual,
- is_static, attrs.is_inline, attrs.is_explicit,
- is_attr_used, attrs.is_artificial);
-
- type_handled = cxx_method_decl != nullptr;
- // Artificial methods are always handled even when we
- // don't create a new declaration for them.
- type_handled |= attrs.is_artificial;
-
- if (cxx_method_decl) {
- LinkDeclContextToDIE(cxx_method_decl, die);
-
- ClangASTMetadata metadata;
- metadata.SetUserID(die.GetID());
-
- if (!object_pointer_name.empty()) {
- metadata.SetObjectPtrName(object_pointer_name.c_str());
- LLDB_LOGF(log,
- "Setting object pointer name: %s on method "
- "object %p.\n",
- object_pointer_name.c_str(),
- static_cast<void *>(cxx_method_decl));
- }
- m_ast.SetMetadata(cxx_method_decl, metadata);
- } else {
- ignore_containing_context = true;
- }
- }
- } else {
- // We were asked to parse the type for a method in a
- // class, yet the class hasn't been asked to complete
- // itself through the clang::ExternalASTSource protocol,
- // so we need to just have the class complete itself and
- // do things the right way, then our
- // DIE should then have an entry in the
- // dwarf->GetDIEToType() map. First
- // we need to modify the dwarf->GetDIEToType() so it
- // doesn't think we are trying to parse this DIE
- // anymore...
- dwarf->GetDIEToType()[die.GetDIE()] = NULL;
-
- // Now we get the full type to force our class type to
- // complete itself using the clang::ExternalASTSource
- // protocol which will parse all base classes and all
- // methods (including the method for this DIE).
- class_type->GetFullCompilerType();
-
- // The type for this DIE should have been filled in the
- // function call above.
- Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()];
- if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) {
- return type_ptr->shared_from_this();
- }
-
- // The previous comment isn't actually true if the class wasn't
- // resolved using the current method's parent DIE as source
- // data. We need to ensure that we look up the method correctly
- // in the class and then link the method's DIE to the unique
- // CXXMethodDecl appropriately.
- type_handled = true;
- }
- }
- }
- }
+ type_handled = handled;
}
}
@@ -1356,13 +1357,14 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
ClangASTMetadata metadata;
metadata.SetUserID(die.GetID());
- if (!object_pointer_name.empty()) {
- metadata.SetObjectPtrName(object_pointer_name.c_str());
+ char const *object_pointer_name =
+ attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr;
+ if (object_pointer_name) {
+ metadata.SetObjectPtrName(object_pointer_name);
LLDB_LOGF(log,
"Setting object pointer name: %s on function "
"object %p.",
- object_pointer_name.c_str(),
- static_cast<void *>(function_decl));
+ object_pointer_name, static_cast<void *>(function_decl));
}
m_ast.SetMetadata(function_decl, metadata);
}
@@ -1560,7 +1562,6 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType(
if (!type_sp)
return type_sp;
- SymbolFileDWARF *dwarf = die.GetDWARF();
DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die);
dw_tag_t sc_parent_tag = sc_parent_die.Tag();
@@ -1579,8 +1580,6 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType(
if (symbol_context_scope != nullptr)
type_sp->SetSymbolContextScope(symbol_context_scope);
-
- dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
return type_sp;
}
@@ -1616,7 +1615,7 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) {
case DW_TAG_union_type: {
if (const char *class_union_struct_name = parent_decl_ctx_die.GetName()) {
qualified_name.insert(
- 0, GetDIEClassTemplateParams(parent_decl_ctx_die).AsCString(""));
+ 0, GetDIEClassTemplateParams(parent_decl_ctx_die));
qualified_name.insert(0, "::");
qualified_name.insert(0, class_union_struct_name);
}
@@ -1634,20 +1633,19 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) {
qualified_name.append("::");
qualified_name.append(name);
- qualified_name.append(GetDIEClassTemplateParams(die).AsCString(""));
+ qualified_name.append(GetDIEClassTemplateParams(die));
return qualified_name;
}
TypeSP
DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
- const DWARFDIE &die,
+ const DWARFDIE &decl_die,
ParsedDWARFTypeAttributes &attrs) {
- TypeSP type_sp;
CompilerType clang_type;
- const dw_tag_t tag = die.Tag();
- SymbolFileDWARF *dwarf = die.GetDWARF();
- LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU());
+ const dw_tag_t tag = decl_die.Tag();
+ SymbolFileDWARF *dwarf = decl_die.GetDWARF();
+ LanguageType cu_language = SymbolFileDWARF::GetLanguage(*decl_die.GetCU());
Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
// UniqueDWARFASTType is large, so don't create a local variables on the
@@ -1664,20 +1662,19 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
// For C++, we rely solely upon the one definition rule that says
// only one thing can exist at a given decl context. We ignore the
// file and line that things are declared on.
- std::string qualified_name = GetCPlusPlusQualifiedName(die);
+ std::string qualified_name = GetCPlusPlusQualifiedName(decl_die);
if (!qualified_name.empty())
unique_typename = ConstString(qualified_name);
unique_decl.Clear();
}
if (dwarf->GetUniqueDWARFASTTypeMap().Find(
- unique_typename, die, unique_decl, attrs.byte_size.value_or(-1),
- *unique_ast_entry_up)) {
- type_sp = unique_ast_entry_up->m_type_sp;
- if (type_sp) {
- dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+ unique_typename, decl_die, unique_decl,
+ attrs.byte_size.value_or(-1), *unique_ast_entry_up)) {
+ if (TypeSP type_sp = unique_ast_entry_up->m_type_sp) {
LinkDeclContextToDIE(
- GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die), die);
+ GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die),
+ decl_die);
return type_sp;
}
}
@@ -1700,7 +1697,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
}
if (attrs.byte_size && *attrs.byte_size == 0 && attrs.name &&
- !die.HasChildren() && cu_language == eLanguageTypeObjC) {
+ !decl_die.HasChildren() && cu_language == eLanguageTypeObjC) {
// Work around an issue with clang at the moment where forward
// declarations for objective C classes are emitted as:
// DW_TAG_structure_type [2]
@@ -1717,14 +1714,14 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
if (attrs.class_language == eLanguageTypeObjC ||
attrs.class_language == eLanguageTypeObjC_plus_plus) {
if (!attrs.is_complete_objc_class &&
- die.Supports_DW_AT_APPLE_objc_complete_type()) {
+ decl_die.Supports_DW_AT_APPLE_objc_complete_type()) {
// We have a valid eSymbolTypeObjCClass class symbol whose name
// matches the current objective C class that we are trying to find
// and this DIE isn't the complete definition (we checked
// is_complete_objc_class above and know it is false), so the real
// definition is in here somewhere
- type_sp =
- dwarf->FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true);
+ TypeSP type_sp =
+ dwarf->FindCompleteObjCDefinitionTypeForDIE(decl_die, attrs.name, true);
if (!type_sp) {
SymbolFileDWARFDebugMap *debug_map_symfile =
@@ -1733,7 +1730,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
// We weren't able to find a full declaration in this DWARF,
// see if we have a declaration anywhere else...
type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE(
- die, attrs.name, true);
+ decl_die, attrs.name, true);
}
}
@@ -1743,21 +1740,22 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
log,
"SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" is an "
"incomplete objc type, complete type is {5:x8}",
- static_cast<void *>(this), die.GetOffset(),
+ static_cast<void *>(this), decl_die.GetOffset(),
DW_TAG_value_to_name(tag), tag, attrs.name.GetCString(),
type_sp->GetID());
}
-
- // We found a real definition for this type elsewhere so lets use
- // it and cache the fact that we found a complete type for this
- // die
- dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
return type_sp;
}
}
}
+ DWARFDIE def_die;
if (attrs.is_forward_declaration) {
+ Progress progress(llvm::formatv(
+ "Parsing type in {0}: '{1}'",
+ dwarf->GetObjectFile()->GetFileSpec().GetFilename().GetString(),
+ attrs.name.GetString()));
+
// We have a forward declaration to a type and we need to try and
// find a full declaration. We look in the current type index just in
// case we have a forward declaration followed by an actual
@@ -1768,83 +1766,80 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
log,
"SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" is a "
"forward declaration, trying to find complete type",
- static_cast<void *>(this), die.GetOffset(), DW_TAG_value_to_name(tag),
- tag, attrs.name.GetCString());
+ static_cast<void *>(this), decl_die.GetID(),
+ DW_TAG_value_to_name(tag), tag, attrs.name.GetCString());
}
// See if the type comes from a Clang module and if so, track down
// that type.
- type_sp = ParseTypeFromClangModule(sc, die, log);
- if (type_sp)
+ if (TypeSP type_sp = ParseTypeFromClangModule(sc, decl_die, log))
return type_sp;
- // type_sp = FindDefinitionTypeForDIE (dwarf_cu, die,
- // type_name_const_str);
- type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die);
+ def_die = dwarf->FindDefinitionDIE(decl_die);
- if (!type_sp) {
+ if (!def_die) {
SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile();
if (debug_map_symfile) {
// We weren't able to find a full declaration in this DWARF, see
// if we have a declaration anywhere else...
- type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext(die);
+ def_die = debug_map_symfile->FindDefinitionDIE(decl_die);
}
}
- if (type_sp) {
- if (log) {
- dwarf->GetObjectFile()->GetModule()->LogMessage(
- log,
- "SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" is a "
- "forward declaration, complete type is {5:x8}",
- static_cast<void *>(this), die.GetOffset(),
- DW_TAG_value_to_name(tag), tag, attrs.name.GetCString(),
- type_sp->GetID());
- }
-
- // We found a real definition for this type elsewhere so lets use
- // it and cache the fact that we found a complete type for this die
- dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
- clang::DeclContext *defn_decl_ctx =
- GetCachedClangDeclContextForDIE(dwarf->GetDIE(type_sp->GetID()));
- if (defn_decl_ctx)
- LinkDeclContextToDIE(defn_decl_ctx, die);
- return type_sp;
+ if (log) {
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" is a "
+ "forward declaration, complete type is {5}",
+ static_cast<void *>(this), def_die.GetID(), DW_TAG_value_to_name(tag),
+ tag, attrs.name.GetCString(),
+ def_die ? llvm::utohexstr(def_die.GetID()) : "not found");
}
}
+
+ if (def_die) {
+ attrs = ParsedDWARFTypeAttributes(def_die);
+ } else {
+ // No definition found. Proceed with the declaration die. We can use it to
+ // create a forward-declared type.
+ def_die = decl_die;
+ }
assert(tag_decl_kind != -1);
UNUSED_IF_ASSERT_DISABLED(tag_decl_kind);
bool clang_type_was_created = false;
- clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr);
+ clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE(def_die, nullptr);
- PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(), decl_ctx, die,
+ PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(),
+ containing_decl_ctx, def_die,
attrs.name.GetCString());
- if (attrs.accessibility == eAccessNone && decl_ctx) {
+ if (attrs.accessibility == eAccessNone && containing_decl_ctx) {
// Check the decl context that contains this class/struct/union. If
// it is a class we must give it an accessibility.
- const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind();
+ const clang::Decl::Kind containing_decl_kind =
+ containing_decl_ctx->getDeclKind();
if (DeclKindIsCXXClass(containing_decl_kind))
attrs.accessibility = default_accessibility;
}
ClangASTMetadata metadata;
- metadata.SetUserID(die.GetID());
- metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die));
+ metadata.SetUserID(def_die.GetID());
+ metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(def_die));
TypeSystemClang::TemplateParameterInfos template_param_infos;
- if (ParseTemplateParameterInfos(die, template_param_infos)) {
+ if (ParseTemplateParameterInfos(def_die, template_param_infos)) {
clang::ClassTemplateDecl *class_template_decl =
m_ast.ParseClassTemplateDecl(
- decl_ctx, GetOwningClangModule(die), attrs.accessibility,
- attrs.name.GetCString(), tag_decl_kind, template_param_infos);
+ containing_decl_ctx, GetOwningClangModule(def_die),
+ attrs.accessibility, attrs.name.GetCString(), tag_decl_kind,
+ template_param_infos);
if (!class_template_decl) {
if (log) {
dwarf->GetObjectFile()->GetModule()->LogMessage(
log,
"SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" "
"clang::ClassTemplateDecl failed to return a decl.",
- static_cast<void *>(this), die.GetOffset(),
+ static_cast<void *>(this), def_die.GetID(),
DW_TAG_value_to_name(tag), tag, attrs.name.GetCString());
}
return TypeSP();
@@ -1852,8 +1847,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
clang::ClassTemplateSpecializationDecl *class_specialization_decl =
m_ast.CreateClassTemplateSpecializationDecl(
- decl_ctx, GetOwningClangModule(die), class_template_decl,
- tag_decl_kind, template_param_infos);
+ containing_decl_ctx, GetOwningClangModule(def_die),
+ class_template_decl, tag_decl_kind, template_param_infos);
clang_type =
m_ast.CreateClassTemplateSpecializationType(class_specialization_decl);
clang_type_was_created = true;
@@ -1865,26 +1860,34 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
if (!clang_type_was_created) {
clang_type_was_created = true;
clang_type = m_ast.CreateRecordType(
- decl_ctx, GetOwningClangModule(die), attrs.accessibility,
+ containing_decl_ctx, GetOwningClangModule(def_die), attrs.accessibility,
attrs.name.GetCString(), tag_decl_kind, attrs.class_language, &metadata,
attrs.exports_symbols);
}
- // Store a forward declaration to this class type in case any
- // parameters in any class methods need it for the clang types for
- // function prototypes.
- LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die);
- type_sp = dwarf->MakeType(
- die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID,
+ TypeSP type_sp = dwarf->MakeType(
+ def_die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID,
Type::eEncodingIsUID, &attrs.decl, clang_type,
Type::ResolveState::Forward,
TypePayloadClang(OptionalClangModuleID(), attrs.is_complete_objc_class));
+ // Store a forward declaration to this class type in case any
+ // parameters in any class methods need it for the clang types for
+ // function prototypes.
+ clang::DeclContext *type_decl_ctx =
+ TypeSystemClang::GetDeclContextForType(clang_type);
+ LinkDeclContextToDIE(type_decl_ctx, decl_die);
+ if (decl_die != def_die) {
+ LinkDeclContextToDIE(type_decl_ctx, def_die);
+ dwarf->GetDIEToType()[def_die.GetDIE()] = type_sp.get();
+ // Declaration DIE is inserted into the type map in ParseTypeFromDWARF
+ }
+
// Add our type to the unique type map so we don't end up creating many
// copies of the same type over and over in the ASTContext for our
// module
unique_ast_entry_up->m_type_sp = type_sp;
- unique_ast_entry_up->m_die = die;
+ unique_ast_entry_up->m_die = def_die;
unique_ast_entry_up->m_declaration = unique_decl;
unique_ast_entry_up->m_byte_size = attrs.byte_size.value_or(0);
dwarf->GetUniqueDWARFASTTypeMap().Insert(unique_typename,
@@ -1895,18 +1898,17 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
// has child classes or types that require the class to be created
// for use as their decl contexts the class will be ready to accept
// these child definitions.
- if (!die.HasChildren()) {
+ if (!def_die.HasChildren()) {
// No children for this struct/union/class, lets finish it
if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) {
TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
} else {
dwarf->GetObjectFile()->GetModule()->ReportError(
- "DWARF DIE at {0:x16} named \"{1}\" was not able to start "
- "its "
+ "DWARF DIE {0:x16} named \"{1}\" was not able to start its "
"definition.\nPlease file a bug and attach the file at the "
"start of this error message",
- die.GetOffset(), attrs.name.GetCString());
+ def_die.GetID(), attrs.name.GetCString());
}
// Setting authority byte size and alignment for empty structures.
@@ -1954,7 +1956,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
// binaries.
dwarf->GetForwardDeclCompilerTypeToDIE().try_emplace(
ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(),
- *die.GetDIERef());
+ *def_die.GetDIERef());
m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true);
}
}
@@ -2440,7 +2442,7 @@ DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
std::vector<clang::ParmVarDecl *> param_decls;
StreamString sstr;
- DWARFDeclContext decl_ctx = SymbolFileDWARF::GetDWARFDeclContext(die);
+ DWARFDeclContext decl_ctx = die.GetDWARFDeclContext();
sstr << decl_ctx.GetQualifiedName();
clang::DeclContext *containing_decl_ctx =
@@ -3788,7 +3790,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
if (dst_decl_ctx)
src_dwarf_ast_parser->LinkDeclContextToDIE(dst_decl_ctx, src);
- if (Type *src_child_type = die_to_type[src.GetDIE()])
+ if (Type *src_child_type = die_to_type.lookup(src.GetDIE()))
die_to_type[dst.GetDIE()] = src_child_type;
};
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index 8d4af203bb28..7b5ddbaa2a6b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -23,6 +23,7 @@
#include "lldb/Core/PluginInterface.h"
#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include <optional>
@@ -103,9 +104,9 @@ public:
///
/// \param die The struct/class DWARFDIE containing template parameters.
/// \return A string, including surrounding '<>', of the template parameters.
- /// If the DIE's name already has '<>', returns an empty ConstString because
+ /// If the DIE's name already has '<>', returns an empty string because
/// it's assumed that the caller is using the DIE name anyway.
- lldb_private::ConstString GetDIEClassTemplateParams(
+ std::string GetDIEClassTemplateParams(
const lldb_private::plugin::dwarf::DWARFDIE &die) override;
protected:
@@ -370,6 +371,56 @@ private:
ParsedDWARFTypeAttributes &attrs);
lldb::TypeSP ParseSubroutine(const lldb_private::plugin::dwarf::DWARFDIE &die,
const ParsedDWARFTypeAttributes &attrs);
+
+ /// Helper function called by \ref ParseSubroutine when parsing ObjC-methods.
+ ///
+ /// \param[in] objc_method Name of the ObjC method being parsed.
+ ///
+ /// \param[in] die The DIE that represents the ObjC method being parsed.
+ ///
+ /// \param[in] clang_type The CompilerType representing the function prototype
+ /// of the ObjC method being parsed.
+ ///
+ /// \param[in] attrs DWARF attributes for \ref die.
+ ///
+ /// \param[in] is_variadic Is true iff we're parsing a variadic method.
+ ///
+ /// \returns true on success
+ bool
+ ParseObjCMethod(const lldb_private::ObjCLanguage::MethodName &objc_method,
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::CompilerType clang_type,
+ const ParsedDWARFTypeAttributes &attrs, bool is_variadic);
+
+ /// Helper function called by \ref ParseSubroutine when parsing C++ methods.
+ ///
+ /// \param[in] die The DIE that represents the C++ method being parsed.
+ ///
+ /// \param[in] clang_type The CompilerType representing the function prototype
+ /// of the C++ method being parsed.
+ ///
+ /// \param[in] attrs DWARF attributes for \ref die.
+ ///
+ /// \param[in] decl_ctx_die The DIE representing the DeclContext of the C++
+ /// method being parsed.
+ ///
+ /// \param[in] is_static Is true iff we're parsing a static method.
+ ///
+ /// \param[out] ignore_containing_context Will get set to true if the caller
+ /// should treat this C++ method as-if it was not a C++ method.
+ /// Currently used as a hack to work around templated C++ methods
+ /// causing class definitions to mismatch between CUs.
+ ///
+ /// \returns A pair of <bool, TypeSP>. The first element is 'true' on success.
+ /// The second element is non-null if we have previously parsed this
+ /// method (a null TypeSP does not indicate failure).
+ std::pair<bool, lldb::TypeSP>
+ ParseCXXMethod(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::CompilerType clang_type,
+ const ParsedDWARFTypeAttributes &attrs,
+ const lldb_private::plugin::dwarf::DWARFDIE &decl_ctx_die,
+ bool is_static, bool &ignore_containing_context);
+
lldb::TypeSP ParseArrayType(const lldb_private::plugin::dwarf::DWARFDIE &die,
const ParsedDWARFTypeAttributes &attrs);
lldb::TypeSP
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
index 7cf92adc6ef5..fb32e2adeb3f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
@@ -367,20 +367,6 @@ lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const {
return nullptr;
}
-std::vector<DWARFDIE> DWARFDIE::GetDeclContextDIEs() const {
- if (!IsValid())
- return {};
-
- std::vector<DWARFDIE> result;
- DWARFDIE parent = GetParentDeclContextDIE();
- while (parent.IsValid() && parent.GetDIE() != GetDIE()) {
- result.push_back(std::move(parent));
- parent = parent.GetParentDeclContextDIE();
- }
-
- return result;
-}
-
static void GetDeclContextImpl(DWARFDIE die,
llvm::SmallSet<lldb::user_id_t, 4> &seen,
std::vector<CompilerContext> &context) {
@@ -408,15 +394,13 @@ static void GetDeclContextImpl(DWARFDIE die,
case DW_TAG_namespace:
push_ctx(CompilerContextKind::Namespace, die.GetName());
break;
+ case DW_TAG_class_type:
case DW_TAG_structure_type:
- push_ctx(CompilerContextKind::Struct, die.GetName());
+ push_ctx(CompilerContextKind::ClassOrStruct, die.GetName());
break;
case DW_TAG_union_type:
push_ctx(CompilerContextKind::Union, die.GetName());
break;
- case DW_TAG_class_type:
- push_ctx(CompilerContextKind::Class, die.GetName());
- break;
case DW_TAG_enumeration_type:
push_ctx(CompilerContextKind::Enum, die.GetName());
break;
@@ -470,15 +454,13 @@ static void GetTypeLookupContextImpl(DWARFDIE die,
case DW_TAG_namespace:
push_ctx(CompilerContextKind::Namespace, die.GetName());
break;
+ case DW_TAG_class_type:
case DW_TAG_structure_type:
- push_ctx(CompilerContextKind::Struct, die.GetName());
+ push_ctx(CompilerContextKind::ClassOrStruct, die.GetName());
break;
case DW_TAG_union_type:
push_ctx(CompilerContextKind::Union, die.GetName());
break;
- case DW_TAG_class_type:
- push_ctx(CompilerContextKind::Class, die.GetName());
- break;
case DW_TAG_enumeration_type:
push_ctx(CompilerContextKind::Enum, die.GetName());
break;
@@ -491,6 +473,18 @@ static void GetTypeLookupContextImpl(DWARFDIE die,
case DW_TAG_base_type:
push_ctx(CompilerContextKind::Builtin, name);
break;
+ // If any of the tags below appear in the parent chain, stop the decl
+ // context and return. Prior to these being in here, if a type existed in a
+ // namespace "a" like "a::my_struct", but we also have a function in that
+ // same namespace "a" which contained a type named "my_struct", both would
+ // return "a::my_struct" as the declaration context since the
+ // DW_TAG_subprogram would be skipped and its parent would be found.
+ case DW_TAG_compile_unit:
+ case DW_TAG_type_unit:
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ return;
default:
break;
}
@@ -507,12 +501,64 @@ std::vector<CompilerContext> DWARFDIE::GetTypeLookupContext() const {
return context;
}
+static DWARFDeclContext GetDWARFDeclContextImpl(DWARFDIE die) {
+ DWARFDeclContext dwarf_decl_ctx;
+ while (die) {
+ const dw_tag_t tag = die.Tag();
+ if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)
+ break;
+ dwarf_decl_ctx.AppendDeclContext(tag, die.GetName());
+ DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE();
+ if (parent_decl_ctx_die == die)
+ break;
+ die = parent_decl_ctx_die;
+ }
+ return dwarf_decl_ctx;
+}
+
+DWARFDeclContext DWARFDIE::GetDWARFDeclContext() const {
+ return GetDWARFDeclContextImpl(*this);
+}
+
+static DWARFDIE GetParentDeclContextDIEImpl(DWARFDIE die) {
+ DWARFDIE orig_die = die;
+ while (die) {
+ // If this is the original DIE that we are searching for a declaration for,
+ // then don't look in the cache as we don't want our own decl context to be
+ // our decl context...
+ if (die != orig_die) {
+ switch (die.Tag()) {
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ return die;
+
+ default:
+ break;
+ }
+ }
+
+ if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification)) {
+ if (DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE())
+ return decl_ctx_die;
+ }
+
+ if (DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin)) {
+ if (DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE())
+ return decl_ctx_die;
+ }
+
+ die = die.GetParent();
+ }
+ return DWARFDIE();
+}
+
DWARFDIE
DWARFDIE::GetParentDeclContextDIE() const {
- if (IsValid())
- return m_die->GetParentDeclContextDIE(m_cu);
- else
- return DWARFDIE();
+ return GetParentDeclContextDIEImpl(*this);
}
bool DWARFDIE::IsStructUnionOrClass() const {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
index 511ca62d0197..e1318953a384 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
@@ -69,9 +69,6 @@ public:
DWARFDIE
GetParentDeclContextDIE() const;
- // DeclContext related functions
- std::vector<DWARFDIE> GetDeclContextDIEs() const;
-
/// Return this DIE's decl context as it is needed to look up types
/// in Clang modules. This context will include any modules or functions that
/// the type is declared in so an exact module match can be efficiently made.
@@ -89,6 +86,8 @@ public:
/// using a full or partial CompilerContext array.
std::vector<CompilerContext> GetTypeLookupContext() const;
+ DWARFDeclContext GetDWARFDeclContext() const;
+
// Getting attribute values from the DIE.
//
// GetAttributeValueAsXXX() functions should only be used if you are
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
index da73891f6665..f383261e8a5f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -89,8 +89,7 @@ void DWARFDebugAranges::AppendRange(dw_offset_t offset, dw_addr_t low_pc,
}
void DWARFDebugAranges::Sort(bool minimize) {
- LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION,
- static_cast<void *>(this));
+ LLDB_SCOPED_TIMER();
m_aranges.Sort();
m_aranges.CombineConsecutiveEntriesWithEqualData();
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
index c37cc91e08ed..f7df38d24019 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -232,6 +232,10 @@ DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section,
return result;
}
+const std::shared_ptr<SymbolFileDWARFDwo> &DWARFDebugInfo::GetDwpSymbolFile() {
+ return m_dwarf.GetDwpSymbolFile();
+}
+
DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) {
auto pos = llvm::lower_bound(m_type_hash_to_unit_index,
std::make_pair(hash, 0u), llvm::less_first());
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
index 4706b55d38ea..598739bf3cb9 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -52,6 +52,8 @@ public:
const DWARFDebugAranges &GetCompileUnitAranges();
+ const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile();
+
protected:
typedef std::vector<DWARFUnitSP> UnitColl;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index 688a287a0650..e2660735ea7d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -610,79 +610,6 @@ void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable(
}
}
-DWARFDeclContext
-DWARFDebugInfoEntry::GetDWARFDeclContextStatic(const DWARFDebugInfoEntry *die,
- DWARFUnit *cu) {
- DWARFDeclContext dwarf_decl_ctx;
- for (;;) {
- const dw_tag_t tag = die->Tag();
- if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)
- return dwarf_decl_ctx;
- dwarf_decl_ctx.AppendDeclContext(tag, die->GetName(cu));
- DWARFDIE parent_decl_ctx_die = die->GetParentDeclContextDIE(cu);
- if (!parent_decl_ctx_die || parent_decl_ctx_die.GetDIE() == die)
- return dwarf_decl_ctx;
- if (parent_decl_ctx_die.Tag() == DW_TAG_compile_unit ||
- parent_decl_ctx_die.Tag() == DW_TAG_partial_unit)
- return dwarf_decl_ctx;
- die = parent_decl_ctx_die.GetDIE();
- cu = parent_decl_ctx_die.GetCU();
- }
-}
-
-DWARFDeclContext DWARFDebugInfoEntry::GetDWARFDeclContext(DWARFUnit *cu) const {
- return GetDWARFDeclContextStatic(this, cu);
-}
-
-DWARFDIE
-DWARFDebugInfoEntry::GetParentDeclContextDIE(DWARFUnit *cu) const {
- DWARFAttributes attributes = GetAttributes(cu, Recurse::yes);
- return GetParentDeclContextDIE(cu, attributes);
-}
-
-DWARFDIE
-DWARFDebugInfoEntry::GetParentDeclContextDIE(
- DWARFUnit *cu, const DWARFAttributes &attributes) const {
- DWARFDIE die(cu, const_cast<DWARFDebugInfoEntry *>(this));
-
- while (die) {
- // If this is the original DIE that we are searching for a declaration for,
- // then don't look in the cache as we don't want our own decl context to be
- // our decl context...
- if (die.GetDIE() != this) {
- switch (die.Tag()) {
- case DW_TAG_compile_unit:
- case DW_TAG_partial_unit:
- case DW_TAG_namespace:
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_class_type:
- return die;
-
- default:
- break;
- }
- }
-
- DWARFDIE spec_die = attributes.FormValueAsReference(DW_AT_specification);
- if (spec_die) {
- DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE();
- if (decl_ctx_die)
- return decl_ctx_die;
- }
-
- DWARFDIE abs_die = attributes.FormValueAsReference(DW_AT_abstract_origin);
- if (abs_die) {
- DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE();
- if (decl_ctx_die)
- return decl_ctx_die;
- }
-
- die = die.GetParent();
- }
- return DWARFDIE();
-}
-
lldb::offset_t DWARFDebugInfoEntry::GetFirstAttributeOffset() const {
return GetOffset() + llvm::getULEB128Size(m_abbr_idx);
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
index 6773b00e8206..3816c6500717 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
@@ -157,12 +157,6 @@ public:
return HasChildren() ? this + 1 : nullptr;
}
- DWARFDeclContext GetDWARFDeclContext(DWARFUnit *cu) const;
-
- DWARFDIE GetParentDeclContextDIE(DWARFUnit *cu) const;
- DWARFDIE GetParentDeclContextDIE(DWARFUnit *cu,
- const DWARFAttributes &attributes) const;
-
void SetSiblingIndex(uint32_t idx) { m_sibling_idx = idx; }
void SetParentIndex(uint32_t idx) { m_parent_idx = idx; }
@@ -172,9 +166,6 @@ public:
bool IsGlobalOrStaticScopeVariable() const;
protected:
- static DWARFDeclContext
- GetDWARFDeclContextStatic(const DWARFDebugInfoEntry *die, DWARFUnit *cu);
-
// Up to 2TB offset within the .debug_info/.debug_types
dw_offset_t m_offset : DW_DIE_OFFSET_MAX_BITSIZE;
// How many to subtract from "this" to get the parent. If zero this die has no
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
index 44421c0eda3e..f759cb8fae61 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
@@ -12,18 +12,16 @@
using namespace lldb_private::dwarf;
using namespace lldb_private::plugin::dwarf;
-/// Returns the name of `entry` if it has one, or the appropriate "anonymous
-/// {namespace, class, struct, union}".
-static const char *GetName(DWARFDeclContext::Entry entry) {
- if (entry.name != nullptr)
- return entry.name;
- if (entry.tag == DW_TAG_namespace)
+const char *DWARFDeclContext::Entry::GetName() const {
+ if (name != nullptr)
+ return name;
+ if (tag == DW_TAG_namespace)
return "(anonymous namespace)";
- if (entry.tag == DW_TAG_class_type)
+ if (tag == DW_TAG_class_type)
return "(anonymous class)";
- if (entry.tag == DW_TAG_structure_type)
+ if (tag == DW_TAG_structure_type)
return "(anonymous struct)";
- if (entry.tag == DW_TAG_union_type)
+ if (tag == DW_TAG_union_type)
return "(anonymous union)";
return "(anonymous)";
}
@@ -46,7 +44,7 @@ const char *DWARFDeclContext::GetQualifiedName() const {
llvm::raw_string_ostream string_stream(m_qualified_name);
llvm::interleave(
llvm::reverse(m_entries), string_stream,
- [&](auto entry) { string_stream << GetName(entry); }, "::");
+ [&](auto entry) { string_stream << entry.GetName(); }, "::");
}
}
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
index 7e6c5f51f4be..b563d1c4417b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
@@ -9,8 +9,9 @@
#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H
#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H
-#include "lldb/Utility/ConstString.h"
#include "DWARFDefines.h"
+#include "lldb/Utility/ConstString.h"
+#include "llvm/ADT/StringExtras.h"
#include <cassert>
#include <string>
@@ -38,6 +39,10 @@ public:
return false;
}
+ /// Returns the name of this entry if it has one, or the appropriate
+ /// "anonymous {namespace, class, struct, union}".
+ const char *GetName() const;
+
// Test operator
explicit operator bool() const { return tag != 0; }
@@ -83,6 +88,17 @@ public:
m_qualified_name.clear();
}
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const DWARFDeclContext &ctx) {
+ OS << "DWARFDeclContext{";
+ llvm::ListSeparator LS;
+ for (const Entry &e : ctx.m_entries) {
+ OS << LS << "{" << DW_TAG_value_to_name(e.tag) << ", " << e.GetName()
+ << "}";
+ }
+ return OS << "}";
+ }
+
protected:
typedef std::vector<Entry> collection;
collection m_entries;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
index 30fb5d5ebdb0..eafddbad03f5 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
@@ -121,8 +121,7 @@ void DWARFIndex::GetFullyQualifiedType(
bool DWARFIndex::GetFullyQualifiedTypeImpl(
const DWARFDeclContext &context, DWARFDIE die,
llvm::function_ref<bool(DWARFDIE die)> callback) {
- DWARFDeclContext dwarf_decl_ctx =
- die.GetDIE()->GetDWARFDeclContext(die.GetCU());
+ DWARFDeclContext dwarf_decl_ctx = die.GetDWARFDeclContext();
if (dwarf_decl_ctx == context)
return callback(die);
return true;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
index 90e42be7202d..7e66b3dccf97 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
@@ -10,6 +10,7 @@
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
#include "lldb/Core/Module.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
@@ -34,6 +35,17 @@ DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
module, std::move(index_up), debug_names, debug_str, dwarf));
}
+llvm::DenseSet<uint64_t>
+DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) {
+ llvm::DenseSet<uint64_t> result;
+ for (const DebugNames::NameIndex &ni : debug_names) {
+ const uint32_t num_tus = ni.getForeignTUCount();
+ for (uint32_t tu = 0; tu < num_tus; ++tu)
+ result.insert(ni.getForeignTUSignature(tu));
+ }
+ return result;
+}
+
llvm::DenseSet<dw_offset_t>
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
llvm::DenseSet<dw_offset_t> result;
@@ -48,20 +60,80 @@ DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
return result;
}
+std::optional<DWARFTypeUnit *>
+DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const {
+ std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature();
+ if (!type_sig.has_value())
+ return std::nullopt;
+
+ // Ask the entry for the skeleton compile unit offset and fetch the .dwo
+ // file from it and get the type unit by signature from there. If we find
+ // the type unit in the .dwo file, we don't need to check that the
+ // DW_AT_dwo_name matches because each .dwo file can have its own type unit.
+ std::optional<uint64_t> cu_offset = entry.getRelatedCUOffset();
+ if (!cu_offset)
+ return nullptr; // Return NULL, this is a type unit, but couldn't find it.
+
+ DWARFUnit *cu =
+ m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
+ if (!cu)
+ return nullptr; // Return NULL, this is a type unit, but couldn't find it.
+
+ auto dwp_sp = m_debug_info.GetDwpSymbolFile();
+ if (!dwp_sp) {
+ // No .dwp file, we need to load the .dwo file.
+ DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit();
+ // We don't need the check if the type unit matches the .dwo file if we have
+ // a .dwo file (not a .dwp), so we can just return the value here.
+ if (!dwo_cu.IsDWOUnit())
+ return nullptr; // We weren't able to load the .dwo file.
+ return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(
+ *type_sig);
+ }
+ // We have a .dwp file, just get the type unit from there. We need to verify
+ // that the type unit that ended up in the final .dwp file is the right type
+ // unit. Type units have signatures which are the same across multiple .dwo
+ // files, but only one of those type units will end up in the .dwp file. The
+ // contents of type units for the same type can be different in different .dwo
+ // files, which means the DIE offsets might not be the same between two
+ // different type units. So we need to determine if this accelerator table
+ // matches the type unit that ended up in the .dwp file. If it doesn't match,
+ // then we need to ignore this accelerator table entry as the type unit that
+ // is in the .dwp file will have its own index. In order to determine if the
+ // type unit that ended up in a .dwp file matches this DebugNames::Entry, we
+ // need to find the skeleton compile unit for this entry.
+ DWARFTypeUnit *foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig);
+ if (!foreign_tu)
+ return nullptr; // Return NULL, this is a type unit, but couldn't find it.
+
+ DWARFBaseDIE cu_die = cu->GetUnitDIEOnly();
+ DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly();
+ llvm::StringRef cu_dwo_name =
+ cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
+ llvm::StringRef tu_dwo_name =
+ tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
+ if (cu_dwo_name == tu_dwo_name)
+ return foreign_tu; // We found a match!
+ return nullptr; // Return NULL, this is a type unit, but couldn't find it.
+}
+
DWARFUnit *
DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const {
+
+ if (std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry))
+ return foreign_tu.value();
+
// Look for a DWARF unit offset (CU offset or local TU offset) as they are
// both offsets into the .debug_info section.
std::optional<uint64_t> unit_offset = entry.getCUOffset();
- if (!unit_offset) {
+ if (!unit_offset)
unit_offset = entry.getLocalTUOffset();
- if (!unit_offset)
- return nullptr;
+ if (unit_offset) {
+ if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo,
+ *unit_offset))
+ return &cu->GetNonSkeletonUnit();
}
-
- DWARFUnit *cu =
- m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset);
- return cu ? &cu->GetNonSkeletonUnit() : nullptr;
+ return nullptr;
}
DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const {
@@ -85,6 +157,11 @@ bool DebugNamesDWARFIndex::ProcessEntry(
DWARFDIE die = GetDIE(entry);
if (!die)
return true;
+ // Clang used to erroneously emit index entries for declaration DIEs in case
+ // when the definition is in a type unit (llvm.org/pr77696).
+ if (die.IsStructUnionOrClass() &&
+ die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
+ return true;
return callback(die);
}
@@ -269,6 +346,13 @@ void DebugNamesDWARFIndex::GetFullyQualifiedType(
if (!isType(entry.tag()))
continue;
+ // If we get a NULL foreign_tu back, the entry doesn't match the type unit
+ // in the .dwp file, or we were not able to load the .dwo file or the DWO ID
+ // didn't match.
+ std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
+ if (foreign_tu && foreign_tu.value() == nullptr)
+ continue;
+
// Grab at most one extra parent, subsequent parents are not necessary to
// test equality.
std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
index a27a414ecdd1..cb15c1d4f994 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
@@ -70,7 +70,8 @@ private:
: DWARFIndex(module), m_debug_info(dwarf.DebugInfo()),
m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data),
m_debug_names_up(std::move(debug_names_up)),
- m_fallback(module, dwarf, GetUnits(*m_debug_names_up)) {}
+ m_fallback(module, dwarf, GetUnits(*m_debug_names_up),
+ GetTypeUnitSignatures(*m_debug_names_up)) {}
DWARFDebugInfo &m_debug_info;
@@ -85,6 +86,31 @@ private:
DWARFUnit *GetNonSkeletonUnit(const DebugNames::Entry &entry) const;
DWARFDIE GetDIE(const DebugNames::Entry &entry) const;
+
+ /// Checks if an entry is a foreign TU and fetch the type unit.
+ ///
+ /// This function checks if the DebugNames::Entry refers to a foreign TU and
+ /// returns an optional with a value of the \a entry is a foreign type unit
+ /// entry. A valid pointer will be returned if this entry is from a .dwo file
+ /// or if it is from a .dwp file and it matches the type unit's originating
+ /// .dwo file by verifying that the DW_TAG_type_unit DIE has a DW_AT_dwo_name
+ /// that matches the DWO name from the originating skeleton compile unit.
+ ///
+ /// \param[in] entry
+ /// The accelerator table entry to check.
+ ///
+ /// \returns
+ /// A std::optional that has a value if this entry represents a foreign type
+ /// unit. If the pointer is valid, then we were able to find and match the
+ /// entry to the type unit in the .dwo or .dwp file. The returned value can
+ /// have a valid, yet contain NULL in the following cases:
+ /// - we were not able to load the .dwo file (missing or DWO ID mismatch)
+ /// - we were able to load the .dwp file, but the type units DWO name
+ /// doesn't match the originating skeleton compile unit's entry
+ /// Returns std::nullopt if this entry is not a foreign type unit entry.
+ std::optional<DWARFTypeUnit *>
+ GetForeignTypeUnit(const DebugNames::Entry &entry) const;
+
bool ProcessEntry(const DebugNames::Entry &entry,
llvm::function_ref<bool(DWARFDIE die)> callback);
@@ -97,6 +123,8 @@ private:
llvm::StringRef name);
static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names);
+ static llvm::DenseSet<uint64_t>
+ GetTypeUnitSignatures(const DebugNames &debug_names);
};
} // namespace dwarf
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
index 92275600f99c..d581d3773ab2 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -60,8 +60,11 @@ void ManualDWARFIndex::Index() {
}
if (dwp_info && dwp_info->ContainsTypeUnits()) {
for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {
- if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U)))
- units_to_index.push_back(tu);
+ if (auto *tu =
+ llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) {
+ if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash()))
+ units_to_index.push_back(tu);
+ }
}
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
index 0126e587e52d..d8c4a22ab21f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
@@ -21,9 +21,11 @@ class SymbolFileDWARFDwo;
class ManualDWARFIndex : public DWARFIndex {
public:
ManualDWARFIndex(Module &module, SymbolFileDWARF &dwarf,
- llvm::DenseSet<dw_offset_t> units_to_avoid = {})
+ llvm::DenseSet<dw_offset_t> units_to_avoid = {},
+ llvm::DenseSet<uint64_t> type_sigs_to_avoid = {})
: DWARFIndex(module), m_dwarf(&dwarf),
- m_units_to_avoid(std::move(units_to_avoid)) {}
+ m_units_to_avoid(std::move(units_to_avoid)),
+ m_type_sigs_to_avoid(std::move(type_sigs_to_avoid)) {}
void Preload() override { Index(); }
@@ -170,6 +172,7 @@ private:
SymbolFileDWARF *m_dwarf;
/// Which dwarf units should we skip while building the index.
llvm::DenseSet<dw_offset_t> m_units_to_avoid;
+ llvm::DenseSet<uint64_t> m_type_sigs_to_avoid;
IndexSet m_set;
bool m_indexed = false;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index a52a7d676737..f2ff3a8b259f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -710,8 +710,8 @@ llvm::DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() {
DWARFDebugInfo &SymbolFileDWARF::DebugInfo() {
llvm::call_once(m_info_once_flag, [&] {
- LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION,
- static_cast<void *>(this));
+ LLDB_SCOPED_TIMER();
+
m_info = std::make_unique<DWARFDebugInfo>(*this, m_context);
});
return *m_info;
@@ -732,8 +732,7 @@ DWARFCompileUnit *SymbolFileDWARF::GetDWARFCompileUnit(CompileUnit *comp_unit) {
DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() {
if (!m_ranges) {
- LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION,
- static_cast<void *>(this));
+ LLDB_SCOPED_TIMER();
if (m_context.getOrLoadRangesData().GetByteSize() > 0)
m_ranges = std::make_unique<DWARFDebugRanges>();
@@ -1728,14 +1727,7 @@ lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) {
return pos->second;
}
-DWARFDIE
-SymbolFileDWARF::GetDIE(const DIERef &die_ref) {
- // This method can be called without going through the symbol vendor so we
- // need to lock the module.
- std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
-
- SymbolFileDWARF *symbol_file = nullptr;
-
+SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) {
// Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we
// must make sure we use the correct DWARF file when resolving things. On
// MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple
@@ -1743,30 +1735,44 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) {
// references to other DWARF objects and we must be ready to receive a
// "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF
// instance.
+
std::optional<uint32_t> file_index = die_ref.file_index();
- if (file_index) {
- if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile()) {
- symbol_file = debug_map->GetSymbolFileByOSOIndex(*file_index); // OSO case
- if (symbol_file)
- return symbol_file->DebugInfo().GetDIE(die_ref.section(),
- die_ref.die_offset());
- return DWARFDIE();
- }
+ // If the file index matches, then we have the right SymbolFileDWARF already.
+ // This will work for both .dwo file and DWARF in .o files for mac. Also if
+ // both the file indexes are invalid, then we have a match.
+ if (GetFileIndex() == file_index)
+ return this;
+
+ if (file_index) {
+ // We have a SymbolFileDWARFDebugMap, so let it find the right file
+ if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile())
+ return debug_map->GetSymbolFileByOSOIndex(*file_index);
+
+ // Handle the .dwp file case correctly
if (*file_index == DIERef::k_file_index_mask)
- symbol_file = GetDwpSymbolFile().get(); // DWP case
- else
- symbol_file = this->DebugInfo()
- .GetUnitAtIndex(*die_ref.file_index())
- ->GetDwoSymbolFile(); // DWO case
- } else if (die_ref.die_offset() == DW_INVALID_OFFSET) {
- return DWARFDIE();
+ return GetDwpSymbolFile().get(); // DWP case
+
+ // Handle the .dwo file case correctly
+ return DebugInfo().GetUnitAtIndex(*die_ref.file_index())
+ ->GetDwoSymbolFile(); // DWO case
}
+ return this;
+}
- if (symbol_file)
- return symbol_file->GetDIE(die_ref);
+DWARFDIE
+SymbolFileDWARF::GetDIE(const DIERef &die_ref) {
+ if (die_ref.die_offset() == DW_INVALID_OFFSET)
+ return DWARFDIE();
- return DebugInfo().GetDIE(die_ref.section(), die_ref.die_offset());
+ // This method can be called without going through the symbol vendor so we
+ // need to lock the module.
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *symbol_file = GetDIERefSymbolFile(die_ref);
+ if (symbol_file)
+ return symbol_file->DebugInfo().GetDIE(die_ref.section(),
+ die_ref.die_offset());
+ return DWARFDIE();
}
/// Return the DW_AT_(GNU_)dwo_id.
@@ -3039,205 +3045,113 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE(
return type_sp;
}
-// This function helps to ensure that the declaration contexts match for two
-// different DIEs. Often times debug information will refer to a forward
-// declaration of a type (the equivalent of "struct my_struct;". There will
-// often be a declaration of that type elsewhere that has the full definition.
-// When we go looking for the full type "my_struct", we will find one or more
-// matches in the accelerator tables and we will then need to make sure the
-// type was in the same declaration context as the original DIE. This function
-// can efficiently compare two DIEs and will return true when the declaration
-// context matches, and false when they don't.
-bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1,
- const DWARFDIE &die2) {
- if (die1 == die2)
- return true;
+DWARFDIE
+SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) {
+ if (!die.GetName())
+ return {};
- std::vector<DWARFDIE> decl_ctx_1;
- std::vector<DWARFDIE> decl_ctx_2;
- // The declaration DIE stack is a stack of the declaration context DIEs all
- // the way back to the compile unit. If a type "T" is declared inside a class
- // "B", and class "B" is declared inside a class "A" and class "A" is in a
- // namespace "lldb", and the namespace is in a compile unit, there will be a
- // stack of DIEs:
- //
- // [0] DW_TAG_class_type for "B"
- // [1] DW_TAG_class_type for "A"
- // [2] DW_TAG_namespace for "lldb"
- // [3] DW_TAG_compile_unit or DW_TAG_partial_unit for the source file.
- //
- // We grab both contexts and make sure that everything matches all the way
- // back to the compiler unit.
-
- // First lets grab the decl contexts for both DIEs
- decl_ctx_1 = die1.GetDeclContextDIEs();
- decl_ctx_2 = die2.GetDeclContextDIEs();
- // Make sure the context arrays have the same size, otherwise we are done
- const size_t count1 = decl_ctx_1.size();
- const size_t count2 = decl_ctx_2.size();
- if (count1 != count2)
- return false;
+ const dw_tag_t tag = die.Tag();
- // Make sure the DW_TAG values match all the way back up the compile unit. If
- // they don't, then we are done.
- DWARFDIE decl_ctx_die1;
- DWARFDIE decl_ctx_die2;
- size_t i;
- for (i = 0; i < count1; i++) {
- decl_ctx_die1 = decl_ctx_1[i];
- decl_ctx_die2 = decl_ctx_2[i];
- if (decl_ctx_die1.Tag() != decl_ctx_die2.Tag())
- return false;
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ if (log) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindDefinitionDIE(tag={0} "
+ "({1}), name='{2}')",
+ DW_TAG_value_to_name(tag), tag, die.GetName());
}
-#ifndef NDEBUG
-
- // Make sure the top item in the decl context die array is always
- // DW_TAG_compile_unit or DW_TAG_partial_unit. If it isn't then
- // something went wrong in the DWARFDIE::GetDeclContextDIEs()
- // function.
- dw_tag_t cu_tag = decl_ctx_1[count1 - 1].Tag();
- UNUSED_IF_ASSERT_DISABLED(cu_tag);
- assert(cu_tag == DW_TAG_compile_unit || cu_tag == DW_TAG_partial_unit);
-
-#endif
- // Always skip the compile unit when comparing by only iterating up to "count
- // - 1". Here we compare the names as we go.
- for (i = 0; i < count1 - 1; i++) {
- decl_ctx_die1 = decl_ctx_1[i];
- decl_ctx_die2 = decl_ctx_2[i];
- const char *name1 = decl_ctx_die1.GetName();
- const char *name2 = decl_ctx_die2.GetName();
- // If the string was from a DW_FORM_strp, then the pointer will often be
- // the same!
- if (name1 == name2)
- continue;
- // Name pointers are not equal, so only compare the strings if both are not
- // NULL.
- if (name1 && name2) {
- // If the strings don't compare, we are done...
- if (strcmp(name1, name2) != 0)
- return false;
+ // Get the type system that we are looking to find a type for. We will
+ // use this to ensure any matches we find are in a language that this
+ // type system supports
+ const LanguageType language = GetLanguage(*die.GetCU());
+ TypeSystemSP type_system = nullptr;
+ if (language != eLanguageTypeUnknown) {
+ auto type_system_or_err = GetTypeSystemForLanguage(language);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Cannot get TypeSystem for language {1}: {0}",
+ Language::GetNameForLanguageType(language));
} else {
- // One name was NULL while the other wasn't
- return false;
+ type_system = *type_system_or_err;
}
}
- // We made it through all of the checks and the declaration contexts are
- // equal.
- return true;
-}
-
-TypeSP
-SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) {
- TypeSP type_sp;
- if (die.GetName()) {
- const dw_tag_t tag = die.Tag();
-
- Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
- if (log) {
- GetObjectFile()->GetModule()->LogMessage(
- log,
- "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag={0} "
- "({1}), name='{2}')",
- DW_TAG_value_to_name(tag), tag, die.GetName());
- }
-
- // Get the type system that we are looking to find a type for. We will
- // use this to ensure any matches we find are in a language that this
- // type system supports
- const LanguageType language = GetLanguage(*die.GetCU());
- TypeSystemSP type_system = nullptr;
- if (language != eLanguageTypeUnknown) {
- auto type_system_or_err = GetTypeSystemForLanguage(language);
- if (auto err = type_system_or_err.takeError()) {
- LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
- "Cannot get TypeSystem for language {1}: {0}",
- Language::GetNameForLanguageType(language));
- } else {
- type_system = *type_system_or_err;
+ // See comments below about -gsimple-template-names for why we attempt to
+ // compute missing template parameter names.
+ std::vector<std::string> template_params;
+ DWARFDeclContext die_dwarf_decl_ctx;
+ DWARFASTParser *dwarf_ast =
+ type_system ? type_system->GetDWARFParser() : nullptr;
+ for (DWARFDIE ctx_die = die; ctx_die && !isUnitType(ctx_die.Tag());
+ ctx_die = ctx_die.GetParentDeclContextDIE()) {
+ die_dwarf_decl_ctx.AppendDeclContext(ctx_die.Tag(), ctx_die.GetName());
+ template_params.push_back(
+ (ctx_die.IsStructUnionOrClass() && dwarf_ast)
+ ? dwarf_ast->GetDIEClassTemplateParams(ctx_die)
+ : "");
+ }
+ const bool any_template_params = llvm::any_of(
+ template_params, [](llvm::StringRef p) { return !p.empty(); });
+
+ auto die_matches = [&](DWARFDIE type_die) {
+ // Resolve the type if both have the same tag or {class, struct} tags.
+ const bool tag_matches =
+ type_die.Tag() == tag ||
+ (IsStructOrClassTag(type_die.Tag()) && IsStructOrClassTag(tag));
+ if (!tag_matches)
+ return false;
+ if (any_template_params) {
+ size_t pos = 0;
+ for (DWARFDIE ctx_die = type_die; ctx_die && !isUnitType(ctx_die.Tag()) &&
+ pos < template_params.size();
+ ctx_die = ctx_die.GetParentDeclContextDIE(), ++pos) {
+ if (template_params[pos].empty())
+ continue;
+ if (template_params[pos] !=
+ dwarf_ast->GetDIEClassTemplateParams(ctx_die))
+ return false;
}
+ if (pos != template_params.size())
+ return false;
}
+ return true;
+ };
+ DWARFDIE result;
+ m_index->GetFullyQualifiedType(die_dwarf_decl_ctx, [&](DWARFDIE type_die) {
+ // Make sure type_die's language matches the type system we are
+ // looking for. We don't want to find a "Foo" type from Java if we
+ // are looking for a "Foo" type for C, C++, ObjC, or ObjC++.
+ if (type_system &&
+ !type_system->SupportsLanguage(GetLanguage(*type_die.GetCU())))
+ return true;
- // See comments below about -gsimple-template-names for why we attempt to
- // compute missing template parameter names.
- ConstString template_params;
- if (type_system) {
- DWARFASTParser *dwarf_ast = type_system->GetDWARFParser();
- if (dwarf_ast)
- template_params = dwarf_ast->GetDIEClassTemplateParams(die);
- }
-
- const DWARFDeclContext die_dwarf_decl_ctx = GetDWARFDeclContext(die);
- m_index->GetFullyQualifiedType(die_dwarf_decl_ctx, [&](DWARFDIE type_die) {
- // Make sure type_die's language matches the type system we are
- // looking for. We don't want to find a "Foo" type from Java if we
- // are looking for a "Foo" type for C, C++, ObjC, or ObjC++.
- if (type_system &&
- !type_system->SupportsLanguage(GetLanguage(*type_die.GetCU())))
- return true;
-
- const dw_tag_t type_tag = type_die.Tag();
- // Resolve the type if both have the same tag or {class, struct} tags.
- const bool try_resolving_type =
- type_tag == tag ||
- (IsStructOrClassTag(type_tag) && IsStructOrClassTag(tag));
-
- if (!try_resolving_type) {
- if (log) {
- GetObjectFile()->GetModule()->LogMessage(
- log,
- "SymbolFileDWARF::"
- "FindDefinitionTypeForDWARFDeclContext(tag={0} ({1}), "
- "name='{2}') ignoring die={3:x16} ({4})",
- DW_TAG_value_to_name(tag), tag, die.GetName(),
- type_die.GetOffset(), type_die.GetName());
- }
- return true;
- }
-
+ if (!die_matches(type_die)) {
if (log) {
- DWARFDeclContext type_dwarf_decl_ctx = GetDWARFDeclContext(type_die);
GetObjectFile()->GetModule()->LogMessage(
log,
- "SymbolFileDWARF::"
- "FindDefinitionTypeForDWARFDeclContext(tag={0} ({1}), name='{2}') "
- "trying die={3:x16} ({4})",
+ "SymbolFileDWARF::FindDefinitionDIE(tag={0} ({1}), "
+ "name='{2}') ignoring die={3:x16} ({4})",
DW_TAG_value_to_name(tag), tag, die.GetName(), type_die.GetOffset(),
- type_dwarf_decl_ctx.GetQualifiedName());
+ type_die.GetName());
}
+ return true;
+ }
- Type *resolved_type = ResolveType(type_die, false);
- if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED)
- return true;
-
- // With -gsimple-template-names, the DIE name may not contain the template
- // parameters. If the declaration has template parameters but doesn't
- // contain '<', check that the child template parameters match.
- if (template_params) {
- llvm::StringRef test_base_name =
- GetTypeForDIE(type_die)->GetBaseName().GetStringRef();
- auto i = test_base_name.find('<');
-
- // Full name from clang AST doesn't contain '<' so this type_die isn't
- // a template parameter, but we're expecting template parameters, so
- // bail.
- if (i == llvm::StringRef::npos)
- return true;
-
- llvm::StringRef test_template_params =
- test_base_name.slice(i, test_base_name.size());
- // Bail if template parameters don't match.
- if (test_template_params != template_params.GetStringRef())
- return true;
- }
+ if (log) {
+ DWARFDeclContext type_dwarf_decl_ctx = type_die.GetDWARFDeclContext();
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindDefinitionTypeDIE(tag={0} ({1}), name='{2}') "
+ "trying die={3:x16} ({4})",
+ DW_TAG_value_to_name(tag), tag, die.GetName(), type_die.GetOffset(),
+ type_dwarf_decl_ctx.GetQualifiedName());
+ }
- type_sp = resolved_type->shared_from_this();
- return false;
- });
- }
- return type_sp;
+ result = type_die;
+ return false;
+ });
+ return result;
}
TypeSP SymbolFileDWARF::ParseType(const SymbolContext &sc, const DWARFDIE &die,
@@ -3624,8 +3538,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
if ((parent_tag == DW_TAG_compile_unit ||
parent_tag == DW_TAG_partial_unit) &&
Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU())))
- mangled =
- GetDWARFDeclContext(die).GetQualifiedNameAsConstString().GetCString();
+ mangled = die.GetDWARFDeclContext()
+ .GetQualifiedNameAsConstString()
+ .GetCString();
}
if (tag == DW_TAG_formal_parameter)
@@ -4450,14 +4365,6 @@ SymbolFileDWARF::GetContainingDeclContext(const DWARFDIE &die) {
return CompilerDeclContext();
}
-DWARFDeclContext SymbolFileDWARF::GetDWARFDeclContext(const DWARFDIE &die) {
- if (!die.IsValid())
- return {};
- DWARFDeclContext dwarf_decl_ctx =
- die.GetDIE()->GetDWARFDeclContext(die.GetCU());
- return dwarf_decl_ctx;
-}
-
LanguageType SymbolFileDWARF::LanguageTypeFromDWARF(uint64_t val) {
// Note: user languages between lo_user and hi_user must be handled
// explicitly here.
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 7282c08c6857..8469248872a4 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -241,6 +241,15 @@ public:
return m_external_type_modules;
}
+ /// Given a DIERef, find the correct SymbolFileDWARF.
+ ///
+ /// A DIERef contains a file index that can uniquely identify a N_OSO file for
+ /// DWARF in .o files on mac, or a .dwo or .dwp file index for split DWARF.
+ /// Calling this function will find the correct symbol file to use so that
+ /// further lookups can be done on the correct symbol file so that the DIE
+ /// offset makes sense in the DIERef.
+ virtual SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref);
+
virtual DWARFDIE GetDIE(const DIERef &die_ref);
DWARFDIE GetDIE(lldb::user_id_t uid);
@@ -296,8 +305,6 @@ public:
static CompilerDeclContext GetContainingDeclContext(const DWARFDIE &die);
- static DWARFDeclContext GetDWARFDeclContext(const DWARFDIE &die);
-
static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val);
static lldb::LanguageType GetLanguage(DWARFUnit &unit);
@@ -353,8 +360,7 @@ public:
SymbolFileDWARFDebugMap *GetDebugMapSymfile();
- virtual lldb::TypeSP
- FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die);
+ virtual DWARFDIE FindDefinitionDIE(const DWARFDIE &die);
virtual lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE(
const DWARFDIE &die, ConstString type_name, bool must_be_implementation);
@@ -461,8 +467,6 @@ protected:
FindBlockContainingSpecification(const DWARFDIE &die,
dw_offset_t spec_block_die_offset);
- bool DIEDeclContextsMatch(const DWARFDIE &die1, const DWARFDIE &die2);
-
bool ClassContainsSelector(const DWARFDIE &class_die, ConstString selector);
/// Parse call site entries (DW_TAG_call_site), including any nested call site
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index f066f13d51c5..64cde16433ef 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1147,14 +1147,13 @@ SymbolFileDWARFDebugMap::ParseCallEdgesInFunction(
return {};
}
-TypeSP SymbolFileDWARFDebugMap::FindDefinitionTypeForDWARFDeclContext(
- const DWARFDIE &die) {
- TypeSP type_sp;
+DWARFDIE SymbolFileDWARFDebugMap::FindDefinitionDIE(const DWARFDIE &die) {
+ DWARFDIE result;
ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
- type_sp = oso_dwarf->FindDefinitionTypeForDWARFDeclContext(die);
- return type_sp ? IterationAction::Stop : IterationAction::Continue;
+ result = oso_dwarf->FindDefinitionDIE(die);
+ return result ? IterationAction::Stop : IterationAction::Continue;
});
- return type_sp;
+ return result;
}
bool SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type(
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index de22dd676eef..7d5516b92737 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -277,7 +277,7 @@ protected:
CompileUnitInfo *GetCompileUnitInfo(SymbolFileDWARF *oso_dwarf);
- lldb::TypeSP FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die);
+ DWARFDIE FindDefinitionDIE(const DWARFDIE &die);
bool Supports_DW_AT_APPLE_objc_complete_type(SymbolFileDWARF *skip_dwarf_oso);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
index 71c9997e4c82..4a8c532a0d2a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
@@ -125,9 +125,8 @@ UniqueDWARFASTTypeMap &SymbolFileDWARFDwo::GetUniqueDWARFASTTypeMap() {
return GetBaseSymbolFile().GetUniqueDWARFASTTypeMap();
}
-lldb::TypeSP
-SymbolFileDWARFDwo::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) {
- return GetBaseSymbolFile().FindDefinitionTypeForDWARFDeclContext(die);
+DWARFDIE SymbolFileDWARFDwo::FindDefinitionDIE(const DWARFDIE &die) {
+ return GetBaseSymbolFile().FindDefinitionDIE(die);
}
lldb::TypeSP SymbolFileDWARFDwo::FindCompleteObjCDefinitionTypeForDIE(
@@ -174,3 +173,8 @@ bool SymbolFileDWARFDwo::GetDebugInfoHadFrameVariableErrors() const {
void SymbolFileDWARFDwo::SetDebugInfoHadFrameVariableErrors() {
return GetBaseSymbolFile().SetDebugInfoHadFrameVariableErrors();
}
+
+SymbolFileDWARF *
+SymbolFileDWARFDwo::GetDIERefSymbolFile(const DIERef &die_ref) {
+ return GetBaseSymbolFile().GetDIERefSymbolFile(die_ref);
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
index 1500540424b5..3bd0a2d25a5a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
@@ -67,6 +67,8 @@ public:
bool GetDebugInfoHadFrameVariableErrors() const override;
void SetDebugInfoHadFrameVariableErrors() override;
+ SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref) override;
+
protected:
DIEToTypePtr &GetDIEToType() override;
@@ -76,8 +78,7 @@ protected:
UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() override;
- lldb::TypeSP
- FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) override;
+ DWARFDIE FindDefinitionDIE(const DWARFDIE &die) override;
lldb::TypeSP
FindCompleteObjCDefinitionTypeForDIE(const DWARFDIE &die,
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 369ae46cf264..cd1c500d9aa2 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2574,6 +2574,128 @@ TypeSystemClang::GetDeclContextForType(clang::QualType type) {
return nullptr;
}
+/// Returns the clang::RecordType of the specified \ref qual_type. This
+/// function will try to complete the type if necessary (and allowed
+/// by the specified \ref allow_completion). If we fail to return a *complete*
+/// type, returns nullptr.
+static const clang::RecordType *GetCompleteRecordType(clang::ASTContext *ast,
+ clang::QualType qual_type,
+ bool allow_completion) {
+ assert(qual_type->isRecordType());
+
+ const auto *tag_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+
+ clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+
+ // RecordType with no way of completing it, return the plain
+ // TagType.
+ if (!cxx_record_decl || !cxx_record_decl->hasExternalLexicalStorage())
+ return tag_type;
+
+ const bool is_complete = cxx_record_decl->isCompleteDefinition();
+ const bool fields_loaded =
+ cxx_record_decl->hasLoadedFieldsFromExternalStorage();
+
+ // Already completed this type, nothing to be done.
+ if (is_complete && fields_loaded)
+ return tag_type;
+
+ if (!allow_completion)
+ return nullptr;
+
+ // Call the field_begin() accessor to for it to use the external source
+ // to load the fields...
+ //
+ // TODO: if we need to complete the type but have no external source,
+ // shouldn't we error out instead?
+ clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
+ if (external_ast_source) {
+ external_ast_source->CompleteType(cxx_record_decl);
+ if (cxx_record_decl->isCompleteDefinition()) {
+ cxx_record_decl->field_begin();
+ cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
+ }
+ }
+
+ return tag_type;
+}
+
+/// Returns the clang::EnumType of the specified \ref qual_type. This
+/// function will try to complete the type if necessary (and allowed
+/// by the specified \ref allow_completion). If we fail to return a *complete*
+/// type, returns nullptr.
+static const clang::EnumType *GetCompleteEnumType(clang::ASTContext *ast,
+ clang::QualType qual_type,
+ bool allow_completion) {
+ assert(qual_type->isEnumeralType());
+ assert(ast);
+
+ const clang::EnumType *enum_type =
+ llvm::cast<clang::EnumType>(qual_type.getTypePtr());
+
+ auto *tag_decl = enum_type->getAsTagDecl();
+ assert(tag_decl);
+
+ // Already completed, nothing to be done.
+ if (tag_decl->getDefinition())
+ return enum_type;
+
+ if (!allow_completion)
+ return nullptr;
+
+ // No definition but can't complete it, error out.
+ if (!tag_decl->hasExternalLexicalStorage())
+ return nullptr;
+
+ // We can't complete the type without an external source.
+ clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
+ if (!external_ast_source)
+ return nullptr;
+
+ external_ast_source->CompleteType(tag_decl);
+ return enum_type;
+}
+
+/// Returns the clang::ObjCObjectType of the specified \ref qual_type. This
+/// function will try to complete the type if necessary (and allowed
+/// by the specified \ref allow_completion). If we fail to return a *complete*
+/// type, returns nullptr.
+static const clang::ObjCObjectType *
+GetCompleteObjCObjectType(clang::ASTContext *ast, QualType qual_type,
+ bool allow_completion) {
+ assert(qual_type->isObjCObjectType());
+ assert(ast);
+
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::cast<clang::ObjCObjectType>(qual_type);
+
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ // We currently can't complete objective C types through the newly added
+ // ASTContext because it only supports TagDecl objects right now...
+ if (!class_interface_decl)
+ return objc_class_type;
+
+ // Already complete, nothing to be done.
+ if (class_interface_decl->getDefinition())
+ return objc_class_type;
+
+ if (!allow_completion)
+ return nullptr;
+
+ // No definition but can't complete it, error out.
+ if (!class_interface_decl->hasExternalLexicalStorage())
+ return nullptr;
+
+ // We can't complete the type without an external source.
+ clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
+ if (!external_ast_source)
+ return nullptr;
+
+ external_ast_source->CompleteType(class_interface_decl);
+ return objc_class_type;
+}
+
static bool GetCompleteQualType(clang::ASTContext *ast,
clang::QualType qual_type,
bool allow_completion = true) {
@@ -2591,92 +2713,26 @@ static bool GetCompleteQualType(clang::ASTContext *ast,
allow_completion);
} break;
case clang::Type::Record: {
- clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- if (cxx_record_decl->hasExternalLexicalStorage()) {
- const bool is_complete = cxx_record_decl->isCompleteDefinition();
- const bool fields_loaded =
- cxx_record_decl->hasLoadedFieldsFromExternalStorage();
- if (is_complete && fields_loaded)
- return true;
+ if (const auto *RT =
+ GetCompleteRecordType(ast, qual_type, allow_completion))
+ return !RT->isIncompleteType();
- if (!allow_completion)
- return false;
-
- // Call the field_begin() accessor to for it to use the external source
- // to load the fields...
- clang::ExternalASTSource *external_ast_source =
- ast->getExternalSource();
- if (external_ast_source) {
- external_ast_source->CompleteType(cxx_record_decl);
- if (cxx_record_decl->isCompleteDefinition()) {
- cxx_record_decl->field_begin();
- cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
- }
- }
- }
- }
- const clang::TagType *tag_type =
- llvm::cast<clang::TagType>(qual_type.getTypePtr());
- return !tag_type->isIncompleteType();
+ return false;
} break;
case clang::Type::Enum: {
- const clang::TagType *tag_type =
- llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
- if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
- if (tag_decl) {
- if (tag_decl->getDefinition())
- return true;
-
- if (!allow_completion)
- return false;
-
- if (tag_decl->hasExternalLexicalStorage()) {
- if (ast) {
- clang::ExternalASTSource *external_ast_source =
- ast->getExternalSource();
- if (external_ast_source) {
- external_ast_source->CompleteType(tag_decl);
- return !tag_type->isIncompleteType();
- }
- }
- }
- return false;
- }
- }
+ if (const auto *ET = GetCompleteEnumType(ast, qual_type, allow_completion))
+ return !ET->isIncompleteType();
+ return false;
} break;
case clang::Type::ObjCObject:
case clang::Type::ObjCInterface: {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- // We currently can't complete objective C types through the newly added
- // ASTContext because it only supports TagDecl objects right now...
- if (class_interface_decl) {
- if (class_interface_decl->getDefinition())
- return true;
+ if (const auto *OT =
+ GetCompleteObjCObjectType(ast, qual_type, allow_completion))
+ return !OT->isIncompleteType();
- if (!allow_completion)
- return false;
-
- if (class_interface_decl->hasExternalLexicalStorage()) {
- if (ast) {
- clang::ExternalASTSource *external_ast_source =
- ast->getExternalSource();
- if (external_ast_source) {
- external_ast_source->CompleteType(class_interface_decl);
- return !objc_class_type->isIncompleteType();
- }
- }
- }
- return false;
- }
- }
+ return false;
} break;
case clang::Type::Attributed:
@@ -4688,11 +4744,11 @@ TypeSystemClang::GetBitSize(lldb::opaque_compiler_type_t type,
ExecutionContext exe_ctx(exe_scope);
Process *process = exe_ctx.GetProcessPtr();
if (process) {
- ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);
- if (objc_runtime) {
- uint64_t bit_size = 0;
- if (objc_runtime->GetTypeBitSize(GetType(qual_type), bit_size))
- return bit_size;
+ if (ObjCLanguageRuntime *objc_runtime =
+ ObjCLanguageRuntime::Get(*process)) {
+ if (std::optional<uint64_t> bit_size =
+ objc_runtime->GetTypeBitSize(GetType(qual_type)))
+ return *bit_size;
}
} else {
static bool g_printed = false;
@@ -5003,6 +5059,11 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
case clang::BuiltinType::UnresolvedTemplate:
break;
+
+ // AMD GPU builtin types.
+#define AMDGPU_TYPE(Name, Id, SingletonId) case clang::BuiltinType::Id:
+#include "clang/Basic/AMDGPUTypes.def"
+ break;
}
break;
// All pointer types are represented as unsigned integer encodings. We may
@@ -9112,10 +9173,8 @@ static CompilerContextKind GetCompilerKind(clang::Decl::Kind clang_kind,
if (decl_ctx) {
if (decl_ctx->isFunctionOrMethod())
return CompilerContextKind::Function;
- else if (decl_ctx->isRecord())
- return (CompilerContextKind)((uint16_t)CompilerContextKind::Class |
- (uint16_t)CompilerContextKind::Struct |
- (uint16_t)CompilerContextKind::Union);
+ if (decl_ctx->isRecord())
+ return CompilerContextKind::ClassOrStruct | CompilerContextKind::Union;
}
break;
}
diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
index dc54d13ae23c..f3df8a2c27f5 100644
--- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -423,8 +423,7 @@ void DWARFCallFrameInfo::GetFDEIndex() {
if (m_fde_index_initialized) // if two threads hit the locker
return;
- LLDB_SCOPED_TIMERF("%s - %s", LLVM_PRETTY_FUNCTION,
- m_objfile.GetFileSpec().GetFilename().AsCString(""));
+ LLDB_SCOPED_TIMERF("%s", m_objfile.GetFileSpec().GetFilename().AsCString(""));
bool clear_address_zeroth_bit = false;
if (ArchSpec arch = m_objfile.GetArchitecture()) {
diff --git a/lldb/source/Symbol/LineEntry.cpp b/lldb/source/Symbol/LineEntry.cpp
index 461399e0326e..19e9bb561375 100644
--- a/lldb/source/Symbol/LineEntry.cpp
+++ b/lldb/source/Symbol/LineEntry.cpp
@@ -244,7 +244,9 @@ void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) {
if (target_sp) {
// Apply any file remappings to our file.
if (auto new_file_spec = target_sp->GetSourcePathMap().FindFile(
- original_file_sp->GetSpecOnly()))
- file_sp->Update(*new_file_spec);
+ original_file_sp->GetSpecOnly())) {
+ file_sp = std::make_shared<SupportFile>(*new_file_spec,
+ original_file_sp->GetChecksum());
+ }
}
}
diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp
index 585808ace15c..e76574795733 100644
--- a/lldb/source/Symbol/Type.cpp
+++ b/lldb/source/Symbol/Type.cpp
@@ -75,20 +75,18 @@ bool lldb_private::contextMatches(llvm::ArrayRef<CompilerContext> context_chain,
static CompilerContextKind ConvertTypeClass(lldb::TypeClass type_class) {
if (type_class == eTypeClassAny)
return CompilerContextKind::AnyType;
- uint16_t result = 0;
- if (type_class & lldb::eTypeClassClass)
- result |= (uint16_t)CompilerContextKind::Class;
- if (type_class & lldb::eTypeClassStruct)
- result |= (uint16_t)CompilerContextKind::Struct;
+ CompilerContextKind result = {};
+ if (type_class & (lldb::eTypeClassClass | lldb::eTypeClassStruct))
+ result |= CompilerContextKind::ClassOrStruct;
if (type_class & lldb::eTypeClassUnion)
- result |= (uint16_t)CompilerContextKind::Union;
+ result |= CompilerContextKind::Union;
if (type_class & lldb::eTypeClassEnumeration)
- result |= (uint16_t)CompilerContextKind::Enum;
+ result |= CompilerContextKind::Enum;
if (type_class & lldb::eTypeClassFunction)
- result |= (uint16_t)CompilerContextKind::Function;
+ result |= CompilerContextKind::Function;
if (type_class & lldb::eTypeClassTypedef)
- result |= (uint16_t)CompilerContextKind::Typedef;
- return (CompilerContextKind)result;
+ result |= CompilerContextKind::Typedef;
+ return result;
}
TypeQuery::TypeQuery(llvm::StringRef name, TypeQueryOptions options)
@@ -207,11 +205,8 @@ void CompilerContext::Dump(Stream &s) const {
case CompilerContextKind::Namespace:
s << "Namespace";
break;
- case CompilerContextKind::Class:
- s << "Class";
- break;
- case CompilerContextKind::Struct:
- s << "Structure";
+ case CompilerContextKind::ClassOrStruct:
+ s << "ClassOrStruct";
break;
case CompilerContextKind::Union:
s << "Union";
diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp
index 4956f10a0b0a..931ce1b0203a 100644
--- a/lldb/source/Symbol/TypeSystem.cpp
+++ b/lldb/source/Symbol/TypeSystem.cpp
@@ -335,3 +335,14 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
}
return GetTypeSystemForLanguage(language);
}
+
+bool TypeSystem::SupportsLanguageStatic(lldb::LanguageType language) {
+ if (language == eLanguageTypeUnknown || language >= eNumLanguageTypes)
+ return false;
+
+ LanguageSet languages =
+ PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
+ if (languages.Empty())
+ return false;
+ return languages[language];
+}
diff --git a/lldb/source/Target/InstrumentationRuntime.cpp b/lldb/source/Target/InstrumentationRuntime.cpp
index 9f22a1be20cc..9da06e8e155a 100644
--- a/lldb/source/Target/InstrumentationRuntime.cpp
+++ b/lldb/source/Target/InstrumentationRuntime.cpp
@@ -60,6 +60,8 @@ void InstrumentationRuntime::ModulesDidLoad(
if (CheckIfRuntimeIsValid(module_sp)) {
SetRuntimeModuleSP(module_sp);
Activate();
+ if (!IsActive())
+ SetRuntimeModuleSP({}); // Don't cache module if activation failed.
return false; // Stop iterating, we're done.
}
}
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index ee1f92470e16..b3116545b91d 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -768,41 +768,6 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec,
const FileSpecList *module_search_paths_ptr) {
Status error;
- if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
- if (module_spec.GetArchitecture().IsValid()) {
- error = ModuleList::GetSharedModule(module_spec, exe_module_sp,
- module_search_paths_ptr, nullptr,
- nullptr);
- } 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
- ModuleSpec arch_module_spec(module_spec);
- ArchSpec process_host_arch;
- for (const ArchSpec &arch :
- GetSupportedArchitectures(process_host_arch)) {
- arch_module_spec.GetArchitecture() = arch;
- error = ModuleList::GetSharedModule(arch_module_spec, exe_module_sp,
- module_search_paths_ptr, nullptr,
- nullptr);
- // Did we find an executable using one of the
- if (error.Success() && exe_module_sp)
- break;
- }
- }
- } else {
- error.SetErrorStringWithFormat(
- "'%s' does not exist", module_spec.GetFileSpec().GetPath().c_str());
- }
- return error;
-}
-
-Status
-Platform::ResolveRemoteExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) {
- Status error;
-
// We may connect to a process and use the provided executable (Don't use
// local $PATH).
ModuleSpec resolved_module_spec(module_spec);
@@ -822,9 +787,9 @@ Platform::ResolveRemoteExecutable(const ModuleSpec &module_spec,
return error;
exe_module_sp.reset();
}
- // No valid architecture was specified or the exact arch wasn't found so
- // 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
+ // No valid architecture was specified or the exact arch wasn't found.
+ // 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;
llvm::ListSeparator LS;
ArchSpec process_host_arch;
@@ -833,12 +798,10 @@ Platform::ResolveRemoteExecutable(const ModuleSpec &module_spec,
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();
+ error.SetErrorToGenericError();
}
arch_names << LS << arch.GetArchitectureName();
@@ -1516,8 +1479,7 @@ Platform::GetCachedExecutable(ModuleSpec &module_spec,
Status error = GetRemoteSharedModule(
module_spec, nullptr, module_sp,
[&](const ModuleSpec &spec) {
- return ResolveRemoteExecutable(spec, module_sp,
- module_search_paths_ptr);
+ return ResolveExecutable(spec, module_sp, module_search_paths_ptr);
},
nullptr);
if (error.Success()) {
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 1e321f8bde39..6fac0df1d7a6 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -2007,6 +2007,129 @@ size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) {
}
}
+void Process::DoFindInMemory(lldb::addr_t start_addr, lldb::addr_t end_addr,
+ const uint8_t *buf, size_t size,
+ AddressRanges &matches, size_t alignment,
+ size_t max_matches) {
+ // Inputs are already validated in FindInMemory() functions.
+ assert(buf != nullptr);
+ assert(size > 0);
+ assert(alignment > 0);
+ assert(max_matches > 0);
+ assert(start_addr != LLDB_INVALID_ADDRESS);
+ assert(end_addr != LLDB_INVALID_ADDRESS);
+ assert(start_addr < end_addr);
+
+ lldb::addr_t start = llvm::alignTo(start_addr, alignment);
+ while (matches.size() < max_matches && (start + size) < end_addr) {
+ const lldb::addr_t found_addr = FindInMemory(start, end_addr, buf, size);
+ if (found_addr == LLDB_INVALID_ADDRESS)
+ break;
+
+ if (found_addr % alignment) {
+ // We need to check the alignment because the FindInMemory uses a special
+ // algorithm to efficiently search mememory but doesn't support alignment.
+ start = llvm::alignTo(start + 1, alignment);
+ continue;
+ }
+
+ matches.emplace_back(found_addr, size);
+ start = found_addr + alignment;
+ }
+}
+
+AddressRanges Process::FindRangesInMemory(const uint8_t *buf, uint64_t size,
+ const AddressRanges &ranges,
+ size_t alignment, size_t max_matches,
+ Status &error) {
+ AddressRanges matches;
+ if (buf == nullptr) {
+ error.SetErrorString("buffer is null");
+ return matches;
+ }
+ if (size == 0) {
+ error.SetErrorString("buffer size is zero");
+ return matches;
+ }
+ if (ranges.empty()) {
+ error.SetErrorString("empty ranges");
+ return matches;
+ }
+ if (alignment == 0) {
+ error.SetErrorString("alignment must be greater than zero");
+ return matches;
+ }
+ if (max_matches == 0) {
+ error.SetErrorString("max_matches must be greater than zero");
+ return matches;
+ }
+
+ int resolved_ranges = 0;
+ Target &target = GetTarget();
+ for (size_t i = 0; i < ranges.size(); ++i) {
+ if (matches.size() >= max_matches)
+ break;
+ const AddressRange &range = ranges[i];
+ if (range.IsValid() == false)
+ continue;
+
+ const lldb::addr_t start_addr =
+ range.GetBaseAddress().GetLoadAddress(&target);
+ if (start_addr == LLDB_INVALID_ADDRESS)
+ continue;
+
+ ++resolved_ranges;
+ const lldb::addr_t end_addr = start_addr + range.GetByteSize();
+ DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment,
+ max_matches);
+ }
+
+ if (resolved_ranges > 0)
+ error.Clear();
+ else
+ error.SetErrorString("unable to resolve any ranges");
+
+ return matches;
+}
+
+lldb::addr_t Process::FindInMemory(const uint8_t *buf, uint64_t size,
+ const AddressRange &range, size_t alignment,
+ Status &error) {
+ if (buf == nullptr) {
+ error.SetErrorString("buffer is null");
+ return LLDB_INVALID_ADDRESS;
+ }
+ if (size == 0) {
+ error.SetErrorString("buffer size is zero");
+ return LLDB_INVALID_ADDRESS;
+ }
+ if (!range.IsValid()) {
+ error.SetErrorString("range is invalid");
+ return LLDB_INVALID_ADDRESS;
+ }
+ if (alignment == 0) {
+ error.SetErrorString("alignment must be greater than zero");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ Target &target = GetTarget();
+ const lldb::addr_t start_addr =
+ range.GetBaseAddress().GetLoadAddress(&target);
+ if (start_addr == LLDB_INVALID_ADDRESS) {
+ error.SetErrorString("range load address is invalid");
+ return LLDB_INVALID_ADDRESS;
+ }
+ const lldb::addr_t end_addr = start_addr + range.GetByteSize();
+
+ AddressRanges matches;
+ DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment, 1);
+ if (matches.empty())
+ return LLDB_INVALID_ADDRESS;
+
+ error.Clear();
+ return matches[0].GetBaseAddress().GetLoadAddress(&target);
+}
+
size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str,
Status &error) {
char buf[256];
@@ -5924,7 +6047,9 @@ void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) {
if (!sc.module_sp)
return;
LanguageType language = sc.GetLanguage();
- if (language == eLanguageTypeUnknown)
+ if (language == eLanguageTypeUnknown ||
+ language == lldb::eLanguageTypeAssembly ||
+ language == lldb::eLanguageTypeMipsAssembler)
return;
LanguageSet plugins =
PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
diff --git a/lldb/source/Target/RegisterFlags.cpp b/lldb/source/Target/RegisterFlags.cpp
index 5274960587bf..976e03870ad9 100644
--- a/lldb/source/Target/RegisterFlags.cpp
+++ b/lldb/source/Target/RegisterFlags.cpp
@@ -12,17 +12,42 @@
#include "llvm/ADT/StringExtras.h"
+#include <limits>
#include <numeric>
#include <optional>
using namespace lldb_private;
RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end)
- : m_name(std::move(name)), m_start(start), m_end(end) {
+ : m_name(std::move(name)), m_start(start), m_end(end),
+ m_enum_type(nullptr) {
assert(m_start <= m_end && "Start bit must be <= end bit.");
}
-void RegisterFlags::Field::log(Log *log) const {
+RegisterFlags::Field::Field(std::string name, unsigned bit_position)
+ : m_name(std::move(name)), m_start(bit_position), m_end(bit_position),
+ m_enum_type(nullptr) {}
+
+RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end,
+ const FieldEnum *enum_type)
+ : m_name(std::move(name)), m_start(start), m_end(end),
+ m_enum_type(enum_type) {
+ if (m_enum_type) {
+ // Check that all values fit into this field. The XML parser will also
+ // do this check so at runtime nothing should fail this check.
+ // We can also make enums in C++ at compile time, which might fail this
+ // check, so we catch them before it makes it into a release.
+ uint64_t max_value = GetMaxValue();
+ UNUSED_IF_ASSERT_DISABLED(max_value);
+ for (const auto &enumerator : m_enum_type->GetEnumerators()) {
+ UNUSED_IF_ASSERT_DISABLED(enumerator);
+ assert(enumerator.m_value <= max_value &&
+ "Enumerator value exceeds maximum value for this field");
+ }
+ }
+}
+
+void RegisterFlags::Field::DumpToLog(Log *log) const {
LLDB_LOG(log, " Name: \"{0}\" Start: {1} End: {2}", m_name.c_str(), m_start,
m_end);
}
@@ -53,11 +78,36 @@ unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const {
return lhs_start - rhs_end - 1;
}
-void RegisterFlags::SetFields(const std::vector<Field> &fields) {
- // We expect that the XML processor will discard anything describing flags but
- // with no fields.
- assert(fields.size() && "Some fields must be provided.");
+unsigned RegisterFlags::Field::GetSizeInBits(unsigned start, unsigned end) {
+ return end - start + 1;
+}
+
+unsigned RegisterFlags::Field::GetSizeInBits() const {
+ return GetSizeInBits(m_start, m_end);
+}
+
+uint64_t RegisterFlags::Field::GetMaxValue(unsigned start, unsigned end) {
+ uint64_t max = std::numeric_limits<uint64_t>::max();
+ unsigned bits = GetSizeInBits(start, end);
+ // If the field is >= 64 bits the shift below would be undefined.
+ // We assume the GDB client has discarded any field that would fail this
+ // assert, it's only to check information we define directly in C++.
+ assert(bits <= 64 && "Cannot handle field with size > 64 bits");
+ if (bits < 64) {
+ max = ((uint64_t)1 << bits) - 1;
+ }
+ return max;
+}
+
+uint64_t RegisterFlags::Field::GetMaxValue() const {
+ return GetMaxValue(m_start, m_end);
+}
+
+uint64_t RegisterFlags::Field::GetMask() const {
+ return GetMaxValue() << m_start;
+}
+void RegisterFlags::SetFields(const std::vector<Field> &fields) {
// We expect that these are unsorted but do not overlap.
// They could fill the register but may have gaps.
std::vector<Field> provided_fields = fields;
@@ -102,10 +152,10 @@ RegisterFlags::RegisterFlags(std::string id, unsigned size,
SetFields(fields);
}
-void RegisterFlags::log(Log *log) const {
+void RegisterFlags::DumpToLog(Log *log) const {
LLDB_LOG(log, "ID: \"{0}\" Size: {1}", m_id.c_str(), m_size);
for (const Field &field : m_fields)
- field.log(log);
+ field.DumpToLog(log);
}
static StreamString FormatCell(const StreamString &content,
@@ -190,6 +240,142 @@ std::string RegisterFlags::AsTable(uint32_t max_width) const {
return table;
}
+// Print enums as:
+// value = name, value2 = name2
+// Subject to the limits of the terminal width.
+static void DumpEnumerators(StreamString &strm, size_t indent,
+ size_t current_width, uint32_t max_width,
+ const FieldEnum::Enumerators &enumerators) {
+ for (auto it = enumerators.cbegin(); it != enumerators.cend(); ++it) {
+ StreamString enumerator_strm;
+ // The first enumerator of a line doesn't need to be separated.
+ if (current_width != indent)
+ enumerator_strm << ' ';
+
+ enumerator_strm.Printf("%" PRIu64 " = %s", it->m_value, it->m_name.c_str());
+
+ // Don't put "," after the last enumerator.
+ if (std::next(it) != enumerators.cend())
+ enumerator_strm << ",";
+
+ llvm::StringRef enumerator_string = enumerator_strm.GetString();
+ // If printing the next enumerator would take us over the width, start
+ // a new line. However, if we're printing the first enumerator of this
+ // line, don't start a new one. Resulting in there being at least one per
+ // line.
+ //
+ // This means for very small widths we get:
+ // A: 0 = foo,
+ // 1 = bar
+ // Instead of:
+ // A:
+ // 0 = foo,
+ // 1 = bar
+ if ((current_width + enumerator_string.size() > max_width) &&
+ current_width != indent) {
+ current_width = indent;
+ strm << '\n' << std::string(indent, ' ');
+ // We're going to a new line so we don't need a space before the
+ // name of the enumerator.
+ enumerator_string = enumerator_string.drop_front();
+ }
+
+ current_width += enumerator_string.size();
+ strm << enumerator_string;
+ }
+}
+
+std::string RegisterFlags::DumpEnums(uint32_t max_width) const {
+ StreamString strm;
+ bool printed_enumerators_once = false;
+
+ for (const auto &field : m_fields) {
+ const FieldEnum *enum_type = field.GetEnum();
+ if (!enum_type)
+ continue;
+
+ const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators();
+ if (enumerators.empty())
+ continue;
+
+ // Break between enumerators of different fields.
+ if (printed_enumerators_once)
+ strm << "\n\n";
+ else
+ printed_enumerators_once = true;
+
+ std::string name_string = field.GetName() + ": ";
+ size_t indent = name_string.size();
+ size_t current_width = indent;
+
+ strm << name_string;
+
+ DumpEnumerators(strm, indent, current_width, max_width, enumerators);
+ }
+
+ return strm.GetString().str();
+}
+
+void RegisterFlags::EnumsToXML(Stream &strm, llvm::StringSet<> &seen) const {
+ for (const Field &field : m_fields)
+ if (const FieldEnum *enum_type = field.GetEnum()) {
+ const std::string &id = enum_type->GetID();
+ if (!seen.contains(id)) {
+ enum_type->ToXML(strm, GetSize());
+ seen.insert(id);
+ }
+ }
+}
+
+void FieldEnum::ToXML(Stream &strm, unsigned size) const {
+ // Example XML:
+ // <enum id="foo" size="4">
+ // <evalue name="bar" value="1"/>
+ // </enum>
+ // Note that "size" is only emitted for GDB compatibility, LLDB does not need
+ // it.
+
+ strm.Indent();
+ strm << "<enum id=\"" << GetID() << "\" ";
+ // This is the size of the underlying enum type if this were a C type.
+ // In other words, the size of the register in bytes.
+ strm.Printf("size=\"%d\"", size);
+
+ const Enumerators &enumerators = GetEnumerators();
+ if (enumerators.empty()) {
+ strm << "/>\n";
+ return;
+ }
+
+ strm << ">\n";
+ strm.IndentMore();
+ for (const auto &enumerator : enumerators) {
+ strm.Indent();
+ enumerator.ToXML(strm);
+ strm.PutChar('\n');
+ }
+ strm.IndentLess();
+ strm.Indent("</enum>\n");
+}
+
+void FieldEnum::Enumerator::ToXML(Stream &strm) const {
+ std::string escaped_name;
+ llvm::raw_string_ostream escape_strm(escaped_name);
+ llvm::printHTMLEscaped(m_name, escape_strm);
+ strm.Printf("<evalue name=\"%s\" value=\"%" PRIu64 "\"/>",
+ escaped_name.c_str(), m_value);
+}
+
+void FieldEnum::Enumerator::DumpToLog(Log *log) const {
+ LLDB_LOG(log, " Name: \"{0}\" Value: {1}", m_name.c_str(), m_value);
+}
+
+void FieldEnum::DumpToLog(Log *log) const {
+ LLDB_LOG(log, "ID: \"{0}\"", m_id.c_str());
+ for (const auto &enumerator : GetEnumerators())
+ enumerator.DumpToLog(log);
+}
+
void RegisterFlags::ToXML(Stream &strm) const {
// Example XML:
// <flags id="cpsr_flags" size="4">
@@ -214,7 +400,9 @@ void RegisterFlags::ToXML(Stream &strm) const {
}
void RegisterFlags::Field::ToXML(Stream &strm) const {
- // Example XML:
+ // Example XML with an enum:
+ // <field name="correct" start="0" end="0" type="some_enum">
+ // Without:
// <field name="correct" start="0" end="0"/>
strm.Indent();
strm << "<field name=\"";
@@ -225,5 +413,17 @@ void RegisterFlags::Field::ToXML(Stream &strm) const {
strm << escaped_name << "\" ";
strm.Printf("start=\"%d\" end=\"%d\"", GetStart(), GetEnd());
+
+ if (const FieldEnum *enum_type = GetEnum())
+ strm << " type=\"" << enum_type->GetID() << "\"";
+
strm << "/>";
}
+
+FieldEnum::FieldEnum(std::string id, const Enumerators &enumerators)
+ : m_id(id), m_enumerators(enumerators) {
+ for (const auto &enumerator : m_enumerators) {
+ UNUSED_IF_ASSERT_DISABLED(enumerator);
+ assert(enumerator.m_name.size() && "Enumerator name cannot be empty");
+ }
+} \ No newline at end of file
diff --git a/lldb/source/Target/RemoteAwarePlatform.cpp b/lldb/source/Target/RemoteAwarePlatform.cpp
index 9a41a423cadd..5fc2d63876b9 100644
--- a/lldb/source/Target/RemoteAwarePlatform.cpp
+++ b/lldb/source/Target/RemoteAwarePlatform.cpp
@@ -30,142 +30,26 @@ bool RemoteAwarePlatform::GetModuleSpec(const FileSpec &module_file_spec,
}
Status RemoteAwarePlatform::ResolveExecutable(
- const ModuleSpec &module_spec, ModuleSP &exe_module_sp,
+ const ModuleSpec &module_spec, lldb::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);
+ // The host platform can resolve the path more aggressively.
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());
- }
+ FileSpec &resolved_file_spec = 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);
+ if (!FileSystem::Instance().Exists(resolved_file_spec)) {
+ resolved_module_spec.GetFileSpec().SetFile(resolved_file_spec.GetPath(),
+ FileSpec::Style::native);
+ FileSystem::Instance().Resolve(resolved_file_spec);
}
- // 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;
- llvm::ListSeparator LS;
- ArchSpec process_host_arch;
- for (const ArchSpec &arch :
- GetSupportedArchitectures(process_host_arch)) {
- resolved_module_spec.GetArchitecture() = arch;
- error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, nullptr, nullptr);
- // Did we find an executable using one of the
- if (error.Success()) {
- if (exe_module_sp && exe_module_sp->GetObjectFile())
- break;
- else
- error.SetErrorToGenericError();
- }
-
- arch_names << LS << arch.GetArchitectureName();
- }
-
- if (error.Fail() || !exe_module_sp) {
- if (FileSystem::Instance().Readable(
- resolved_module_spec.GetFileSpec())) {
- error.SetErrorStringWithFormatv(
- "'{0}' doesn't contain any '{1}' platform architectures: {2}",
- resolved_module_spec.GetFileSpec(), GetPluginName(),
- arch_names.GetData());
- } else {
- error.SetErrorStringWithFormat(
- "'%s' is not readable",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
- }
- }
+ if (!FileSystem::Instance().Exists(resolved_file_spec))
+ FileSystem::Instance().ResolveExecutableLocation(resolved_file_spec);
}
- return error;
+ return Platform::ResolveExecutable(resolved_module_spec, exe_module_sp,
+ module_search_paths_ptr);
}
Status RemoteAwarePlatform::RunShellCommand(
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 2a5300012511..583d1524881f 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -107,7 +107,8 @@ TargetStats::ToJSON(Target &target,
const lldb_private::StatisticsOptions &options) {
json::Object target_metrics_json;
ProcessSP process_sp = target.GetProcessSP();
- const bool summary_only = options.summary_only;
+ const bool summary_only = options.GetSummaryOnly();
+ const bool include_modules = options.GetIncludeModules();
if (!summary_only) {
CollectStats(target);
@@ -117,8 +118,9 @@ TargetStats::ToJSON(Target &target,
target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON());
target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON());
- target_metrics_json.try_emplace("moduleIdentifiers",
- std::move(json_module_uuid_array));
+ if (include_modules)
+ target_metrics_json.try_emplace("moduleIdentifiers",
+ std::move(json_module_uuid_array));
if (m_launch_or_attach_time && m_first_private_stop_time) {
double elapsed_time =
@@ -224,9 +226,11 @@ llvm::json::Value DebuggerStats::ReportStatistics(
Debugger &debugger, Target *target,
const lldb_private::StatisticsOptions &options) {
- const bool summary_only = options.summary_only;
- const bool load_all_debug_info = options.load_all_debug_info;
- const bool include_transcript = options.include_transcript;
+ const bool summary_only = options.GetSummaryOnly();
+ const bool load_all_debug_info = options.GetLoadAllDebugInfo();
+ const bool include_targets = options.GetIncludeTargets();
+ const bool include_modules = options.GetIncludeModules();
+ const bool include_transcript = options.GetIncludeTranscript();
json::Array json_targets;
json::Array json_modules;
@@ -314,7 +318,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
if (module_stat.debug_info_had_incomplete_types)
++num_modules_with_incomplete_types;
- if (!summary_only) {
+ if (include_modules) {
module_stat.identifier = (intptr_t)module;
module_stat.path = module->GetFileSpec().GetPath();
if (ConstString object_name = module->GetObjectName()) {
@@ -347,13 +351,15 @@ llvm::json::Value DebuggerStats::ReportStatistics(
{"totalSymbolTableStripped", num_stripped_modules},
};
- if (target) {
- json_targets.emplace_back(target->ReportStatistics(options));
- } else {
- for (const auto &target : debugger.GetTargetList().Targets())
+ if (include_targets) {
+ if (target) {
json_targets.emplace_back(target->ReportStatistics(options));
+ } else {
+ for (const auto &target : debugger.GetTargetList().Targets())
+ json_targets.emplace_back(target->ReportStatistics(options));
+ }
+ global_stats.try_emplace("targets", std::move(json_targets));
}
- global_stats.try_emplace("targets", std::move(json_targets));
ConstStringStats const_string_stats;
json::Object json_memory{
@@ -362,10 +368,13 @@ llvm::json::Value DebuggerStats::ReportStatistics(
global_stats.try_emplace("memory", std::move(json_memory));
if (!summary_only) {
json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();
- global_stats.try_emplace("modules", std::move(json_modules));
global_stats.try_emplace("commands", std::move(cmd_stats));
}
+ if (include_modules) {
+ global_stats.try_emplace("modules", std::move(json_modules));
+ }
+
if (include_transcript) {
// When transcript is available, add it to the to-be-returned statistics.
//
diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp
index d6de6b3c3cf0..373555324ba6 100644
--- a/lldb/source/Target/ThreadPlanPython.cpp
+++ b/lldb/source/Target/ThreadPlanPython.cpp
@@ -10,6 +10,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -32,6 +33,26 @@ ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name,
eVoteNoOpinion, eVoteNoOpinion),
m_class_name(class_name), m_args_data(args_data), m_did_push(false),
m_stop_others(false) {
+ ScriptInterpreter *interpreter = GetScriptInterpreter();
+ if (!interpreter) {
+ SetPlanComplete(false);
+ // FIXME: error handling
+ // error.SetErrorStringWithFormat(
+ // "ThreadPlanPython::%s () - ERROR: %s", __FUNCTION__,
+ // "Couldn't get script interpreter");
+ return;
+ }
+
+ m_interface = interpreter->CreateScriptedThreadPlanInterface();
+ if (!m_interface) {
+ SetPlanComplete(false);
+ // FIXME: error handling
+ // error.SetErrorStringWithFormat(
+ // "ThreadPlanPython::%s () - ERROR: %s", __FUNCTION__,
+ // "Script interpreter couldn't create Scripted Thread Plan Interface");
+ return;
+ }
+
SetIsControllingPlan(true);
SetOkayToDiscard(true);
SetPrivate(false);
@@ -60,13 +81,14 @@ 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 = GetScriptInterpreter();
- if (script_interp) {
- m_implementation_sp = script_interp->CreateScriptedThreadPlan(
- m_class_name.c_str(), m_args_data, m_error_str,
- this->shared_from_this());
- }
+ if (m_interface) {
+ auto obj_or_err = m_interface->CreatePluginObject(
+ m_class_name, this->shared_from_this(), m_args_data);
+ if (!obj_or_err) {
+ m_error_str = llvm::toString(obj_or_err.takeError());
+ SetPlanComplete(false);
+ } else
+ m_implementation_sp = *obj_or_err;
}
}
@@ -77,14 +99,13 @@ bool ThreadPlanPython::ShouldStop(Event *event_ptr) {
bool should_stop = true;
if (m_implementation_sp) {
- ScriptInterpreter *script_interp = GetScriptInterpreter();
- if (script_interp) {
- bool script_error;
- should_stop = script_interp->ScriptedThreadPlanShouldStop(
- m_implementation_sp, event_ptr, script_error);
- if (script_error)
- SetPlanComplete(false);
- }
+ auto should_stop_or_err = m_interface->ShouldStop(event_ptr);
+ if (!should_stop_or_err) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), should_stop_or_err.takeError(),
+ "Can't call ScriptedThreadPlan::ShouldStop.");
+ SetPlanComplete(false);
+ } else
+ should_stop = *should_stop_or_err;
}
return should_stop;
}
@@ -96,14 +117,13 @@ bool ThreadPlanPython::IsPlanStale() {
bool is_stale = true;
if (m_implementation_sp) {
- ScriptInterpreter *script_interp = GetScriptInterpreter();
- if (script_interp) {
- bool script_error;
- is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp,
- script_error);
- if (script_error)
- SetPlanComplete(false);
- }
+ auto is_stale_or_err = m_interface->IsStale();
+ if (!is_stale_or_err) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), is_stale_or_err.takeError(),
+ "Can't call ScriptedThreadPlan::IsStale.");
+ SetPlanComplete(false);
+ } else
+ is_stale = *is_stale_or_err;
}
return is_stale;
}
@@ -115,14 +135,14 @@ bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) {
bool explains_stop = true;
if (m_implementation_sp) {
- ScriptInterpreter *script_interp = GetScriptInterpreter();
- if (script_interp) {
- bool script_error;
- explains_stop = script_interp->ScriptedThreadPlanExplainsStop(
- m_implementation_sp, event_ptr, script_error);
- if (script_error)
- SetPlanComplete(false);
- }
+ auto explains_stop_or_error = m_interface->ExplainsStop(event_ptr);
+ if (!explains_stop_or_error) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread),
+ explains_stop_or_error.takeError(),
+ "Can't call ScriptedThreadPlan::ExplainsStop.");
+ SetPlanComplete(false);
+ } else
+ explains_stop = *explains_stop_or_error;
}
return explains_stop;
}
@@ -150,14 +170,8 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() {
LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION,
m_class_name.c_str());
lldb::StateType run_state = eStateRunning;
- if (m_implementation_sp) {
- ScriptInterpreter *script_interp = GetScriptInterpreter();
- if (script_interp) {
- bool script_error;
- run_state = script_interp->ScriptedThreadPlanGetRunState(
- m_implementation_sp, script_error);
- }
- }
+ if (m_implementation_sp)
+ run_state = m_interface->GetRunState();
return run_state;
}
@@ -168,12 +182,13 @@ void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) {
if (m_implementation_sp) {
ScriptInterpreter *script_interp = GetScriptInterpreter();
if (script_interp) {
- bool script_error;
- bool added_desc = script_interp->ScriptedThreadPlanGetStopDescription(
- m_implementation_sp, s, script_error);
- if (script_error || !added_desc)
+ auto desc_or_err = m_interface->GetStopDescription(s);
+ if (!desc_or_err || !*desc_or_err) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), desc_or_err.takeError(),
+ "Can't call ScriptedThreadPlan::GetStopDescription.");
s->Printf("Python thread plan implemented by class %s.",
m_class_name.c_str());
+ }
}
return;
}
diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt
index a3b0a405b413..e9954d66cd1a 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -39,6 +39,7 @@ add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES
DataExtractor.cpp
Diagnostics.cpp
Environment.cpp
+ ErrorMessages.cpp
Event.cpp
FileSpec.cpp
FileSpecList.cpp
diff --git a/lldb/source/Utility/ErrorMessages.cpp b/lldb/source/Utility/ErrorMessages.cpp
new file mode 100644
index 000000000000..aea5cb5f47c1
--- /dev/null
+++ b/lldb/source/Utility/ErrorMessages.cpp
@@ -0,0 +1,40 @@
+//===-- ErrorMessages.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/Utility/ErrorMessages.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace lldb_private {
+
+std::string toString(lldb::ExpressionResults e) {
+ switch (e) {
+ case lldb::eExpressionSetupError:
+ return "expression setup error";
+ case lldb::eExpressionParseError:
+ return "expression parse error";
+ case lldb::eExpressionResultUnavailable:
+ return "expression error";
+ case lldb::eExpressionCompleted:
+ return "expression completed successfully";
+ case lldb::eExpressionDiscarded:
+ return "expression discarded";
+ case lldb::eExpressionInterrupted:
+ return "expression interrupted";
+ case lldb::eExpressionHitBreakpoint:
+ return "expression hit breakpoint";
+ case lldb::eExpressionTimedOut:
+ return "expression timed out";
+ case lldb::eExpressionStoppedForDebug:
+ return "expression stop at entry point for debugging";
+ case lldb::eExpressionThreadVanished:
+ return "expression thread vanished";
+ }
+ llvm_unreachable("unhandled enumerator");
+}
+
+} // namespace lldb_private
diff --git a/lldb/source/Utility/ProcessInfo.cpp b/lldb/source/Utility/ProcessInfo.cpp
index 6b2a7114dfb4..845b337e246f 100644
--- a/lldb/source/Utility/ProcessInfo.cpp
+++ b/lldb/source/Utility/ProcessInfo.cpp
@@ -121,8 +121,8 @@ void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const {
if (m_pid != LLDB_INVALID_PROCESS_ID)
s.Printf(" pid = %" PRIu64 "\n", m_pid);
- if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
- s.Printf(" parent = %" PRIu64 "\n", m_parent_pid);
+ if (ParentProcessIDIsValid())
+ s.Printf(" parent = %" PRIu64 "\n", GetParentProcessID());
if (m_executable) {
s.Printf(" name = %s\n", m_executable.GetFilename().GetCString());
@@ -193,7 +193,8 @@ void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool show_args,
void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver,
bool show_args, bool verbose) const {
if (m_pid != LLDB_INVALID_PROCESS_ID) {
- s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
+ s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid,
+ (ParentProcessIDIsValid()) ? GetParentProcessID() : 0);
StreamString arch_strm;
if (m_arch.IsValid())
diff --git a/lldb/source/Utility/RegularExpression.cpp b/lldb/source/Utility/RegularExpression.cpp
index 20bebbfe15f2..026793462221 100644
--- a/lldb/source/Utility/RegularExpression.cpp
+++ b/lldb/source/Utility/RegularExpression.cpp
@@ -12,10 +12,11 @@
using namespace lldb_private;
-RegularExpression::RegularExpression(llvm::StringRef str)
+RegularExpression::RegularExpression(llvm::StringRef str,
+ llvm::Regex::RegexFlags flags)
: m_regex_text(std::string(str)),
// m_regex does not reference str anymore after it is constructed.
- m_regex(llvm::Regex(str)) {}
+ m_regex(llvm::Regex(str, flags)) {}
RegularExpression::RegularExpression(const RegularExpression &rhs)
: RegularExpression(rhs.GetText()) {}
diff --git a/lldb/source/Utility/Scalar.cpp b/lldb/source/Utility/Scalar.cpp
index c70c5e107991..c680101aa9ef 100644
--- a/lldb/source/Utility/Scalar.cpp
+++ b/lldb/source/Utility/Scalar.cpp
@@ -753,9 +753,7 @@ bool Scalar::SignExtend(uint32_t sign_bit_pos) {
return false;
case Scalar::e_int:
- if (max_bit_pos == sign_bit_pos)
- return true;
- else if (sign_bit_pos < (max_bit_pos - 1)) {
+ if (sign_bit_pos < (max_bit_pos - 1)) {
llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1);
llvm::APInt bitwize_and = m_integer & sign_bit;
if (bitwize_and.getBoolValue()) {