aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins')
-rw-r--r--lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp6
-rw-r--r--lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp5
-rw-r--r--lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp3
-rw-r--r--lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp20
-rw-r--r--lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp27
-rw-r--r--lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp10
-rw-r--r--lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp5
-rw-r--r--lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp6
-rw-r--r--lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp3
-rw-r--r--lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp13
-rw-r--r--lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp3
-rw-r--r--lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp3
-rw-r--r--lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp9
-rw-r--r--lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp9
-rw-r--r--lldb/source/Plugins/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp13
-rw-r--r--lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp6
-rw-r--r--lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp11
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt2
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp22
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp9
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp4
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp111
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h22
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp24
-rw-r--r--lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp43
-rw-r--r--lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp30
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/CMakeLists.txt13
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.cpp481
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.h61
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp5
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt3
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp70
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h4
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp11
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/Generic.h3
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp145
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp18
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.h4
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp124
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp3
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h4
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp112
-rw-r--r--lldb/source/Plugins/Language/ObjC/NSSet.cpp2
-rw-r--r--lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp9
-rw-r--r--lldb/source/Plugins/Language/ObjC/ObjCLanguage.h10
-rw-r--r--lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp4
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt3
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp6
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.cpp137
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.h47
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp5
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h3
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp273
-rw-r--r--lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp4
-rw-r--r--lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp8
-rw-r--r--lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp4
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp69
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp291
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h2
-rw-r--r--lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp90
-rw-r--r--lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp2
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp12
-rw-r--r--lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp298
-rw-r--r--lldb/source/Plugins/Platform/Android/PlatformAndroid.h11
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp10
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp51
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h3
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp10
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp22
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h11
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp9
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp20
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h1
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp4
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp3
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp61
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h2
-rw-r--r--lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp3
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp230
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedFrame.h48
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedThread.cpp6
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp2
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp113
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.h63
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp30
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h212
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp11
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h8
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp12
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h5
-rw-r--r--lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp52
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h10
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp8
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h5
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp35
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h1
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp7
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h8
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp29
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp122
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp23
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp27
-rw-r--r--lldb/source/Plugins/SyntheticFrameProvider/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/CMakeLists.txt12
-rw-r--r--lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp221
-rw-r--r--lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.h53
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp159
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h13
-rw-r--r--lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp293
-rw-r--r--lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h12
118 files changed, 3444 insertions, 1376 deletions
diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
index e40d2c5..8bfb432 100644
--- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
+++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
@@ -86,9 +86,9 @@ std::string ABIAArch64::GetMCName(std::string reg) {
uint32_t ABIAArch64::GetGenericNum(llvm::StringRef name) {
return llvm::StringSwitch<uint32_t>(name)
.Case("pc", LLDB_REGNUM_GENERIC_PC)
- .Cases("lr", "x30", LLDB_REGNUM_GENERIC_RA)
- .Cases("sp", "x31", LLDB_REGNUM_GENERIC_SP)
- .Cases("fp", "x29", LLDB_REGNUM_GENERIC_FP)
+ .Cases({"lr", "x30"}, LLDB_REGNUM_GENERIC_RA)
+ .Cases({"sp", "x31"}, LLDB_REGNUM_GENERIC_SP)
+ .Cases({"fp", "x29"}, LLDB_REGNUM_GENERIC_FP)
.Case("cpsr", LLDB_REGNUM_GENERIC_FLAGS)
.Case("x0", LLDB_REGNUM_GENERIC_ARG1)
.Case("x1", LLDB_REGNUM_GENERIC_ARG2)
diff --git a/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp b/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp
index f9c249d..e41a28b 100644
--- a/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp
+++ b/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp
@@ -480,11 +480,10 @@ ABISysV_arc::GetReturnValueObjectSimple(Thread &thread,
}
// Floating point return type.
else if (type_flags & eTypeIsFloat) {
- uint32_t float_count = 0;
bool is_complex = false;
- if (compiler_type.IsFloatingPointType(float_count, is_complex) &&
- 1 == float_count && !is_complex) {
+ if (compiler_type.IsFloatingPointType(is_complex) &&
+ !compiler_type.IsVectorType() && !is_complex) {
const size_t byte_size =
llvm::expectedToOptional(compiler_type.GetByteSize(&thread))
.value_or(0);
diff --git a/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp b/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp
index 5b5f6fa..8e69021 100644
--- a/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp
+++ b/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp
@@ -1695,7 +1695,6 @@ Status ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -1767,7 +1766,7 @@ Status ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
diff --git a/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp
index bb0c4ba..7258f5c 100644
--- a/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp
+++ b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp
@@ -1550,7 +1550,6 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl(
bool is_signed;
bool is_complex;
- uint32_t float_count;
bool is_vfp_candidate = false;
uint8_t vfp_count = 0;
uint8_t vfp_byte_size = 0;
@@ -1634,8 +1633,9 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl(
if (!GetReturnValuePassedInMemory(thread, reg_ctx, *byte_size, value))
return return_valobj_sp;
}
- } else if (compiler_type.IsFloatingPointType(float_count, is_complex)) {
- if (float_count == 1 && !is_complex) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
+ // Vector types are handled above.
+ if (!is_complex) {
switch (*bit_width) {
default:
return return_valobj_sp;
@@ -1681,7 +1681,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl(
break;
}
}
- } else if (is_complex && float_count == 2) {
+ } else if (is_complex) {
if (IsArmHardFloat(thread)) {
is_vfp_candidate = true;
vfp_byte_size = *byte_size / 2;
@@ -1709,8 +1709,9 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl(
vfp_count = (*base_byte_size == 8 ? homogeneous_count
: homogeneous_count * 2);
}
- } else if (base_type.IsFloatingPointType(float_count, is_complex)) {
- if (float_count == 1 && !is_complex) {
+ } else if (base_type.IsFloatingPointType(is_complex)) {
+ // Vector types are handled above.
+ if (!is_complex) {
is_vfp_candidate = true;
if (base_byte_size)
vfp_byte_size = *base_byte_size;
@@ -1727,10 +1728,10 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl(
base_type = compiler_type.GetFieldAtIndex(index, name, nullptr,
nullptr, nullptr);
- if (base_type.IsFloatingPointType(float_count, is_complex)) {
+ if (base_type.IsFloatingPointType(is_complex)) {
std::optional<uint64_t> base_byte_size =
llvm::expectedToOptional(base_type.GetByteSize(&thread));
- if (float_count == 2 && is_complex) {
+ if (is_complex) {
if (index != 0 && base_byte_size &&
vfp_byte_size != *base_byte_size)
break;
@@ -1841,7 +1842,6 @@ Status ABISysV_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -1884,7 +1884,7 @@ Status ABISysV_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
diff --git a/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp b/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
index 7bf99ce..91b965d 100644
--- a/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
+++ b/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
@@ -510,11 +510,10 @@ ValueObjectSP ABISysV_loongarch::GetReturnValueObjectSimple(
value, ConstString(""));
}
if (type_flags & eTypeIsFloat) {
- uint32_t float_count = 0;
bool is_complex = false;
- if (compiler_type.IsFloatingPointType(float_count, is_complex) &&
- float_count == 1 && !is_complex) {
+ if (compiler_type.IsFloatingPointType(is_complex) &&
+ !(type_flags & eTypeIsVector) && !is_complex) {
return_valobj_sp =
GetValObjFromFPRegs(thread, reg_ctx, machine, type_flags, byte_size);
return return_valobj_sp;
@@ -623,17 +622,17 @@ void ABISysV_loongarch::Terminate() {
static uint32_t GetGenericNum(llvm::StringRef name) {
return llvm::StringSwitch<uint32_t>(name)
.Case("pc", LLDB_REGNUM_GENERIC_PC)
- .Cases("ra", "r1", LLDB_REGNUM_GENERIC_RA)
- .Cases("sp", "r3", LLDB_REGNUM_GENERIC_SP)
- .Cases("fp", "r22", LLDB_REGNUM_GENERIC_FP)
- .Cases("a0", "r4", LLDB_REGNUM_GENERIC_ARG1)
- .Cases("a1", "r5", LLDB_REGNUM_GENERIC_ARG2)
- .Cases("a2", "r6", LLDB_REGNUM_GENERIC_ARG3)
- .Cases("a3", "r7", LLDB_REGNUM_GENERIC_ARG4)
- .Cases("a4", "r8", LLDB_REGNUM_GENERIC_ARG5)
- .Cases("a5", "r9", LLDB_REGNUM_GENERIC_ARG6)
- .Cases("a6", "r10", LLDB_REGNUM_GENERIC_ARG7)
- .Cases("a7", "r11", LLDB_REGNUM_GENERIC_ARG8)
+ .Cases({"ra", "r1"}, LLDB_REGNUM_GENERIC_RA)
+ .Cases({"sp", "r3"}, LLDB_REGNUM_GENERIC_SP)
+ .Cases({"fp", "r22"}, LLDB_REGNUM_GENERIC_FP)
+ .Cases({"a0", "r4"}, LLDB_REGNUM_GENERIC_ARG1)
+ .Cases({"a1", "r5"}, LLDB_REGNUM_GENERIC_ARG2)
+ .Cases({"a2", "r6"}, LLDB_REGNUM_GENERIC_ARG3)
+ .Cases({"a3", "r7"}, LLDB_REGNUM_GENERIC_ARG4)
+ .Cases({"a4", "r8"}, LLDB_REGNUM_GENERIC_ARG5)
+ .Cases({"a5", "r9"}, LLDB_REGNUM_GENERIC_ARG6)
+ .Cases({"a6", "r10"}, LLDB_REGNUM_GENERIC_ARG7)
+ .Cases({"a7", "r11"}, LLDB_REGNUM_GENERIC_ARG8)
.Default(LLDB_INVALID_REGNUM);
}
diff --git a/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp b/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp
index dd91a05..e036044 100644
--- a/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp
+++ b/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp
@@ -708,7 +708,6 @@ Status ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -750,7 +749,7 @@ Status ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
@@ -797,7 +796,6 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl(
bool is_signed = false;
bool is_complex = false;
- uint32_t count = 0;
// In MIPS register "r2" (v0) holds the integer function return values
const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoByName("r2", 0);
@@ -860,10 +858,10 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl(
return_valobj_sp = ValueObjectMemory::Create(
&thread, "", Address(mem_address, nullptr), return_compiler_type);
return return_valobj_sp;
- } else if (return_compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (return_compiler_type.IsFloatingPointType(is_complex)) {
if (IsSoftFloat(fp_flag)) {
uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0);
- if (count != 1 && is_complex)
+ if (is_complex)
return return_valobj_sp;
switch (*bit_width) {
default:
@@ -896,7 +894,7 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl(
f0_value.GetData(f0_data);
lldb::offset_t offset = 0;
- if (count == 1 && !is_complex) {
+ if (!return_compiler_type.IsVectorType() && !is_complex) {
switch (*bit_width) {
default:
return return_valobj_sp;
diff --git a/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp b/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp
index baefbfc..0dd9db0 100644
--- a/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp
+++ b/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp
@@ -923,7 +923,6 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl(
bool sucess = false;
std::string name;
bool is_complex;
- uint32_t count;
const uint32_t num_children = return_compiler_type.GetNumFields();
// A structure consisting of one or two FP values (and nothing else) will
@@ -937,7 +936,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl(
return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset,
nullptr, nullptr);
- if (field_compiler_type.IsFloatingPointType(count, is_complex))
+ if (field_compiler_type.IsFloatingPointType(is_complex))
use_fp_regs = true;
else
found_non_fp_field = true;
@@ -1044,7 +1043,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl(
if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) ||
field_compiler_type.IsPointerType() ||
- field_compiler_type.IsFloatingPointType(count, is_complex)) {
+ field_compiler_type.IsFloatingPointType(is_complex)) {
padding = field_byte_offset - integer_bytes;
if (integer_bytes < 8) {
diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp
index e4bdc44..0d25fae 100644
--- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp
+++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp
@@ -426,7 +426,6 @@ Status ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -454,7 +453,7 @@ Status ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
@@ -695,7 +694,6 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl(
uint64_t field_bit_offset = 0;
bool is_signed;
bool is_complex;
- uint32_t count;
CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex(
idx, name, &field_bit_offset, nullptr, nullptr);
@@ -741,7 +739,7 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl(
// return a nullptr return value object.
return return_valobj_sp;
}
- } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (field_compiler_type.IsFloatingPointType(is_complex)) {
// Structs with long doubles are always passed in memory.
if (*field_bit_width == 128) {
is_memory = true;
diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp
index f5327a1..6335761 100644
--- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp
+++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp
@@ -309,7 +309,6 @@ Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -339,7 +338,7 @@ Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
index 822c93d..a5547a4 100644
--- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
+++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
@@ -643,11 +643,10 @@ ABISysV_riscv::GetReturnValueObjectSimple(Thread &thread,
}
// Floating point return type.
else if (type_flags & eTypeIsFloat) {
- uint32_t float_count = 0;
bool is_complex = false;
- if (compiler_type.IsFloatingPointType(float_count, is_complex) &&
- float_count == 1 && !is_complex) {
+ if (compiler_type.IsFloatingPointType(is_complex) &&
+ !(type_flags & eTypeIsVector) && !is_complex) {
const uint32_t arch_fp_flags =
arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask;
return_valobj_sp = GetValObjFromFPRegs(
@@ -799,6 +798,8 @@ bool ABISysV_riscv::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
.Cases({"f8", "f9", "f18", "f19", "f20", "f21", "f22", "f23"},
is_hw_fp)
.Cases({"f24", "f25", "f26", "f27"}, is_hw_fp)
+ // vlenb is constant and needed for vector unwinding.
+ .Case("vlenb", true)
.Default(false);
return is_callee_saved;
@@ -816,9 +817,9 @@ void ABISysV_riscv::Terminate() {
static uint32_t GetGenericNum(llvm::StringRef name) {
return llvm::StringSwitch<uint32_t>(name)
.Case("pc", LLDB_REGNUM_GENERIC_PC)
- .Cases("ra", "x1", LLDB_REGNUM_GENERIC_RA)
- .Cases("sp", "x2", LLDB_REGNUM_GENERIC_SP)
- .Cases("fp", "s0", LLDB_REGNUM_GENERIC_FP)
+ .Cases({"ra", "x1"}, LLDB_REGNUM_GENERIC_RA)
+ .Cases({"sp", "x2"}, LLDB_REGNUM_GENERIC_SP)
+ .Cases({"fp", "s0"}, LLDB_REGNUM_GENERIC_FP)
.Case("a0", LLDB_REGNUM_GENERIC_ARG1)
.Case("a1", LLDB_REGNUM_GENERIC_ARG2)
.Case("a2", LLDB_REGNUM_GENERIC_ARG3)
diff --git a/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp b/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp
index 5e52b6e..301c3b3 100644
--- a/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp
+++ b/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp
@@ -393,7 +393,6 @@ Status ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -423,7 +422,7 @@ Status ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
diff --git a/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp b/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp
index eaeed6c..ee79abe 100644
--- a/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp
+++ b/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp
@@ -198,7 +198,6 @@ Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -240,7 +239,7 @@ Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
diff --git a/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp
index effb3de..29fd9f0 100644
--- a/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp
+++ b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp
@@ -307,7 +307,6 @@ Status ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -337,7 +336,7 @@ Status ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
@@ -587,7 +586,6 @@ static bool FlattenAggregateType(
for (uint32_t idx = 0; idx < num_children; ++idx) {
std::string name;
bool is_signed;
- uint32_t count;
bool is_complex;
uint64_t field_bit_offset = 0;
@@ -606,7 +604,7 @@ static bool FlattenAggregateType(
const uint32_t field_type_flags = field_compiler_type.GetTypeInfo();
if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) ||
field_compiler_type.IsPointerType() ||
- field_compiler_type.IsFloatingPointType(count, is_complex)) {
+ field_compiler_type.IsFloatingPointType(is_complex)) {
aggregate_field_offsets.push_back(field_byte_offset);
aggregate_compiler_types.push_back(field_compiler_type);
} else if (field_type_flags & eTypeHasChildren) {
@@ -696,7 +694,6 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl(
is_memory = false;
for (uint32_t idx = 0; idx < num_children; idx++) {
bool is_signed;
- uint32_t count;
bool is_complex;
CompilerType field_compiler_type = aggregate_compiler_types[idx];
@@ -736,7 +733,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl(
// return a nullptr return value object.
return return_valobj_sp;
}
- } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (field_compiler_type.IsFloatingPointType(is_complex)) {
// Structs with long doubles are always passed in memory.
if (field_bit_width == 128) {
is_memory = true;
diff --git a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
index 339012c..6520af2 100644
--- a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
+++ b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
@@ -312,7 +312,6 @@ Status ABIWindows_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
- uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
@@ -342,7 +341,7 @@ Status ABIWindows_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
"We don't support returning longer than 64 bit "
"integer values at present.");
}
- } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
+ } else if (compiler_type.IsFloatingPointType(is_complex)) {
if (is_complex)
error = Status::FromErrorString(
"We don't support returning complex values at present");
@@ -558,7 +557,6 @@ static bool FlattenAggregateType(
for (uint32_t idx = 0; idx < num_children; ++idx) {
std::string name;
bool is_signed;
- uint32_t count;
bool is_complex;
uint64_t field_bit_offset = 0;
@@ -582,7 +580,7 @@ static bool FlattenAggregateType(
const uint32_t field_type_flags = field_compiler_type.GetTypeInfo();
if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) ||
field_compiler_type.IsPointerType() ||
- field_compiler_type.IsFloatingPointType(count, is_complex)) {
+ field_compiler_type.IsFloatingPointType(is_complex)) {
aggregate_field_offsets.push_back(field_byte_offset);
aggregate_compiler_types.push_back(field_compiler_type);
} else if (field_type_flags & eTypeHasChildren) {
@@ -672,7 +670,6 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectImpl(
for (uint32_t idx = 0; idx < num_children; idx++) {
bool is_signed;
bool is_complex;
- uint32_t count;
CompilerType field_compiler_type = aggregate_compiler_types[idx];
uint32_t field_byte_width =
@@ -691,7 +688,7 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectImpl(
uint32_t copy_from_offset = 0;
if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) ||
field_compiler_type.IsPointerType() ||
- field_compiler_type.IsFloatingPointType(count, is_complex)) {
+ field_compiler_type.IsFloatingPointType(is_complex)) {
copy_from_extractor = &rax_data;
copy_from_offset = used_bytes;
used_bytes += field_byte_width;
diff --git a/lldb/source/Plugins/CMakeLists.txt b/lldb/source/Plugins/CMakeLists.txt
index 08f444e..b6878b2 100644
--- a/lldb/source/Plugins/CMakeLists.txt
+++ b/lldb/source/Plugins/CMakeLists.txt
@@ -22,6 +22,7 @@ add_subdirectory(SymbolFile)
add_subdirectory(SystemRuntime)
add_subdirectory(SymbolLocator)
add_subdirectory(SymbolVendor)
+add_subdirectory(SyntheticFrameProvider)
add_subdirectory(Trace)
add_subdirectory(TraceExporter)
add_subdirectory(TypeSystem)
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index 66d0a50..e8bb706 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -70,6 +70,7 @@ public:
bool HasDelaySlot(llvm::MCInst &mc_inst) const;
bool IsCall(llvm::MCInst &mc_inst) const;
bool IsLoad(llvm::MCInst &mc_inst) const;
+ bool IsBarrier(llvm::MCInst &mc_inst) const;
bool IsAuthenticated(llvm::MCInst &mc_inst) const;
private:
@@ -436,6 +437,11 @@ public:
return m_is_load;
}
+ bool IsBarrier() override {
+ VisitInstruction();
+ return m_is_barrier;
+ }
+
bool IsAuthenticated() override {
VisitInstruction();
return m_is_authenticated;
@@ -1195,6 +1201,7 @@ protected:
bool m_is_call = false;
bool m_is_load = false;
bool m_is_authenticated = false;
+ bool m_is_barrier = false;
void VisitInstruction() {
if (m_has_visited_instruction)
@@ -1227,6 +1234,7 @@ protected:
m_is_call = mc_disasm_ptr->IsCall(inst);
m_is_load = mc_disasm_ptr->IsLoad(inst);
m_is_authenticated = mc_disasm_ptr->IsAuthenticated(inst);
+ m_is_barrier = mc_disasm_ptr->IsBarrier(inst);
}
private:
@@ -1432,6 +1440,11 @@ bool DisassemblerLLVMC::MCDisasmInstance::IsLoad(llvm::MCInst &mc_inst) const {
return m_instr_info_up->get(mc_inst.getOpcode()).mayLoad();
}
+bool DisassemblerLLVMC::MCDisasmInstance::IsBarrier(
+ llvm::MCInst &mc_inst) const {
+ return m_instr_info_up->get(mc_inst.getOpcode()).isBarrier();
+}
+
bool DisassemblerLLVMC::MCDisasmInstance::IsAuthenticated(
llvm::MCInst &mc_inst) const {
const auto &InstrDesc = m_instr_info_up->get(mc_inst.getOpcode());
diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index 1d210ea..2d0a4f67 100644
--- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -789,6 +789,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule(
// Search for the kext on the local filesystem via the UUID
if (!m_module_sp && m_uuid.IsValid()) {
ModuleSpec module_spec;
+ module_spec.SetTarget(target.shared_from_this());
module_spec.GetUUID() = m_uuid;
if (!m_uuid.IsValid())
module_spec.GetArchitecture() = target.GetArchitecture();
@@ -801,9 +802,8 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule(
// system.
PlatformSP platform_sp(target.GetPlatform());
if (platform_sp) {
- FileSpecList search_paths = target.GetExecutableSearchPaths();
- platform_sp->GetSharedModule(module_spec, process, m_module_sp,
- &search_paths, nullptr, nullptr);
+ platform_sp->GetSharedModule(module_spec, process, m_module_sp, nullptr,
+ nullptr);
}
// Ask the Target to find this file on the local system, if possible.
diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 326b691..3605e7b2 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -469,7 +469,8 @@ void DynamicLoaderPOSIXDYLD::RefreshModules() {
}
ModuleSP module_sp = LoadModuleAtAddress(
- so_entry.file_spec, so_entry.link_addr, so_entry.base_addr, true);
+ so_entry.file_spec, so_entry.link_addr, so_entry.base_addr,
+ /*base_addr_is_offset=*/true);
if (!module_sp.get())
return;
@@ -726,9 +727,8 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
task_group.async(load_module_fn, *I);
task_group.wait();
} else {
- for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) {
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
load_module_fn(*I);
- }
}
m_process->GetTarget().ModulesDidLoad(module_list);
@@ -901,10 +901,9 @@ void DynamicLoaderPOSIXDYLD::ResolveExecutableModule(
if (module_sp && module_sp->MatchesModuleSpec(module_spec))
return;
+ module_spec.SetTarget(target.shared_from_this());
const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths());
- auto error = platform_sp->ResolveExecutable(
- module_spec, module_sp,
- !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr);
+ auto error = platform_sp->ResolveExecutable(module_spec, module_sp);
if (error.Fail()) {
StreamString stream;
module_spec.Dump(stream);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
index 01d588f..759a7c4 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
@@ -51,10 +51,10 @@ add_lldb_library(lldbPluginExpressionParserClang
CLANG_LIBS
clangAST
clangCodeGen
- clangDriver
clangEdit
clangFrontend
clangLex
+ clangOptions
clangParse
clangRewrite
clangRewriteFrontend
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 9900745..bae3c44 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DarwinSDKInfo.h"
+#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
@@ -25,7 +26,6 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
@@ -115,6 +115,7 @@ class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks {
ClangModulesDeclVendor &m_decl_vendor;
ClangPersistentVariables &m_persistent_vars;
clang::SourceManager &m_source_mgr;
+ /// Accumulates error messages across all moduleImport calls.
StreamString m_error_stream;
bool m_has_errors = false;
@@ -140,11 +141,12 @@ public:
module.path.push_back(
ConstString(component.getIdentifierInfo()->getName()));
- StreamString error_stream;
-
ClangModulesDeclVendor::ModuleVector exported_modules;
- if (!m_decl_vendor.AddModule(module, &exported_modules, m_error_stream))
+ if (auto err = m_decl_vendor.AddModule(module, &exported_modules)) {
m_has_errors = true;
+ m_error_stream.PutCString(llvm::toString(std::move(err)));
+ m_error_stream.PutChar('\n');
+ }
for (ClangModulesDeclVendor::ModuleID module : exported_modules)
m_persistent_vars.AddHandLoadedClangModule(module);
@@ -169,9 +171,9 @@ public:
: m_options(opts), m_filename(filename) {
m_options.ShowPresumedLoc = true;
m_options.ShowLevel = false;
- m_os = std::make_shared<llvm::raw_string_ostream>(m_output);
+ m_os = std::make_unique<llvm::raw_string_ostream>(m_output);
m_passthrough =
- std::make_shared<clang::TextDiagnosticPrinter>(*m_os, m_options);
+ std::make_unique<clang::TextDiagnosticPrinter>(*m_os, m_options);
}
void ResetManager(DiagnosticManager *manager = nullptr) {
@@ -313,11 +315,11 @@ public:
private:
DiagnosticManager *m_manager = nullptr;
DiagnosticOptions m_options;
- std::shared_ptr<clang::TextDiagnosticPrinter> m_passthrough;
- /// Output stream of m_passthrough.
- std::shared_ptr<llvm::raw_string_ostream> m_os;
/// Output string filled by m_os.
std::string m_output;
+ /// Output stream of m_passthrough.
+ std::unique_ptr<llvm::raw_string_ostream> m_os;
+ std::unique_ptr<clang::TextDiagnosticPrinter> m_passthrough;
StringRef m_filename;
};
@@ -1502,7 +1504,7 @@ lldb_private::Status ClangExpressionParser::DoPrepareForExecution(
LLDB_LOGF(log, "%s - Current expression language is %s\n", __FUNCTION__,
lang.GetDescription().data());
lldb::ProcessSP process_sp = exe_ctx.GetProcessSP();
- if (process_sp && lang != lldb::eLanguageTypeUnknown) {
+ if (process_sp && lang) {
auto runtime = process_sp->GetLanguageRuntime(lang.AsLanguageType());
if (runtime)
runtime->GetIRPasses(custom_passes);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index ff9ed9c..ad48d29 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -383,10 +383,11 @@ bool ClangExpressionSourceCode::GetText(
block->CalculateSymbolContext(&sc);
if (sc.comp_unit) {
- StreamString error_stream;
-
- decl_vendor->AddModulesForCompileUnit(
- *sc.comp_unit, modules_for_macros, error_stream);
+ if (auto err = decl_vendor->AddModulesForCompileUnit(
+ *sc.comp_unit, modules_for_macros))
+ LLDB_LOG_ERROR(
+ GetLog(LLDBLog::Expressions), std::move(err),
+ "Error while loading hand-imported modules:\n{0}");
}
}
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
index 6de8510..660a21e 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
@@ -10,7 +10,7 @@
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
-#include "clang/Driver/Driver.h"
+#include "clang/Options/OptionUtils.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -53,7 +53,7 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
std::string raw_path = lldb_shlib_spec.GetPath();
llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path);
static const std::string clang_resource_path =
- clang::driver::Driver::GetResourcesPath("bin/lldb");
+ clang::GetResourcesPath("bin/lldb");
static const llvm::StringRef kResourceDirSuffixes[] = {
// LLVM.org's build of LLDB uses the clang resource directory placed
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index b77e269..ce8dc50b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -10,6 +10,7 @@
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -67,13 +68,13 @@ private:
IDAndDiagnostic;
std::vector<IDAndDiagnostic> m_diagnostics;
std::unique_ptr<clang::DiagnosticOptions> m_diag_opts;
+ /// Output string filled by m_os. Will be reused for different diagnostics.
+ std::string m_output;
+ /// Output stream of m_diag_printer.
+ std::unique_ptr<llvm::raw_string_ostream> m_os;
/// The DiagnosticPrinter used for creating the full diagnostic messages
/// that are stored in m_diagnostics.
std::unique_ptr<clang::TextDiagnosticPrinter> m_diag_printer;
- /// Output stream of m_diag_printer.
- std::unique_ptr<llvm::raw_string_ostream> m_os;
- /// Output string filled by m_os. Will be reused for different diagnostics.
- std::string m_output;
/// A Progress with explicitly managed lifetime.
std::unique_ptr<Progress> m_current_progress_up;
std::vector<std::string> m_module_build_stack;
@@ -92,11 +93,11 @@ public:
~ClangModulesDeclVendorImpl() override = default;
- bool AddModule(const SourceModule &module, ModuleVector *exported_modules,
- Stream &error_stream) override;
+ llvm::Error AddModule(const SourceModule &module,
+ ModuleVector *exported_modules) override;
- bool AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules,
- Stream &error_stream) override;
+ llvm::Error AddModulesForCompileUnit(CompileUnit &cu,
+ ModuleVector &exported_modules) override;
uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches,
std::vector<CompilerDecl> &decls) override;
@@ -273,16 +274,14 @@ void ClangModulesDeclVendorImpl::ReportModuleExports(
exports.push_back(module);
}
-bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
- ModuleVector *exported_modules,
- Stream &error_stream) {
+llvm::Error
+ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
+ ModuleVector *exported_modules) {
// Fail early.
- if (m_compiler_instance->hadModuleLoaderFatalFailure()) {
- error_stream.PutCString("error: Couldn't load a module because the module "
- "loader is in a fatal state.\n");
- return false;
- }
+ if (m_compiler_instance->hadModuleLoaderFatalFailure())
+ return llvm::createStringError(
+ "couldn't load a module because the module loader is in a fatal state");
// Check if we've already imported this module.
@@ -297,7 +296,7 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
if (mi != m_imported_modules.end()) {
if (exported_modules)
ReportModuleExports(*exported_modules, mi->second);
- return true;
+ return llvm::Error::success();
}
}
@@ -315,30 +314,30 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
std::equal(sysroot_begin, sysroot_end, path_begin);
// No need to inject search paths to modules in the sysroot.
if (!is_system_module) {
- auto error = [&]() {
- error_stream.Printf("error: No module map file in %s\n",
- module.search_path.AsCString());
- return false;
- };
-
bool is_system = true;
bool is_framework = false;
auto dir = HS.getFileMgr().getOptionalDirectoryRef(
module.search_path.GetStringRef());
if (!dir)
- return error();
+ return llvm::createStringError(
+ "couldn't find module search path directory %s",
+ module.search_path.GetCString());
+
auto file = HS.lookupModuleMapFile(*dir, is_framework);
if (!file)
- return error();
+ return llvm::createStringError("couldn't find modulemap file in %s",
+ module.search_path.GetCString());
+
if (HS.parseAndLoadModuleMapFile(*file, is_system))
- return error();
+ return llvm::createStringError(
+ "failed to parse and load modulemap file in %s",
+ module.search_path.GetCString());
}
}
- if (!HS.lookupModule(module.path.front().GetStringRef())) {
- error_stream.Printf("error: Header search couldn't locate module '%s'\n",
- module.path.front().AsCString());
- return false;
- }
+
+ if (!HS.lookupModule(module.path.front().GetStringRef()))
+ return llvm::createStringError("header search couldn't locate module '%s'",
+ module.path.front().AsCString());
llvm::SmallVector<clang::IdentifierLoc, 4> clang_path;
@@ -364,22 +363,29 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
clang::Module *top_level_module = DoGetModule(clang_path.front(), false);
if (!top_level_module) {
+ lldb_private::StreamString error_stream;
diagnostic_consumer->DumpDiagnostics(error_stream);
- error_stream.Printf("error: Couldn't load top-level module %s\n",
- module.path.front().AsCString());
- return false;
+
+ return llvm::createStringError(llvm::formatv(
+ "couldn't load top-level module {0}:\n{1}",
+ module.path.front().GetStringRef(), error_stream.GetString()));
}
clang::Module *submodule = top_level_module;
for (auto &component : llvm::ArrayRef<ConstString>(module.path).drop_front()) {
- submodule = submodule->findSubmodule(component.GetStringRef());
- if (!submodule) {
+ clang::Module *found = submodule->findSubmodule(component.GetStringRef());
+ if (!found) {
+ lldb_private::StreamString error_stream;
diagnostic_consumer->DumpDiagnostics(error_stream);
- error_stream.Printf("error: Couldn't load submodule %s\n",
- component.GetCString());
- return false;
+
+ return llvm::createStringError(llvm::formatv(
+ "couldn't load submodule '{0}' of module '{1}':\n{2}",
+ component.GetStringRef(), submodule->getFullModuleName(),
+ error_stream.GetString()));
}
+
+ submodule = found;
}
// If we didn't make the submodule visible here, Clang wouldn't allow LLDB to
@@ -399,10 +405,12 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
m_enabled = true;
- return true;
+ return llvm::Error::success();
}
- return false;
+ return llvm::createStringError(
+ llvm::formatv("unknown error while loading module {0}\n",
+ module.path.front().GetStringRef()));
}
bool ClangModulesDeclVendor::LanguageSupportsClangModules(
@@ -424,15 +432,18 @@ bool ClangModulesDeclVendor::LanguageSupportsClangModules(
}
}
-bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit(
- CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules,
- Stream &error_stream) {
- if (LanguageSupportsClangModules(cu.GetLanguage())) {
- for (auto &imported_module : cu.GetImportedModules())
- if (!AddModule(imported_module, &exported_modules, error_stream))
- return false;
- }
- return true;
+llvm::Error ClangModulesDeclVendorImpl::AddModulesForCompileUnit(
+ CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules) {
+ if (!LanguageSupportsClangModules(cu.GetLanguage()))
+ return llvm::Error::success();
+
+ llvm::Error errors = llvm::Error::success();
+
+ for (auto &imported_module : cu.GetImportedModules())
+ if (auto err = AddModule(imported_module, &exported_modules))
+ errors = llvm::joinErrors(std::move(errors), std::move(err));
+
+ return errors;
}
// ClangImporter::lookupValue
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
index ad4d060..0436320 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
@@ -41,21 +41,16 @@ public:
/// The path to the exact module to be loaded. E.g., if the desired
/// module is std.io, then this should be { "std", "io" }.
///
- /// \param[in] exported_modules
+ /// \param[out] exported_modules
/// If non-NULL, a pointer to a vector to populate with the ID of every
/// module that is re-exported by the specified module.
///
- /// \param[in] error_stream
- /// A stream to populate with the output of the Clang parser when
- /// it tries to load the module.
- ///
/// \return
/// True if the module could be loaded; false if not. If the
/// compiler encountered a fatal error during a previous module
/// load, then this will always return false for this ModuleImporter.
- virtual bool AddModule(const SourceModule &module,
- ModuleVector *exported_modules,
- Stream &error_stream) = 0;
+ virtual llvm::Error AddModule(const SourceModule &module,
+ ModuleVector *exported_modules) = 0;
/// Add all modules referred to in a given compilation unit to the list
/// of modules to search.
@@ -63,22 +58,17 @@ public:
/// \param[in] cu
/// The compilation unit to scan for imported modules.
///
- /// \param[in] exported_modules
+ /// \param[out] exported_modules
/// A vector to populate with the ID of each module loaded (directly
/// and via re-exports) in this way.
///
- /// \param[in] error_stream
- /// A stream to populate with the output of the Clang parser when
- /// it tries to load the modules.
- ///
/// \return
/// True if all modules referred to by the compilation unit could be
/// loaded; false if one could not be loaded. If the compiler
/// encountered a fatal error during a previous module
/// load, then this will always return false for this ModuleImporter.
- virtual bool AddModulesForCompileUnit(CompileUnit &cu,
- ModuleVector &exported_modules,
- Stream &error_stream) = 0;
+ virtual llvm::Error
+ AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules) = 0;
/// Enumerate all the macros that are defined by a given set of modules
/// that are already imported.
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index e8d5ec3..d1feda1 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -371,26 +371,20 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target,
if (!sc.comp_unit)
return;
- StreamString error_stream;
-
ClangModulesDeclVendor::ModuleVector modules_for_macros =
persistent_state->GetHandLoadedClangModules();
- if (decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros,
- error_stream))
- return;
- // Failed to load some modules, so emit the error stream as a diagnostic.
- if (!error_stream.Empty()) {
- // The error stream already contains several Clang diagnostics that might
- // be either errors or warnings, so just print them all as one remark
- // diagnostic to prevent that the message starts with "error: error:".
- diagnostic_manager.PutString(lldb::eSeverityInfo, error_stream.GetString());
+ auto err =
+ decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros);
+ if (!err)
return;
- }
- diagnostic_manager.PutString(lldb::eSeverityError,
- "Unknown error while loading modules needed for "
- "current compilation unit.");
+ // Module load errors aren't fatal to the expression evaluator. Printing
+ // them as diagnostics to the console would be too noisy and misleading
+ // Hence just print them to the expression log.
+ llvm::handleAllErrors(std::move(err), [](const llvm::StringError &e) {
+ LLDB_LOG(GetLog(LLDBLog::Expressions), "{0}", e.getMessage());
+ });
}
ClangExpressionSourceCode::WrapKind ClangUserExpression::GetWrapKind() const {
diff --git a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
index a8901be..f124424 100644
--- a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
+++ b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
@@ -346,6 +346,16 @@ EmulateInstructionARM64::GetOpcodeForInstruction(const uint32_t opcode) {
&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
"LDR <Xt>, [<Xn|SP>{, #<pimm>}]"},
+ {0x3f200c00, 0x3c000400, No_VFP,
+ &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
+ "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>], #<simm>"},
+ {0x3f200c00, 0x3c000c00, No_VFP,
+ &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
+ "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>, #<simm>]!"},
+ {0x3f000000, 0x3d000000, No_VFP,
+ &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
+ "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>{, #<pimm>}]"},
+
{0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB,
"B <label>"},
{0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond,
@@ -930,9 +940,29 @@ template <EmulateInstructionARM64::AddrMode a_mode>
bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
uint32_t size = Bits32(opcode, 31, 30);
uint32_t opc = Bits32(opcode, 23, 22);
+ uint32_t vr = Bit32(opcode, 26);
uint32_t n = Bits32(opcode, 9, 5);
uint32_t t = Bits32(opcode, 4, 0);
+ MemOp memop;
+ if (vr) {
+ // opc<1> == 1 && size != 0 is an undefined encoding.
+ if (Bit32(opc, 1) == 1 && size != 0)
+ return false;
+ // opc<1> == 1 && size == 0 encode the 128-bit variant.
+ if (Bit32(opc, 1) == 1)
+ size = 4;
+ memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
+ } else {
+ if (Bit32(opc, 1) == 0) {
+ memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
+ } else {
+ memop = MemOp_LOAD;
+ if (size == 2 && Bit32(opc, 0) == 1)
+ return false;
+ }
+ }
+
bool wback;
bool postindex;
uint64_t offset;
@@ -955,16 +985,6 @@ bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
break;
}
- MemOp memop;
-
- if (Bit32(opc, 1) == 0) {
- memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
- } else {
- memop = MemOp_LOAD;
- if (size == 2 && Bit32(opc, 0) == 1)
- return false;
- }
-
Status error;
bool success = false;
uint64_t address;
@@ -989,7 +1009,8 @@ bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
return false;
std::optional<RegisterInfo> reg_info_Rt =
- GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);
+ vr ? GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t)
+ : GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);
if (!reg_info_Rt)
return false;
diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
index 5c1b7d4..2957cb71 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -1328,32 +1328,36 @@ public:
m_emu, inst, 8, ZextD,
[](uint64_t a, uint64_t b) { return std::max(a, b); });
}
- template <typename T>
- bool F_Load(T inst, const fltSemantics &(*semantics)(),
- unsigned int numBits) {
+ template <typename I, typename T>
+ bool F_Load(I inst, const fltSemantics &(*semantics)()) {
return transformOptional(inst.rs1.Read(m_emu),
[&](auto &&rs1) {
- uint64_t addr = rs1 + uint64_t(inst.imm);
- uint64_t bits = *m_emu.ReadMem<uint64_t>(addr);
+ uint64_t addr =
+ rs1 + uint64_t(SignExt(inst.imm));
+ uint64_t bits = *m_emu.ReadMem<T>(addr);
+ unsigned numBits = sizeof(T) * 8;
APFloat f(semantics(), APInt(numBits, bits));
return inst.rd.WriteAPFloat(m_emu, f);
})
.value_or(false);
}
- bool operator()(FLW inst) { return F_Load(inst, &APFloat::IEEEsingle, 32); }
- template <typename T> bool F_Store(T inst, bool isDouble) {
+ bool operator()(FLW inst) {
+ return F_Load<FLW, uint32_t>(inst, &APFloat::IEEEsingle);
+ }
+ template <typename I, typename T> bool F_Store(I inst, bool isDouble) {
return transformOptional(zipOpt(inst.rs1.Read(m_emu),
inst.rs2.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
auto [rs1, rs2] = tup;
- uint64_t addr = rs1 + uint64_t(inst.imm);
+ uint64_t addr =
+ rs1 + uint64_t(SignExt(inst.imm));
uint64_t bits =
rs2.bitcastToAPInt().getZExtValue();
- return m_emu.WriteMem<uint64_t>(addr, bits);
+ return m_emu.WriteMem<T>(addr, bits);
})
.value_or(false);
}
- bool operator()(FSW inst) { return F_Store(inst, false); }
+ bool operator()(FSW inst) { return F_Store<FSW, uint32_t>(inst, false); }
std::tuple<bool, APFloat> FusedMultiplyAdd(APFloat rs1, APFloat rs2,
APFloat rs3) {
auto opStatus = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode());
@@ -1616,8 +1620,10 @@ public:
bool operator()(FCVT_S_LU inst) {
return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEsingle());
}
- bool operator()(FLD inst) { return F_Load(inst, &APFloat::IEEEdouble, 64); }
- bool operator()(FSD inst) { return F_Store(inst, true); }
+ bool operator()(FLD inst) {
+ return F_Load<FLD, uint64_t>(inst, &APFloat::IEEEdouble);
+ }
+ bool operator()(FSD inst) { return F_Store<FSD, uint64_t>(inst, true); }
bool operator()(FMADD_D inst) { return FMA(inst, true, 1.0f, 1.0f); }
bool operator()(FMSUB_D inst) { return FMA(inst, true, 1.0f, -1.0f); }
bool operator()(FNMSUB_D inst) { return FMA(inst, true, -1.0f, 1.0f); }
diff --git a/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/CMakeLists.txt
new file mode 100644
index 0000000..adbd6c4
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeBoundsSafety PLUGIN
+ InstrumentationRuntimeBoundsSafety.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbSymbol
+ lldbTarget
+ lldbPluginInstrumentationRuntimeUtility
+
+ CLANG_LIBS
+ clangCodeGen
+ )
diff --git a/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.cpp b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.cpp
new file mode 100644
index 0000000..db9b213
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.cpp
@@ -0,0 +1,481 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "InstrumentationRuntimeBoundsSafety.h"
+
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+
+#include <memory>
+#include <type_traits>
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(InstrumentationRuntimeBoundsSafety)
+
+constexpr llvm::StringLiteral
+ BoundsSafetySoftTrapMinimal("__bounds_safety_soft_trap");
+constexpr llvm::StringLiteral
+ BoundsSafetySoftTrapStr("__bounds_safety_soft_trap_s");
+
+constexpr std::array<llvm::StringLiteral, 2>
+getBoundsSafetySoftTrapRuntimeFuncs() {
+ return {BoundsSafetySoftTrapMinimal, BoundsSafetySoftTrapStr};
+}
+
+#define SOFT_TRAP_CATEGORY_PREFIX "Soft "
+#define SOFT_TRAP_FALLBACK_CATEGORY \
+ SOFT_TRAP_CATEGORY_PREFIX "Bounds check failed"
+
+using ComputedStopInfo =
+ std::pair<std::optional<std::string>, std::optional<uint32_t>>;
+
+class InstrumentationBoundsSafetyStopInfo : public StopInfo {
+public:
+ ~InstrumentationBoundsSafetyStopInfo() override = default;
+
+ lldb::StopReason GetStopReason() const override {
+ return lldb::eStopReasonInstrumentation;
+ }
+
+ std::optional<uint32_t>
+ GetSuggestedStackFrameIndex(bool inlined_stack) override {
+ return m_value;
+ }
+
+ const char *GetDescription() override { return m_description.c_str(); }
+
+ bool DoShouldNotify(Event *event_ptr) override { return true; }
+
+ static lldb::StopInfoSP
+ CreateInstrumentationBoundsSafetyStopInfo(Thread &thread) {
+ return StopInfoSP(new InstrumentationBoundsSafetyStopInfo(thread));
+ }
+
+private:
+ InstrumentationBoundsSafetyStopInfo(Thread &thread);
+
+ ComputedStopInfo
+ ComputeStopReasonAndSuggestedStackFrame(bool &warning_emitted_for_failure);
+
+ ComputedStopInfo ComputeStopReasonAndSuggestedStackFrameWithDebugInfo(
+ lldb::StackFrameSP parent_sf, lldb::user_id_t debugger_id,
+ bool &warning_emitted_for_failure);
+
+ ComputedStopInfo ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo(
+ ThreadSP thread_sp, lldb::user_id_t debugger_id,
+ bool &warning_emitted_for_failure);
+};
+
+InstrumentationBoundsSafetyStopInfo::InstrumentationBoundsSafetyStopInfo(
+ Thread &thread)
+ : StopInfo(thread, 0) {
+ // No additional data describing the reason for stopping.
+ m_extended_info = nullptr;
+ m_description = SOFT_TRAP_FALLBACK_CATEGORY;
+
+ bool warning_emitted_for_failure = false;
+ auto [MaybeDescription, MaybeSuggestedStackIndex] =
+ ComputeStopReasonAndSuggestedStackFrame(warning_emitted_for_failure);
+ if (MaybeDescription)
+ m_description = MaybeDescription.value();
+ if (MaybeSuggestedStackIndex)
+ m_value = MaybeSuggestedStackIndex.value();
+
+ // Emit warning about the failure to compute the stop info if one wasn't
+ // already emitted.
+ if ((!MaybeDescription.has_value()) && !warning_emitted_for_failure) {
+ if (ThreadSP thread_sp = GetThread()) {
+ lldb::user_id_t debugger_id =
+ thread_sp->GetProcess()->GetTarget().GetDebugger().GetID();
+ Debugger::ReportWarning(
+ "specific BoundsSafety trap reason could not be computed",
+ debugger_id);
+ }
+ }
+}
+
+// Helper functions to make it convenient to log a failure and then return.
+template <typename T, typename... ArgTys>
+[[nodiscard]] T LogBeforeReturn(ArgTys &&...Args) {
+ LLDB_LOG(GetLog(LLDBLog::InstrumentationRuntime), Args...);
+ return T();
+}
+
+template <typename... ArgTys>
+[[nodiscard]] ComputedStopInfo LogFailedCSI(ArgTys &&...Args) {
+ return LogBeforeReturn<ComputedStopInfo>(Args...);
+}
+
+ComputedStopInfo
+InstrumentationBoundsSafetyStopInfo::ComputeStopReasonAndSuggestedStackFrame(
+ bool &warning_emitted_for_failure) {
+ ThreadSP thread_sp = GetThread();
+ if (!thread_sp)
+ return LogFailedCSI("failed to get thread while stopped");
+
+ lldb::user_id_t debugger_id =
+ thread_sp->GetProcess()->GetTarget().GetDebugger().GetID();
+
+ StackFrameSP parent_sf = thread_sp->GetStackFrameAtIndex(1);
+ if (!parent_sf)
+ return LogFailedCSI("got nullptr when fetching stackframe at index 1");
+
+ if (parent_sf->HasDebugInformation())
+ return ComputeStopReasonAndSuggestedStackFrameWithDebugInfo(
+ parent_sf, debugger_id, warning_emitted_for_failure);
+
+ // If the debug info is missing we can still get some information
+ // from the parameter in the soft trap runtime call.
+ return ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo(
+ thread_sp, debugger_id, warning_emitted_for_failure);
+}
+
+ComputedStopInfo InstrumentationBoundsSafetyStopInfo::
+ ComputeStopReasonAndSuggestedStackFrameWithDebugInfo(
+ lldb::StackFrameSP parent_sf, lldb::user_id_t debugger_id,
+ bool &warning_emitted_for_failure) {
+ // First try to use debug info to understand the reason for trapping. The
+ // call stack will look something like this:
+ //
+ // ```
+ // frame #0: `__bounds_safety_soft_trap_s(reason="")
+ // frame #1: `__clang_trap_msg$Bounds check failed$<reason>'
+ // frame #2: `bad_read(index=10)
+ // ```
+ // ....
+ const char *TrapReasonFuncName = parent_sf->GetFunctionName();
+
+ auto MaybeTrapReason =
+ clang::CodeGen::DemangleTrapReasonInDebugInfo(TrapReasonFuncName);
+ if (!MaybeTrapReason.has_value())
+ return LogFailedCSI(
+ "clang::CodeGen::DemangleTrapReasonInDebugInfo(\"{0}\") call failed",
+ TrapReasonFuncName);
+
+ llvm::StringRef category = MaybeTrapReason.value().first;
+ llvm::StringRef message = MaybeTrapReason.value().second;
+
+ // TODO: Clang should probably be changed to emit the "Soft " prefix itself
+ std::string stop_reason;
+ llvm::raw_string_ostream ss(stop_reason);
+ ss << SOFT_TRAP_CATEGORY_PREFIX;
+ if (category.empty())
+ ss << "<empty category>";
+ else
+ ss << category;
+ if (message.empty()) {
+ // This is not a failure so leave `warning_emitted_for_failure` untouched.
+ Debugger::ReportWarning(
+ "specific BoundsSafety trap reason is not "
+ "available because the compiler omitted it from the debug info",
+ debugger_id);
+ } else {
+ ss << ": " << message;
+ }
+ // Use computed stop-reason and assume the parent of `parent_sf` is the
+ // the place in the user's code where the call to the soft trap runtime
+ // originated.
+ return std::make_pair(stop_reason, parent_sf->GetFrameIndex() + 1);
+}
+
+ComputedStopInfo InstrumentationBoundsSafetyStopInfo::
+ ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo(
+ ThreadSP thread_sp, lldb::user_id_t debugger_id,
+ bool &warning_emitted_for_failure) {
+
+ StackFrameSP softtrap_sf = thread_sp->GetStackFrameAtIndex(0);
+ if (!softtrap_sf)
+ return LogFailedCSI("got nullptr when fetching stackframe at index 0");
+ llvm::StringRef trap_reason_func_name = softtrap_sf->GetFunctionName();
+
+ if (trap_reason_func_name == BoundsSafetySoftTrapMinimal) {
+ // This function has no arguments so there's no additional information
+ // that would allow us to identify the trap reason.
+ //
+ // Use the fallback stop reason and the current frame.
+ // While we "could" set the suggested frame to our parent (where the
+ // bounds check failed), doing this leads to very misleading output in
+ // LLDB. E.g.:
+ //
+ // ```
+ // 0x100003b40 <+104>: bl 0x100003d64 ; __bounds_safety_soft_trap
+ // -> 0x100003b44 <+108>: b 0x100003b48 ; <+112>
+ // ```
+ //
+ // This makes it look we stopped after finishing the call to
+ // `__bounds_safety_soft_trap` but actually we are in the middle of the
+ // call. To avoid this confusion just use the current frame.
+ std::string warning;
+ llvm::raw_string_ostream ss(warning);
+ ss << "specific BoundsSafety trap reason is not available because debug "
+ "info is missing on the caller of '"
+ << BoundsSafetySoftTrapMinimal << "'";
+ Debugger::ReportWarning(warning.c_str(), debugger_id);
+ warning_emitted_for_failure = true;
+ return {};
+ }
+
+ // __bounds_safety_soft_trap_s has one argument which is a pointer to a string
+ // describing the trap or a nullptr.
+ if (trap_reason_func_name != BoundsSafetySoftTrapStr) {
+ assert(0 && "hit breakpoint for unexpected function name");
+ return LogFailedCSI(
+ "unexpected function name. Expected \"{0}\" but got \"{1}\"",
+ BoundsSafetySoftTrapStr.data(), trap_reason_func_name.data());
+ }
+
+ RegisterContextSP rc = thread_sp->GetRegisterContext();
+ if (!rc)
+ return LogFailedCSI("failed to get register context");
+
+ // FIXME: LLDB should have an API that tells us for the current target if
+ // `LLDB_REGNUM_GENERIC_ARG1` can be used.
+ // https://github.com/llvm/llvm-project/issues/168602
+ // Don't try for architectures where examining the first register won't
+ // work.
+ ProcessSP process = thread_sp->GetProcess();
+ if (!process)
+ return LogFailedCSI("failed to get process");
+
+ switch (process->GetTarget().GetArchitecture().GetCore()) {
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_32_i686: {
+ // Technically some x86 calling conventions do use a register for
+ // passing the first argument but let's ignore that for now.
+ std::string warning;
+ llvm::raw_string_ostream ss(warning);
+ ss << "specific BoundsSafety trap reason cannot be inferred on x86 when "
+ "the caller of '"
+ << BoundsSafetySoftTrapStr << "' is missing debug info";
+ Debugger::ReportWarning(warning.c_str(), debugger_id);
+ warning_emitted_for_failure = true;
+ return {};
+ }
+ default: {
+ }
+ };
+
+ // Examine the register for the first argument.
+ const RegisterInfo *arg0_info = rc->GetRegisterInfo(
+ lldb::RegisterKind::eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
+ if (!arg0_info)
+ return LogFailedCSI(
+ "failed to get register info for LLDB_REGNUM_GENERIC_ARG1");
+ RegisterValue reg_value;
+ if (!rc->ReadRegister(arg0_info, reg_value))
+ return LogFailedCSI("failed to read register {0}", arg0_info->name);
+ uint64_t reg_value_as_int = reg_value.GetAsUInt64(UINT64_MAX);
+ if (reg_value_as_int == UINT64_MAX)
+ return LogFailedCSI("failed to read register {0} as a UInt64",
+ arg0_info->name);
+
+ if (reg_value_as_int == 0) {
+ // nullptr arg. The compiler will pass that if no trap reason string was
+ // available.
+ Debugger::ReportWarning(
+ "specific BoundsSafety trap reason cannot be inferred because the "
+ "compiler omitted the reason",
+ debugger_id);
+ warning_emitted_for_failure = true;
+ return {};
+ }
+
+ // The first argument to the call is a pointer to a global C string
+ // containing the trap reason.
+ std::string out_string;
+ Status error_status;
+ thread_sp->GetProcess()->ReadCStringFromMemory(reg_value_as_int, out_string,
+ error_status);
+ if (error_status.Fail())
+ return LogFailedCSI("failed to read C string from address {0}",
+ (void *)reg_value_as_int);
+
+ LLDB_LOG(GetLog(LLDBLog::InstrumentationRuntime),
+ "read C string from {0} found in register {1}: \"{2}\"",
+ (void *)reg_value_as_int, arg0_info->name, out_string.c_str());
+ std::string stop_reason;
+ llvm::raw_string_ostream SS(stop_reason);
+ SS << SOFT_TRAP_FALLBACK_CATEGORY;
+ if (!stop_reason.empty()) {
+ SS << ": " << out_string;
+ }
+ // Use the current frame as the suggested frame for the same reason as for
+ // `__bounds_safety_soft_trap`.
+ return {stop_reason, 0};
+}
+
+InstrumentationRuntimeBoundsSafety::~InstrumentationRuntimeBoundsSafety() {
+ Deactivate();
+}
+
+lldb::InstrumentationRuntimeSP
+InstrumentationRuntimeBoundsSafety::CreateInstance(
+ const lldb::ProcessSP &process_sp) {
+ return InstrumentationRuntimeSP(
+ new InstrumentationRuntimeBoundsSafety(process_sp));
+}
+
+void InstrumentationRuntimeBoundsSafety::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ "BoundsSafety instrumentation runtime plugin.",
+ CreateInstance, GetTypeStatic);
+}
+
+void InstrumentationRuntimeBoundsSafety::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb::InstrumentationRuntimeType
+InstrumentationRuntimeBoundsSafety::GetTypeStatic() {
+ return lldb::eInstrumentationRuntimeTypeBoundsSafety;
+}
+
+const RegularExpression &
+InstrumentationRuntimeBoundsSafety::GetPatternForRuntimeLibrary() {
+ static RegularExpression regex;
+ return regex;
+}
+
+bool InstrumentationRuntimeBoundsSafety::CheckIfRuntimeIsValid(
+ const lldb::ModuleSP module_sp) {
+ Log *log_category = GetLog(LLDBLog::InstrumentationRuntime);
+ for (const auto &SoftTrapFunc : getBoundsSafetySoftTrapRuntimeFuncs()) {
+ ConstString test_sym(SoftTrapFunc);
+
+ if (module_sp->FindFirstSymbolWithNameAndType(test_sym,
+ lldb::eSymbolTypeAny)) {
+ LLDB_LOG(log_category, "found \"{0}\" in {1}",
+ test_sym.AsCString("<unknown symbol>"),
+ module_sp->GetObjectName().AsCString("<unknown module>"));
+ return true;
+ }
+ }
+ LLDB_LOG(log_category,
+ "did not find BoundsSafety soft trap functions in module {0}",
+ module_sp->GetObjectName().AsCString("<unknown module>"));
+ return false;
+}
+
+bool InstrumentationRuntimeBoundsSafety::NotifyBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ assert(baton && "null baton");
+ if (!baton)
+ return false; ///< false => resume execution.
+
+ InstrumentationRuntimeBoundsSafety *const instance =
+ static_cast<InstrumentationRuntimeBoundsSafety *>(baton);
+
+ ProcessSP process_sp = instance->GetProcessSP();
+ if (!process_sp)
+ return LogBeforeReturn<bool>("failed to get process from baton");
+ ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
+ if (!thread_sp)
+ return LogBeforeReturn<bool>(
+ "failed to get thread from StoppointCallbackContext");
+
+ if (process_sp != context->exe_ctx_ref.GetProcessSP())
+ return LogBeforeReturn<bool>(
+ "process from baton ({0}) and StoppointCallbackContext ({1}) do "
+ "not match",
+ (void *)process_sp.get(),
+ (void *)context->exe_ctx_ref.GetProcessSP().get());
+
+ if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
+ return LogBeforeReturn<bool>("IsLastResumeForUserExpression is true");
+
+ // Maybe the stop reason and stackframe selection should be done by
+ // a stackframe recognizer instead?
+ thread_sp->SetStopInfo(
+ InstrumentationBoundsSafetyStopInfo::
+ CreateInstrumentationBoundsSafetyStopInfo(*thread_sp));
+ return true;
+}
+
+void InstrumentationRuntimeBoundsSafety::Activate() {
+ if (IsActive())
+ return;
+
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return LogBeforeReturn<void>("could not get process during Activate()");
+
+ std::vector<std::string> breakpoints;
+ for (auto &breakpoint_func : getBoundsSafetySoftTrapRuntimeFuncs())
+ breakpoints.emplace_back(breakpoint_func);
+
+ BreakpointSP breakpoint = process_sp->GetTarget().CreateBreakpoint(
+ /*containingModules=*/nullptr,
+ /*containingSourceFiles=*/nullptr, breakpoints, eFunctionNameTypeFull,
+ eLanguageTypeUnknown,
+ /*m_offset=*/0,
+ /*skip_prologue*/ eLazyBoolNo,
+ /*internal=*/true,
+ /*request_hardware*/ false);
+
+ if (!breakpoint)
+ return LogBeforeReturn<void>("failed to create breakpoint");
+
+ if (!breakpoint->HasResolvedLocations()) {
+ assert(0 && "breakpoint has no resolved locations");
+ process_sp->GetTarget().RemoveBreakpointByID(breakpoint->GetID());
+ return LogBeforeReturn<void>(
+ "breakpoint {0} for BoundsSafety soft traps did not resolve to "
+ "any locations",
+ breakpoint->GetID());
+ }
+
+ // Note: When `sync=true` the suggested stackframe is completely ignored. So
+ // we use `sync=false`. Is that a bug?
+ breakpoint->SetCallback(
+ InstrumentationRuntimeBoundsSafety::NotifyBreakpointHit, this,
+ /*sync=*/false);
+ breakpoint->SetBreakpointKind("bounds-safety-soft-trap");
+ SetBreakpointID(breakpoint->GetID());
+ LLDB_LOG(GetLog(LLDBLog::InstrumentationRuntime),
+ "created breakpoint {0} for BoundsSafety soft traps",
+ breakpoint->GetID());
+ SetActive(true);
+}
+
+void InstrumentationRuntimeBoundsSafety::Deactivate() {
+ SetActive(false);
+ Log *log_category = GetLog(LLDBLog::InstrumentationRuntime);
+ if (ProcessSP process_sp = GetProcessSP()) {
+ bool success =
+ process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID());
+ LLDB_LOG(log_category,
+ "{0}removed breakpoint {1} for BoundsSafety soft traps",
+ success ? "" : "failed to ", GetBreakpointID());
+ } else {
+ LLDB_LOG(log_category, "no process available during Deactivate()");
+ }
+
+ SetBreakpointID(LLDB_INVALID_BREAK_ID);
+}
diff --git a/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.h b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.h
new file mode 100644
index 0000000..06c30f8
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.h
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_BOUNDS_SAFETY_SOFT_TRAP_H
+#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_BOUNDS_SAFETY_SOFT_TRAP_H
+
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class InstrumentationRuntimeBoundsSafety
+ : public lldb_private::InstrumentationRuntime {
+public:
+ ~InstrumentationRuntimeBoundsSafety() override;
+
+ static lldb::InstrumentationRuntimeSP
+ CreateInstance(const lldb::ProcessSP &process_sp);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "BoundsSafety"; }
+
+ static lldb::InstrumentationRuntimeType GetTypeStatic();
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
+
+private:
+ InstrumentationRuntimeBoundsSafety(const lldb::ProcessSP &process_sp)
+ : lldb_private::InstrumentationRuntime(process_sp) {}
+
+ const RegularExpression &GetPatternForRuntimeLibrary() override;
+
+ bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
+
+ void Activate() override;
+
+ void Deactivate();
+
+ static bool NotifyBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ bool MatchAllModules() override { return true; }
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
index 2a6cf93..b7e1a60 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
+++ b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
@@ -2,6 +2,7 @@ set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND InstrumentationRuntime)
add_subdirectory(ASan)
add_subdirectory(ASanLibsanitizers)
+add_subdirectory(BoundsSafety)
add_subdirectory(MainThreadChecker)
add_subdirectory(TSan)
add_subdirectory(UBSan)
diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
index 38c334b..3642cb1 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
@@ -207,8 +207,11 @@ bool ReportRetriever::NotifyBreakpointHit(ProcessSP process_sp,
return false;
StructuredData::ObjectSP report = RetrieveReportData(process_sp);
- if (!report || report->GetType() != lldb::eStructuredDataTypeDictionary)
+ if (!report || report->GetType() != lldb::eStructuredDataTypeDictionary) {
+ LLDB_LOGF(GetLog(LLDBLog::InstrumentationRuntime),
+ "ReportRetriever::RetrieveReportData() failed");
return false;
+ }
std::string description = FormatDescription(report);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index cbc6f14..c52d3bd 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -14,11 +14,11 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
CxxStringTypes.cpp
Generic.cpp
GenericBitset.cpp
+ GenericInitializerList.cpp
GenericList.cpp
GenericOptional.cpp
LibCxx.cpp
LibCxxAtomic.cpp
- LibCxxInitializerList.cpp
LibCxxMap.cpp
LibCxxQueue.cpp
LibCxxRangesRefView.cpp
@@ -31,6 +31,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibCxxValarray.cpp
LibCxxVector.cpp
LibStdcpp.cpp
+ LibStdcppSpan.cpp
LibStdcppTuple.cpp
LibStdcppUniquePointer.cpp
MsvcStl.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index a2199cb..ae6086f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -84,7 +84,7 @@ CPlusPlusLanguage::GetFunctionNameInfo(ConstString name) const {
if (basename.empty()) {
llvm::StringRef context;
func_name_type |=
- (ExtractContextAndIdentifier(name.GetCString(), context, basename)
+ (ExtractContextAndIdentifier(name.GetStringRef(), context, basename)
? (eFunctionNameTypeMethod | eFunctionNameTypeBase)
: eFunctionNameTypeFull);
} else {
@@ -103,7 +103,7 @@ CPlusPlusLanguage::GetFunctionNameInfo(ConstString name) const {
return {func_name_type, ConstString(basename)};
}
-bool CPlusPlusLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
+bool CPlusPlusLanguage::SymbolNameFitsToLanguage(const Mangled &mangled) const {
auto mangling_scheme =
Mangled::GetManglingScheme(mangled.GetMangledName().GetStringRef());
return mangling_scheme == Mangled::eManglingSchemeItanium ||
@@ -208,6 +208,20 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) {
return idx == basename.size();
}
+/// A context is trivial if an only if it matches this pattern.
+/// "^\s*([A-Za-z_:]*)\s*$". for example function `foo::bar::func()`
+/// has a trivial context but. but `foo<int>::bar::func()` doesn't.
+static bool IsTrivialContext(llvm::StringRef context) {
+ // remove trailing or leading whitespace.
+ context = context.trim();
+
+ const auto iter = context.find_if_not([](char current) {
+ return std::isalnum(static_cast<unsigned char>(current)) ||
+ current == '_' || current == ':';
+ });
+ return iter == llvm::StringRef::npos;
+}
+
/// Writes out the function name in 'full_name' to 'out_stream'
/// but replaces each argument type with the variable name
/// and the corresponding pretty-printed value
@@ -481,18 +495,17 @@ bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() {
m_basename = full.substr(basename_begin, basename_end - basename_begin);
}
- if (IsTrivialBasename(m_basename)) {
+ if (IsTrivialBasename(m_basename) && IsTrivialContext(m_context)) {
return true;
- } else {
- // The C++ basename doesn't match our regular expressions so this can't
- // be a valid C++ method, clear everything out and indicate an error
- m_context = llvm::StringRef();
- m_basename = llvm::StringRef();
- m_arguments = llvm::StringRef();
- m_qualifiers = llvm::StringRef();
- m_return_type = llvm::StringRef();
- return false;
}
+ // The C++ basename doesn't match our regular expressions so this can't
+ // be a valid C++ method, clear everything out and indicate an error
+ m_context = llvm::StringRef();
+ m_basename = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ m_return_type = llvm::StringRef();
+ return false;
}
return false;
}
@@ -546,9 +559,8 @@ bool CPlusPlusLanguage::CxxMethodName::ContainsPath(llvm::StringRef path) {
llvm::StringRef identifier;
llvm::StringRef context;
- std::string path_str = path.str();
- bool success = CPlusPlusLanguage::ExtractContextAndIdentifier(
- path_str.c_str(), context, identifier);
+ const bool success =
+ CPlusPlusLanguage::ExtractContextAndIdentifier(path, context, identifier);
if (!success)
return m_full.GetStringRef().contains(path);
@@ -592,7 +604,8 @@ bool CPlusPlusLanguage::DemangledNameContainsPath(llvm::StringRef path,
}
bool CPlusPlusLanguage::ExtractContextAndIdentifier(
- const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
+ llvm::StringRef name, llvm::StringRef &context,
+ llvm::StringRef &identifier) {
if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
identifier);
@@ -899,11 +912,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::unordered containers synthetic children",
"^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$",
stl_synth_flags, true);
- AddCXXSynthetic(
- cpp_category_sp,
- lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator,
- "libc++ std::initializer_list synthetic children",
- "^std::initializer_list<.+>$", stl_synth_flags, true);
AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator,
"libc++ std::queue synthetic children",
"^std::__[[:alnum:]]+::queue<.+>$", stl_synth_flags, true);
@@ -1416,6 +1424,10 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
stl_synth_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
+ AddCXXSynthetic(cpp_category_sp, LibStdcppSpanSyntheticFrontEndCreator,
+ "libstdc++ std::span synthetic children", "^std::span<.+>$",
+ stl_deref_flags, true);
+
stl_summary_flags.SetDontShowChildren(false);
stl_summary_flags.SetSkipPointers(false);
@@ -1506,6 +1518,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
"libstdc++ std::coroutine_handle summary provider",
libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::ContainerSizeSummaryProvider,
+ "libstdc++ std::span summary provider", "^std::span<.+>$",
+ stl_summary_flags, true);
}
static lldb_private::SyntheticChildrenFrontEnd *
@@ -1705,6 +1722,14 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
},
"MSVC STL/libstdc++ std::wstring summary provider"));
+ // NOTE: it is loaded as a common formatter because the libc++ version is not
+ // in the `__1` namespace, hence we need to dispatch based on the class
+ // layout.
+ AddCXXSynthetic(cpp_category_sp,
+ GenericInitializerListSyntheticFrontEndCreator,
+ "std::initializer_list synthetic children",
+ "^std::initializer_list<.+>$", stl_synth_flags, true);
+
stl_summary_flags.SetDontShowChildren(false);
stl_summary_flags.SetSkipPointers(false);
@@ -1748,6 +1773,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"^std::(multi)?(map|set)<.+>(( )?&)?$", stl_synth_flags,
true);
+ AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider,
+ "std::initializer_list summary provider",
+ "^std::initializer_list<.+>$", stl_summary_flags, true);
AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
"MSVC STL/libstdc++ std::shared_ptr summary provider",
"^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 9a528ca..b547234 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -92,7 +92,7 @@ public:
static llvm::StringRef GetPluginNameStatic() { return "cplusplus"; }
- bool SymbolNameFitsToLanguage(Mangled mangled) const override;
+ bool SymbolNameFitsToLanguage(const Mangled &mangled) const override;
bool DemangledNameContainsPath(llvm::StringRef path,
ConstString demangled) const override;
@@ -154,7 +154,7 @@ public:
// C/C++ identifier, then it will return false
// and identifier and context will be unchanged.
- static bool ExtractContextAndIdentifier(const char *name,
+ static bool ExtractContextAndIdentifier(llvm::StringRef name,
llvm::StringRef &context,
llvm::StringRef &identifier);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
index d8c095d..4d283bb 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -315,7 +315,7 @@ bool CPlusPlusNameParser::ConsumeAbiTag() {
// Consume the actual tag string (and allow some special characters)
while (ConsumeToken(tok::raw_identifier, tok::comma, tok::period,
- tok::numeric_constant))
+ tok::numeric_constant, tok::kw_operator))
;
if (!ConsumeToken(tok::r_square))
@@ -420,10 +420,11 @@ bool CPlusPlusNameParser::ConsumeOperator() {
// Make sure we have more tokens before attempting to look ahead one more.
if (m_next_token_index + 1 < m_tokens.size()) {
// Look ahead two tokens.
- clang::Token n_token = m_tokens[m_next_token_index + 1];
- // If we find ( or < then this is indeed operator<< no need for fix.
- if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) {
- clang::Token tmp_tok;
+ const clang::Token n_token = m_tokens[m_next_token_index + 1];
+ // If we find `(`, `<` or `[` then this is indeed operator<< no need for
+ // fix.
+ if (!n_token.isOneOf(tok::l_paren, tok::less, tok::l_square)) {
+ clang::Token tmp_tok{};
tmp_tok.startToken();
tmp_tok.setLength(1);
tmp_tok.setLocation(token.getLocation().getLocWithOffset(1));
diff --git a/lldb/source/Plugins/Language/CPlusPlus/Generic.h b/lldb/source/Plugins/Language/CPlusPlus/Generic.h
index f394622..539eddd 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/Generic.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/Generic.h
@@ -24,6 +24,9 @@ bool GenericOptionalSummaryProvider(ValueObject &valobj, Stream &stream,
lldb::ValueObjectSP GetDesugaredSmartPointerValue(ValueObject &ptr,
ValueObject &container);
+SyntheticChildrenFrontEnd *
+GenericInitializerListSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
} // namespace formatters
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp
new file mode 100644
index 0000000..7f012b7
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp
@@ -0,0 +1,145 @@
+//===-- GenericInitializerList.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/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include <cstddef>
+#include <optional>
+#include <type_traits>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace generic_check {
+template <class T>
+using size_func = decltype(T::GetSizeMember(std::declval<ValueObject &>()));
+template <class T>
+using start_func = decltype(T::GetStartMember(std::declval<ValueObject &>()));
+namespace {
+template <typename...> struct check_func : std::true_type {};
+} // namespace
+
+template <typename T>
+using has_functions = check_func<size_func<T>, start_func<T>>;
+} // namespace generic_check
+
+struct LibCxx {
+ static ValueObjectSP GetStartMember(ValueObject &backend) {
+ return backend.GetChildMemberWithName("__begin_");
+ }
+
+ static ValueObjectSP GetSizeMember(ValueObject &backend) {
+ return backend.GetChildMemberWithName("__size_");
+ }
+};
+
+struct LibStdcpp {
+ static ValueObjectSP GetStartMember(ValueObject &backend) {
+ return backend.GetChildMemberWithName("_M_array");
+ }
+
+ static ValueObjectSP GetSizeMember(ValueObject &backend) {
+ return backend.GetChildMemberWithName("_M_len");
+ }
+};
+
+namespace lldb_private::formatters {
+
+template <class StandardImpl>
+class GenericInitializerListSyntheticFrontEnd
+ : public SyntheticChildrenFrontEnd {
+public:
+ static_assert(generic_check::has_functions<StandardImpl>::value,
+ "Missing Required Functions.");
+
+ GenericInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
+ if (valobj_sp)
+ Update();
+ }
+
+ ~GenericInitializerListSyntheticFrontEnd() override {
+ // this needs to stay around because it's a child object who will follow its
+ // parent's life cycle
+ // delete m_start;
+ }
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ m_num_elements = 0;
+
+ const ValueObjectSP size_sp(StandardImpl::GetSizeMember(m_backend));
+ if (size_sp)
+ m_num_elements = size_sp->GetValueAsUnsigned(0);
+ return m_num_elements;
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ if (!m_start)
+ return {};
+
+ uint64_t offset = static_cast<uint64_t>(idx) * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(name.GetString(), offset,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+ }
+
+ lldb::ChildCacheState Update() override {
+ m_start = nullptr;
+ m_num_elements = 0;
+ m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
+ if (!m_element_type.IsValid())
+ return lldb::ChildCacheState::eRefetch;
+
+ llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
+ if (!size_or_err)
+ LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
+ "{0}");
+ else {
+ m_element_size = *size_or_err;
+ // Store raw pointers or end up with a circular dependency.
+ m_start = StandardImpl::GetStartMember(m_backend).get();
+ }
+
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
+ if (!m_start) {
+ return llvm::createStringError("Type has no child named '%s'",
+ name.AsCString());
+ }
+ auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
+ if (!optional_idx) {
+ return llvm::createStringError("Type has no child named '%s'",
+ name.AsCString());
+ }
+ return *optional_idx;
+ }
+
+private:
+ ValueObject *m_start = nullptr;
+ CompilerType m_element_type;
+ uint32_t m_element_size = 0;
+ size_t m_num_elements = 0;
+};
+
+SyntheticChildrenFrontEnd *GenericInitializerListSyntheticFrontEndCreator(
+ CXXSyntheticChildren * /*unused*/, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+
+ if (LibCxx::GetStartMember(*valobj_sp) != nullptr)
+ return new GenericInitializerListSyntheticFrontEnd<LibCxx>(valobj_sp);
+
+ return new GenericInitializerListSyntheticFrontEnd<LibStdcpp>(valobj_sp);
+}
+} // namespace lldb_private::formatters
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index 5289027..8c5ac31 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -203,6 +203,16 @@ private:
ValueObject *m_tail = nullptr;
};
+/// Gets the (forward-)list element type from the head node instead of the
+/// template arguments. This is needed with PDB as it doesn't have info about
+/// the template arguments.
+CompilerType GetMsvcStlElementTypeFromHead(ValueObject &head) {
+ auto val_sp = head.GetChildMemberWithName("_Myval");
+ if (val_sp)
+ return val_sp->GetCompilerType();
+ return CompilerType();
+}
+
} // end anonymous namespace
template <StlType Stl>
@@ -530,6 +540,10 @@ lldb::ChildCacheState MsvcStlForwardListFrontEnd::Update() {
m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"}))
m_head = head_sp.get();
+ // With PDB, we can't get the element type from the template arguments
+ if (!m_element_type && m_head)
+ m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
+
return ChildCacheState::eRefetch;
}
@@ -606,6 +620,10 @@ lldb::ChildCacheState MsvcStlListFrontEnd::Update() {
m_head = first.get();
m_tail = last.get();
+ // With PDB, we can't get the element type from the template arguments
+ if (!m_element_type && m_head)
+ m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
+
return lldb::ChildCacheState::eRefetch;
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index 819f8a9..8fd2928 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -194,10 +194,6 @@ SyntheticChildrenFrontEnd *
LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
-SyntheticChildrenFrontEnd *
-LibcxxInitializerListSyntheticFrontEndCreator(CXXSyntheticChildren *,
- lldb::ValueObjectSP);
-
SyntheticChildrenFrontEnd *LibcxxQueueFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
deleted file mode 100644
index d952688..0000000
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-//===-- LibCxxInitializerList.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 "LibCxx.h"
-
-#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Utility/ConstString.h"
-#include "lldb/ValueObject/ValueObject.h"
-#include <optional>
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace lldb_private::formatters;
-
-namespace lldb_private {
-namespace formatters {
-class LibcxxInitializerListSyntheticFrontEnd
- : public SyntheticChildrenFrontEnd {
-public:
- LibcxxInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
-
- ~LibcxxInitializerListSyntheticFrontEnd() override;
-
- llvm::Expected<uint32_t> CalculateNumChildren() override;
-
- lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
-
- lldb::ChildCacheState Update() override;
-
- llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
-private:
- ValueObject *m_start = nullptr;
- CompilerType m_element_type;
- uint32_t m_element_size = 0;
- size_t m_num_elements = 0;
-};
-} // namespace formatters
-} // namespace lldb_private
-
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
- LibcxxInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
- : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
- if (valobj_sp)
- Update();
-}
-
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
- ~LibcxxInitializerListSyntheticFrontEnd() {
- // this needs to stay around because it's a child object who will follow its
- // parent's life cycle
- // delete m_start;
-}
-
-llvm::Expected<uint32_t> lldb_private::formatters::
- LibcxxInitializerListSyntheticFrontEnd::CalculateNumChildren() {
- m_num_elements = 0;
- ValueObjectSP size_sp(m_backend.GetChildMemberWithName("__size_"));
- if (size_sp)
- m_num_elements = size_sp->GetValueAsUnsigned(0);
- return m_num_elements;
-}
-
-lldb::ValueObjectSP lldb_private::formatters::
- LibcxxInitializerListSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
- if (!m_start)
- return lldb::ValueObjectSP();
-
- uint64_t offset = idx * m_element_size;
- offset = offset + m_start->GetValueAsUnsigned(0);
- StreamString name;
- name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- return CreateValueObjectFromAddress(name.GetString(), offset,
- m_backend.GetExecutionContextRef(),
- m_element_type);
-}
-
-lldb::ChildCacheState
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::Update() {
- m_start = nullptr;
- m_num_elements = 0;
- m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
- if (!m_element_type.IsValid())
- return lldb::ChildCacheState::eRefetch;
-
- llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
- if (!size_or_err)
- LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
- "{0}");
- else {
- m_element_size = *size_or_err;
- // Store raw pointers or end up with a circular dependency.
- m_start = m_backend.GetChildMemberWithName("__begin_").get();
- }
-
- return lldb::ChildCacheState::eRefetch;
-}
-
-llvm::Expected<size_t>
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
- GetIndexOfChildWithName(ConstString name) {
- if (!m_start) {
- return llvm::createStringError("Type has no child named '%s'",
- name.AsCString());
- }
- auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
- if (!optional_idx) {
- return llvm::createStringError("Type has no child named '%s'",
- name.AsCString());
- }
- return *optional_idx;
-}
-
-lldb_private::SyntheticChildrenFrontEnd *
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator(
- CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
- return (valobj_sp ? new LibcxxInitializerListSyntheticFrontEnd(valobj_sp)
- : nullptr);
-}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index f4a695e..86f0a5a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -199,9 +199,6 @@ lldb::ChildCacheState VectorIteratorSyntheticFrontEnd::Update() {
if (!valobj_sp)
return lldb::ChildCacheState::eRefetch;
- if (!valobj_sp)
- return lldb::ChildCacheState::eRefetch;
-
ValueObjectSP item_ptr =
formatters::GetChildMemberWithName(*valobj_sp, m_item_names);
if (!item_ptr)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
index 429142f6..8d2c81f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
@@ -38,6 +38,10 @@ LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
SyntheticChildrenFrontEnd *
+LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
LibStdcppTupleSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
new file mode 100644
index 0000000..5e69792
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
@@ -0,0 +1,112 @@
+//===---------------------------------------------------------------------===//
+//
+// 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 "LibStdcpp.h"
+
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <optional>
+
+using namespace lldb;
+
+namespace lldb_private::formatters {
+
+class LibStdcppSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibStdcppSpanSyntheticFrontEnd(const lldb::ValueObjectSP &valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+ }
+
+ ~LibStdcppSpanSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_num_elements;
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ if (!m_start)
+ return {};
+
+ uint64_t offset = (static_cast<uint64_t>(idx) * m_element_size);
+ offset += m_start->GetValueAsUnsigned(0);
+ const std::string name = llvm::formatv("[{0}]", idx);
+ return CreateValueObjectFromAddress(
+ name, offset, m_backend.GetExecutionContextRef(), m_element_type);
+ }
+
+ lldb::ChildCacheState Update() override {
+ const ValueObjectSP data_ptr = m_backend.GetChildMemberWithName("_M_ptr");
+ if (!data_ptr)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_element_type = data_ptr->GetCompilerType().GetPointeeType();
+
+ // Get element size.
+ llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
+ if (!size_or_err) {
+ LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
+ "{0}");
+ return lldb::ChildCacheState::eReuse;
+ }
+
+ m_element_size = *size_or_err;
+ if (m_element_size > 0) {
+ m_start = data_ptr.get();
+ }
+
+ // Get number of elements.
+ if (const ValueObjectSP size_sp =
+ m_backend.GetChildAtNamePath({"_M_extent", "_M_extent_value"})) {
+ m_num_elements = size_sp->GetValueAsUnsigned(0);
+ } else if (const auto arg =
+ m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) {
+
+ m_num_elements = arg->value.GetAPSInt().getLimitedValue();
+ }
+
+ return lldb::ChildCacheState::eReuse;
+ }
+
+ llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
+ if (!m_start)
+ return llvm::createStringError(
+ llvm::formatv("Type has no child named {0}", name.GetStringRef()));
+
+ auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
+ if (!optional_idx) {
+ return llvm::createStringError(
+ llvm::formatv("Type has no child named {0}", name.GetStringRef()));
+ }
+ return *optional_idx;
+ }
+
+private:
+ ValueObject *m_start = nullptr; ///< First element of span. Held, not owned.
+ CompilerType m_element_type; ///< Type of span elements.
+ size_t m_num_elements = 0; ///< Number of elements in span.
+ uint32_t m_element_size = 0; ///< Size in bytes of each span element.
+};
+
+SyntheticChildrenFrontEnd *
+LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren * /*unused*/,
+ lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ const CompilerType type = valobj_sp->GetCompilerType();
+ if (!type || type.GetNumTemplateArguments() != 2)
+ return nullptr;
+ return new LibStdcppSpanSyntheticFrontEnd(valobj_sp);
+}
+
+} // namespace lldb_private::formatters
diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
index 7d814e65..150b233 100644
--- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -419,8 +419,6 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return lldb::ChildCacheState::eRefetch;
- if (!valobj_sp)
- return lldb::ChildCacheState::eRefetch;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
index 3b8e21c..c0dcb95 100644
--- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -235,7 +235,7 @@ ObjCLanguage::GetFunctionNameInfo(ConstString name) const {
return {func_name_type, std::nullopt};
}
-bool ObjCLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
+bool ObjCLanguage::SymbolNameFitsToLanguage(const Mangled &mangled) const {
ConstString demangled_name = mangled.GetDemangledName();
if (!demangled_name)
return false;
@@ -1065,3 +1065,10 @@ ObjCLanguage::GetBooleanFromString(llvm::StringRef str) const {
.Case("NO", {false})
.Default({});
}
+
+bool ObjCLanguage::IsPossibleObjCMethodName(llvm::StringRef name) {
+ if (!name.starts_with("-[") && !name.starts_with("+["))
+ return false;
+
+ return name.ends_with("]");
+}
diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
index a68ea41..ced6bd3 100644
--- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
+++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
@@ -145,7 +145,7 @@ public:
std::pair<lldb::FunctionNameType, std::optional<ConstString>>
GetFunctionNameInfo(ConstString name) const override;
- bool SymbolNameFitsToLanguage(Mangled mangled) const override;
+ bool SymbolNameFitsToLanguage(const Mangled &mangled) const override;
lldb::TypeCategoryImplSP GetFormatters() override;
@@ -175,13 +175,7 @@ public:
static llvm::StringRef GetPluginNameStatic() { return "objc"; }
- static bool IsPossibleObjCMethodName(const char *name) {
- if (!name)
- return false;
- bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
- bool ends_right = (name[strlen(name) - 1] == ']');
- return (starts_right && ends_right);
- }
+ static bool IsPossibleObjCMethodName(llvm::StringRef name);
static bool IsPossibleObjCSelector(const char *name) {
if (!name)
diff --git a/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
index 0489f4d..faa0dd0 100644
--- a/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
@@ -47,7 +47,7 @@ Language *ObjCPlusPlusLanguage::CreateInstance(lldb::LanguageType language) {
std::optional<bool>
ObjCPlusPlusLanguage::GetBooleanFromString(llvm::StringRef str) const {
return llvm::StringSwitch<std::optional<bool>>(str)
- .Cases("true", "YES", {true})
- .Cases("false", "NO", {false})
+ .Cases({"true", "YES"}, {true})
+ .Cases({"false", "NO"}, {false})
.Default({});
}
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
index 1717b0a..727c829 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
@@ -1,10 +1,13 @@
add_lldb_library(lldbPluginCPPRuntime
CPPLanguageRuntime.cpp
+ VerboseTrapFrameRecognizer.cpp
LINK_LIBS
lldbCore
lldbSymbol
lldbTarget
+ CLANG_LIBS
+ clangCodeGen
)
add_subdirectory(ItaniumABI)
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
index 21a5ebe..913678b 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
@@ -12,6 +12,7 @@
#include <memory>
#include "CPPLanguageRuntime.h"
+#include "VerboseTrapFrameRecognizer.h"
#include "llvm/ADT/StringRef.h"
@@ -107,12 +108,15 @@ public:
CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
: LanguageRuntime(process) {
- if (process)
+ if (process) {
process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
StackFrameRecognizerSP(new LibCXXFrameRecognizer()), {},
std::make_shared<RegularExpression>("^std::__[^:]*::"),
/*mangling_preference=*/Mangled::ePreferDemangledWithoutArguments,
/*first_instruction_only=*/false);
+
+ RegisterVerboseTrapFrameRecognizer(*process);
+ }
}
bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.cpp
new file mode 100644
index 0000000..2b6bf2c
--- /dev/null
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.cpp
@@ -0,0 +1,137 @@
+#include "VerboseTrapFrameRecognizer.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrameRecognizer.h"
+#include "lldb/Target/Target.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include "clang/CodeGen/ModuleBuilder.h"
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+/// The 0th frame is the artificial inline frame generated to store
+/// the verbose_trap message. So, starting with the current parent frame,
+/// find the first frame that's not inside of the STL.
+static StackFrameSP FindMostRelevantFrame(Thread &selected_thread) {
+ // Defensive upper-bound of when we stop walking up the frames in
+ // case we somehow ended up looking at an infinite recursion.
+ const size_t max_stack_depth = 128;
+
+ // Start at parent frame.
+ size_t stack_idx = 1;
+ StackFrameSP most_relevant_frame_sp =
+ selected_thread.GetStackFrameAtIndex(stack_idx);
+
+ while (most_relevant_frame_sp && stack_idx <= max_stack_depth) {
+ auto const &sc =
+ most_relevant_frame_sp->GetSymbolContext(eSymbolContextEverything);
+ ConstString frame_name = sc.GetFunctionName();
+ if (!frame_name)
+ return nullptr;
+
+ // Found a frame outside of the `std` namespace. That's the
+ // first frame in user-code that ended up triggering the
+ // verbose_trap. Hence that's the one we want to display.
+ if (!frame_name.GetStringRef().starts_with("std::"))
+ return most_relevant_frame_sp;
+
+ ++stack_idx;
+ most_relevant_frame_sp = selected_thread.GetStackFrameAtIndex(stack_idx);
+ }
+
+ return nullptr;
+}
+
+VerboseTrapRecognizedStackFrame::VerboseTrapRecognizedStackFrame(
+ StackFrameSP most_relevant_frame_sp, std::string stop_desc)
+ : m_most_relevant_frame(most_relevant_frame_sp) {
+ m_stop_desc = std::move(stop_desc);
+}
+
+lldb::RecognizedStackFrameSP
+VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
+ if (frame_sp->GetFrameIndex())
+ return {};
+
+ ThreadSP thread_sp = frame_sp->GetThread();
+ ProcessSP process_sp = thread_sp->GetProcess();
+
+ StackFrameSP most_relevant_frame_sp = FindMostRelevantFrame(*thread_sp);
+
+ if (!most_relevant_frame_sp) {
+ Log *log = GetLog(LLDBLog::Unwind);
+ LLDB_LOG(
+ log,
+ "Failed to find most relevant frame: Hit unwinding bound (1 frame)!");
+ return {};
+ }
+
+ SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
+
+ if (!sc.block)
+ return {};
+
+ // The runtime error is set as the function name in the inlined function info
+ // of frame #0 by the compiler
+ const InlineFunctionInfo *inline_info = nullptr;
+ Block *inline_block = sc.block->GetContainingInlinedBlock();
+
+ if (!inline_block)
+ return {};
+
+ inline_info = sc.block->GetInlinedFunctionInfo();
+
+ if (!inline_info)
+ return {};
+
+ auto func_name = inline_info->GetName().GetStringRef();
+ if (func_name.empty())
+ return {};
+
+ auto maybe_trap_reason =
+ clang::CodeGen::DemangleTrapReasonInDebugInfo(func_name);
+ if (!maybe_trap_reason.has_value()) {
+ LLDB_LOGF(GetLog(LLDBLog::Unwind), "Failed to demangle '%s' as trap reason",
+ func_name.str().c_str());
+ return {};
+ }
+ auto [category, message] = maybe_trap_reason.value();
+
+ std::string stop_reason =
+ category.empty() ? "<empty category>" : category.str();
+ if (!message.empty()) {
+ stop_reason += ": ";
+ stop_reason += message.str();
+ }
+
+ return std::make_shared<VerboseTrapRecognizedStackFrame>(
+ most_relevant_frame_sp, std::move(stop_reason));
+}
+
+lldb::StackFrameSP VerboseTrapRecognizedStackFrame::GetMostRelevantFrame() {
+ return m_most_relevant_frame;
+}
+
+namespace lldb_private {
+
+void RegisterVerboseTrapFrameRecognizer(Process &process) {
+ RegularExpressionSP module_regex_sp = nullptr;
+ auto symbol_regex_sp = std::make_shared<RegularExpression>(
+ llvm::formatv("^{0}", ClangTrapPrefix).str());
+
+ StackFrameRecognizerSP srf_recognizer_sp =
+ std::make_shared<VerboseTrapFrameRecognizer>();
+
+ process.GetTarget().GetFrameRecognizerManager().AddRecognizer(
+ srf_recognizer_sp, module_regex_sp, symbol_regex_sp,
+ Mangled::ePreferDemangled, false);
+}
+
+} // namespace lldb_private
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.h
new file mode 100644
index 0000000..7d7020f
--- /dev/null
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.h
@@ -0,0 +1,47 @@
+//===-- VerboseTrapFrameRecognizer.h --------------------------------------===//
+//
+// 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_SOURCE_PLUGINS_LANGUAGERUNTIME_C_PLUS_PLUS_VERBOSETRAPFRAMERECOGNIZER_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_C_PLUS_PLUS_VERBOSETRAPFRAMERECOGNIZER_H
+
+#include "lldb/Target/StackFrameRecognizer.h"
+
+namespace lldb_private {
+
+void RegisterVerboseTrapFrameRecognizer(Process &process);
+
+/// Holds the stack frame that caused the Verbose trap and the inlined stop
+/// reason message.
+class VerboseTrapRecognizedStackFrame : public RecognizedStackFrame {
+public:
+ VerboseTrapRecognizedStackFrame(lldb::StackFrameSP most_relevant_frame_sp,
+ std::string stop_desc);
+
+ lldb::StackFrameSP GetMostRelevantFrame() override;
+
+private:
+ lldb::StackFrameSP m_most_relevant_frame;
+};
+
+/// When a thread stops, it checks the current frame contains a
+/// Verbose Trap diagnostic. If so, it returns a \a
+/// VerboseTrapRecognizedStackFrame holding the diagnostic a stop reason
+/// description with and the parent frame as the most relavant frame.
+class VerboseTrapFrameRecognizer : public StackFrameRecognizer {
+public:
+ std::string GetName() override {
+ return "Verbose Trap StackFrame Recognizer";
+ }
+
+ lldb::RecognizedStackFrameSP
+ RecognizeFrame(lldb::StackFrameSP frame) override;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_C_PLUS_PLUS_VERBOSETRAPFRAMERECOGNIZER_H
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
index 954f269..ebde889 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
@@ -111,7 +111,6 @@ bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) {
process->GetAddressByteSize());
lldb::offset_t cursor = 0;
-
m_flags = extractor.GetU32_unchecked(&cursor);
m_version = extractor.GetU32_unchecked(&cursor);
m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
@@ -119,18 +118,16 @@ bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) {
m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr);
m_method_list_ptr = extractor.GetAddress_unchecked(&cursor);
m_properties_ptr = extractor.GetAddress_unchecked(&cursor);
- m_firstSubclass = extractor.GetAddress_unchecked(&cursor);
- m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor);
if (m_ro_ptr & 1) {
DataBufferHeap buffer(ptr_size, '\0');
process->ReadMemory(m_ro_ptr ^ 1, buffer.GetBytes(), ptr_size, error);
if (error.Fail())
return false;
- cursor = 0;
DataExtractor extractor(buffer.GetBytes(), ptr_size,
process->GetByteOrder(),
process->GetAddressByteSize());
+ lldb::offset_t cursor = 0;
m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
if (ABISP abi_sp = process->GetABI())
m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr);
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
index 0fff9af..8d19b00 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
@@ -133,9 +133,6 @@ private:
lldb::addr_t m_properties_ptr;
lldb::addr_t m_protocols_ptr;
- ObjCLanguageRuntime::ObjCISA m_firstSubclass;
- ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;
-
bool Read(Process *process, lldb::addr_t addr);
};
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 9beb133..83e39f3 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -320,7 +320,7 @@ extern "C"
static const char *g_get_shared_cache_class_info_name =
"__lldb_apple_objc_v2_get_shared_cache_class_info";
-static const char *g_get_shared_cache_class_info_body = R"(
+static const char *g_get_shared_cache_class_info_definitions = R"(
extern "C"
{
@@ -411,6 +411,9 @@ struct ClassInfo
Class isa;
uint32_t hash;
} __attribute__((__packed__));
+)";
+
+static const char *g_get_shared_cache_class_info_body = R"(
uint32_t
__lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
@@ -418,6 +421,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
void *class_infos_ptr,
uint64_t *relative_selector_offset,
uint32_t class_infos_byte_size,
+ uint32_t *start_idx,
uint32_t should_log)
{
*relative_selector_offset = 0;
@@ -426,6 +430,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);
DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
+ DEBUG_PRINTF ("start_idx = %u\n", *start_idx);
if (objc_opt_ro_ptr)
{
const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
@@ -480,7 +485,11 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
- for (uint32_t i=0; i<clsopt->capacity; ++i)
+ const uint32_t original_start_idx = *start_idx;
+
+ // Always start at the start_idx here. If it's greater than the capacity,
+ // it will skip the loop entirely and go to the duplicate handling below.
+ for (uint32_t i=*start_idx; i<clsopt->capacity; ++i)
{
const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
@@ -524,59 +533,78 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
else
{
DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
+ *start_idx = i;
+ break;
}
++idx;
}
- const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
- const uint32_t duplicate_count = *duplicate_count_ptr;
- const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
-
- DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
- DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
-
- for (uint32_t i=0; i<duplicate_count; ++i)
- {
- const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
- DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
+ if (idx < max_class_infos) {
+ const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
+ const uint32_t duplicate_count = *duplicate_count_ptr;
+ const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
- if (classOffsets[i].isDuplicate) {
- DEBUG_PRINTF("isDuplicate = true\n");
- continue; // duplicate
- }
+ DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
+ DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
- if (objectCacheOffset == 0) {
- DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
- continue; // invalid offset
- }
+ const uint32_t duplicate_start_idx =
+ *start_idx < clsopt->capacity ?
+ 0 :
+ *start_idx - clsopt->capacity;
- if (class_infos && idx < max_class_infos)
+ for (uint32_t i=duplicate_start_idx; i<duplicate_count; ++i)
{
- class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
+ const uint64_t objectCacheOffset = duplicateClassOffsets[i].objectCacheOffset;
+ DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
- // Lookup the class name.
- const char *name = class_name_lookup_func(class_infos[idx].isa);
- DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+ if (duplicateClassOffsets[i].isDuplicate) {
+ DEBUG_PRINTF("isDuplicate = true\n");
+ continue; // duplicate
+ }
- // Hash the class name so we don't have to read it.
- const char *s = name;
- uint32_t h = 5381;
- for (unsigned char c = *s; c; c = *++s)
+ if (objectCacheOffset == 0) {
+ DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
+ continue; // invalid offset
+ }
+
+ if (class_infos && idx < max_class_infos)
{
- // class_getName demangles swift names and the hash must
- // be calculated on the mangled name. hash==0 means lldb
- // will fetch the mangled name and compute the hash in
- // ParseClassInfoArray.
- if (c == '.')
+ class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
+
+ // Lookup the class name.
+ const char *name = class_name_lookup_func(class_infos[idx].isa);
+ DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+
+ // Hash the class name so we don't have to read it.
+ const char *s = name;
+ uint32_t h = 5381;
+ for (unsigned char c = *s; c; c = *++s)
{
- h = 0;
- break;
+ // class_getName demangles swift names and the hash must
+ // be calculated on the mangled name. hash==0 means lldb
+ // will fetch the mangled name and compute the hash in
+ // ParseClassInfoArray.
+ if (c == '.')
+ {
+ h = 0;
+ break;
+ }
+ h = ((h << 5) + h) + c;
}
- h = ((h << 5) + h) + c;
+ class_infos[idx].hash = h;
+ } else {
+ DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
+ *start_idx = i;
+ break;
}
- class_infos[idx].hash = h;
+ ++idx;
}
}
+ // Always make sure start_idx gets updated. Otherwise we have an infinite
+ // loop if there are exactly max_class_infos number of classes.
+ if (*start_idx == original_start_idx) {
+ *start_idx = idx;
+ }
}
else if (objc_opt->version >= 12 && objc_opt->version <= 15)
{
@@ -1937,6 +1965,7 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
class_name_getter_function_name.AsCString(),
class_name_getter_function_name.AsCString());
+ shared_class_expression += g_get_shared_cache_class_info_definitions;
shared_class_expression += g_get_shared_cache_class_info_body;
auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
@@ -1958,6 +1987,9 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
CompilerType clang_uint64_t_pointer_type =
scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64)
.GetPointerType();
+ CompilerType clang_uint32_t_pointer_type =
+ scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32)
+ .GetPointerType();
// Next make the function caller for our implementation utility function.
ValueList arguments;
@@ -1975,6 +2007,13 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
value.SetValueType(Value::ValueType::Scalar);
value.SetCompilerType(clang_uint32_t_type);
arguments.PushValue(value);
+
+ value.SetValueType(Value::ValueType::Scalar);
+ value.SetCompilerType(clang_uint32_t_pointer_type);
+ arguments.PushValue(value);
+
+ value.SetValueType(Value::ValueType::Scalar);
+ value.SetCompilerType(clang_uint32_t_type);
arguments.PushValue(value);
std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);
@@ -2312,10 +2351,7 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
// The number of entries to pre-allocate room for.
// Each entry is (addrsize + 4) bytes
- // FIXME: It is not sustainable to continue incrementing this value every time
- // the shared cache grows. This is because it requires allocating memory in
- // the inferior process and some inferior processes have small memory limits.
- const uint32_t max_num_classes = 212992;
+ const uint32_t max_num_classes_in_buffer = 212992;
UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction(exe_ctx);
if (!get_class_info_code) {
@@ -2337,15 +2373,22 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
DiagnosticManager diagnostics;
const uint32_t class_info_byte_size = addr_size + 4;
- const uint32_t class_infos_byte_size = max_num_classes * class_info_byte_size;
+ const uint32_t class_infos_byte_size =
+ max_num_classes_in_buffer * class_info_byte_size;
lldb::addr_t class_infos_addr = process->AllocateMemory(
class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
const uint32_t relative_selector_offset_addr_size = 64;
lldb::addr_t relative_selector_offset_addr =
process->AllocateMemory(relative_selector_offset_addr_size,
ePermissionsReadable | ePermissionsWritable, err);
+ constexpr uint32_t class_info_start_idx_byte_size = sizeof(uint32_t);
+ lldb::addr_t class_info_start_idx_addr =
+ process->AllocateMemory(class_info_start_idx_byte_size,
+ ePermissionsReadable | ePermissionsWritable, err);
- if (class_infos_addr == LLDB_INVALID_ADDRESS) {
+ if (class_infos_addr == LLDB_INVALID_ADDRESS ||
+ relative_selector_offset_addr == LLDB_INVALID_ADDRESS ||
+ class_info_start_idx_addr == LLDB_INVALID_ADDRESS) {
LLDB_LOGF(log,
"unable to allocate %" PRIu32
" bytes in process for shared cache read",
@@ -2353,6 +2396,17 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
return DescriptorMapUpdateResult::Fail();
}
+ const uint32_t start_idx_init_value = 0;
+ size_t bytes_written = process->WriteMemory(
+ class_info_start_idx_addr, &start_idx_init_value, sizeof(uint32_t), err);
+ if (bytes_written != sizeof(uint32_t)) {
+ LLDB_LOGF(log,
+ "unable to write %" PRIu32
+ " bytes in process for shared cache read",
+ class_infos_byte_size);
+ return DescriptorMapUpdateResult::Fail();
+ }
+
std::lock_guard<std::mutex> guard(m_mutex);
// Fill in our function argument values
@@ -2361,12 +2415,13 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
arguments.GetValueAtIndex(2)->GetScalar() = class_infos_addr;
arguments.GetValueAtIndex(3)->GetScalar() = relative_selector_offset_addr;
arguments.GetValueAtIndex(4)->GetScalar() = class_infos_byte_size;
+ arguments.GetValueAtIndex(5)->GetScalar() = class_info_start_idx_addr;
// Only dump the runtime classes from the expression evaluation if the log is
// verbose:
Log *type_log = GetLog(LLDBLog::Types);
bool dump_log = type_log && type_log->GetVerbose();
- arguments.GetValueAtIndex(5)->GetScalar() = dump_log ? 1 : 0;
+ arguments.GetValueAtIndex(6)->GetScalar() = dump_log ? 1 : 0;
bool success = false;
@@ -2393,78 +2448,80 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
diagnostics.Clear();
- // Run the function
- ExpressionResults results =
- get_shared_cache_class_info_function->ExecuteFunction(
- exe_ctx, &m_args, options, diagnostics, return_value);
-
- if (results == eExpressionCompleted) {
- // The result is the number of ClassInfo structures that were filled in
- num_class_infos = return_value.GetScalar().ULong();
- LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache",
- num_class_infos);
- // Assert if there were more classes than we pre-allocated
- // room for.
- assert(num_class_infos <= max_num_classes);
- if (num_class_infos > 0) {
- if (num_class_infos > max_num_classes) {
- num_class_infos = max_num_classes;
-
- success = false;
- } else {
+ uint32_t num_class_infos_read = 0;
+ bool already_read_relative_selector_offset = false;
+
+ do {
+ // Run the function.
+ ExpressionResults results =
+ get_shared_cache_class_info_function->ExecuteFunction(
+ exe_ctx, &m_args, options, diagnostics, return_value);
+
+ if (results == eExpressionCompleted) {
+ // The result is the number of ClassInfo structures that were filled in.
+ num_class_infos_read = return_value.GetScalar().ULong();
+ num_class_infos += num_class_infos_read;
+ LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache",
+ num_class_infos_read);
+ if (num_class_infos_read > 0) {
success = true;
- }
- // Read the relative selector offset.
- DataBufferHeap relative_selector_offset_buffer(64, 0);
- if (process->ReadMemory(relative_selector_offset_addr,
- relative_selector_offset_buffer.GetBytes(),
- relative_selector_offset_buffer.GetByteSize(),
- err) ==
- relative_selector_offset_buffer.GetByteSize()) {
- DataExtractor relative_selector_offset_data(
- relative_selector_offset_buffer.GetBytes(),
- relative_selector_offset_buffer.GetByteSize(),
- process->GetByteOrder(), addr_size);
- lldb::offset_t offset = 0;
- uint64_t relative_selector_offset =
- relative_selector_offset_data.GetU64(&offset);
- if (relative_selector_offset > 0) {
- // The offset is relative to the objc_opt struct.
- m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +
- relative_selector_offset);
+ // Read the relative selector offset. This only needs to occur once no
+ // matter how many times the function is called.
+ if (!already_read_relative_selector_offset) {
+ DataBufferHeap relative_selector_offset_buffer(64, 0);
+ if (process->ReadMemory(
+ relative_selector_offset_addr,
+ relative_selector_offset_buffer.GetBytes(),
+ relative_selector_offset_buffer.GetByteSize(),
+ err) == relative_selector_offset_buffer.GetByteSize()) {
+ DataExtractor relative_selector_offset_data(
+ relative_selector_offset_buffer.GetBytes(),
+ relative_selector_offset_buffer.GetByteSize(),
+ process->GetByteOrder(), addr_size);
+ lldb::offset_t offset = 0;
+ uint64_t relative_selector_offset =
+ relative_selector_offset_data.GetU64(&offset);
+ if (relative_selector_offset > 0) {
+ // The offset is relative to the objc_opt struct.
+ m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +
+ relative_selector_offset);
+ }
+ }
+ already_read_relative_selector_offset = true;
}
- }
-
- // Read the ClassInfo structures
- DataBufferHeap class_infos_buffer(
- num_class_infos * class_info_byte_size, 0);
- if (process->ReadMemory(class_infos_addr, class_infos_buffer.GetBytes(),
- class_infos_buffer.GetByteSize(),
- err) == class_infos_buffer.GetByteSize()) {
- DataExtractor class_infos_data(class_infos_buffer.GetBytes(),
- class_infos_buffer.GetByteSize(),
- process->GetByteOrder(), addr_size);
- m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);
+ // Read the ClassInfo structures
+ DataBufferHeap class_infos_buffer(
+ num_class_infos_read * class_info_byte_size, 0);
+ if (process->ReadMemory(class_infos_addr,
+ class_infos_buffer.GetBytes(),
+ class_infos_buffer.GetByteSize(),
+ err) == class_infos_buffer.GetByteSize()) {
+ DataExtractor class_infos_data(class_infos_buffer.GetBytes(),
+ class_infos_buffer.GetByteSize(),
+ process->GetByteOrder(), addr_size);
+
+ m_runtime.ParseClassInfoArray(class_infos_data,
+ num_class_infos_read);
+ }
}
- } else {
- success = true;
- }
- } else {
- if (log) {
+ } else if (log) {
LLDB_LOGF(log, "Error evaluating our find class name function.");
diagnostics.Dump(log);
+ break;
}
- }
- } else {
- if (log) {
- LLDB_LOGF(log, "Error writing function arguments.");
- diagnostics.Dump(log);
- }
+ } while (num_class_infos_read == max_num_classes_in_buffer);
+ } else if (log) {
+ LLDB_LOGF(log, "Error writing function arguments.");
+ diagnostics.Dump(log);
}
- // Deallocate the memory we allocated for the ClassInfo array
+ LLDB_LOG(log, "Processed {0} Objective-C classes total from the shared cache",
+ num_class_infos);
+ // Cleanup memory we allocated in the process.
+ process->DeallocateMemory(relative_selector_offset_addr);
+ process->DeallocateMemory(class_info_start_idx_addr);
process->DeallocateMemory(class_infos_addr);
return DescriptorMapUpdateResult(success, false, num_class_infos);
diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp
index d40f87b..945b70f 100644
--- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp
+++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp
@@ -70,7 +70,7 @@ llvm::Triple::ArchType stringTo<llvm::Triple::ArchType>(llvm::StringRef Str) {
using llvm::Triple;
return llvm::StringSwitch<Triple::ArchType>(Str)
.Case("arm", Triple::arm)
- .Cases("arm64", "arm64e", Triple::aarch64)
+ .Cases({"arm64", "arm64e"}, Triple::aarch64)
.Case("mips", Triple::mips)
.Case("msp430", Triple::msp430)
.Case("ppc", Triple::ppc)
@@ -79,7 +79,7 @@ llvm::Triple::ArchType stringTo<llvm::Triple::ArchType>(llvm::StringRef Str) {
.Case("sparc", Triple::sparc)
.Case("sparcv9", Triple::sparcv9)
.Case("x86", Triple::x86)
- .Cases("x86_64", "x86_64h", Triple::x86_64)
+ .Cases({"x86_64", "x86_64h"}, Triple::x86_64)
.Default(Triple::UnknownArch);
}
diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
index 33673f1..53ff6ef6 100644
--- a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
+++ b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
@@ -130,13 +130,13 @@ void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
std::optional<Record::Kind> current_section;
offset_t section_start;
- llvm::StringRef text = toStringRef(m_data.GetData());
+ llvm::StringRef text = toStringRef(m_data_nsp->GetData());
uint32_t next_section_id = 1;
auto maybe_add_section = [&](const uint8_t *end_ptr) {
if (!current_section)
return; // We have been called before parsing the first line.
- offset_t end_offset = end_ptr - m_data.GetDataStart();
+ offset_t end_offset = end_ptr - m_data_nsp->GetDataStart();
auto section_sp = std::make_shared<Section>(
GetModule(), this, next_section_id++,
ConstString(toString(*current_section)), eSectionTypeOther,
@@ -162,8 +162,8 @@ void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
maybe_add_section(line.bytes_begin());
// And start a new one.
current_section = next_section;
- section_start = line.bytes_begin() - m_data.GetDataStart();
+ section_start = line.bytes_begin() - m_data_nsp->GetDataStart();
}
// Finally, add the last section.
- maybe_add_section(m_data.GetDataEnd());
+ maybe_add_section(m_data_nsp->GetDataEnd());
}
diff --git a/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp b/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp
index 1121f69..e78f4f0 100644
--- a/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp
@@ -300,8 +300,8 @@ bool ObjectFileCOFF::ParseHeader() {
std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
- m_data.SetByteOrder(eByteOrderLittle);
- m_data.SetAddressByteSize(GetAddressByteSize());
+ m_data_nsp->SetByteOrder(eByteOrderLittle);
+ m_data_nsp->SetAddressByteSize(GetAddressByteSize());
return true;
}
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 097c91b..5d81b11 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -130,6 +130,29 @@ private:
RelocUnion reloc;
};
+
+lldb::SectionSP MergeSections(lldb::SectionSP lhs, lldb::SectionSP rhs) {
+ assert(lhs && rhs);
+
+ lldb::ModuleSP lhs_module_parent = lhs->GetModule();
+ lldb::ModuleSP rhs_module_parent = rhs->GetModule();
+ assert(lhs_module_parent && rhs_module_parent);
+
+ // Do a sanity check, these should be the same.
+ if (lhs->GetFileAddress() != rhs->GetFileAddress())
+ lhs_module_parent->ReportWarning(
+ "Mismatch addresses for section {0} when "
+ "merging with {1}, expected: {2:x}, "
+ "actual: {3:x}",
+ lhs->GetTypeAsCString(),
+ rhs_module_parent->GetFileSpec().GetPathAsConstString().GetCString(),
+ lhs->GetByteSize(), rhs->GetByteSize());
+
+ // We want to take the greater of two sections. If LHS and RHS are both
+ // SHT_NOBITS, we should default to LHS. If RHS has a bigger section,
+ // indicating it has data that wasn't stripped, we should take that instead.
+ return rhs->GetFileSize() > lhs->GetFileSize() ? rhs : lhs;
+}
} // end anonymous namespace
ELFRelocation::ELFRelocation(unsigned type) {
@@ -781,7 +804,7 @@ ByteOrder ObjectFileELF::GetByteOrder() const {
}
uint32_t ObjectFileELF::GetAddressByteSize() const {
- return m_data.GetAddressByteSize();
+ return m_data_nsp->GetAddressByteSize();
}
AddressClass ObjectFileELF::GetAddressClass(addr_t file_addr) {
@@ -822,7 +845,7 @@ size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const {
bool ObjectFileELF::ParseHeader() {
lldb::offset_t offset = 0;
- return m_header.Parse(m_data, &offset);
+ return m_header.Parse(*m_data_nsp.get(), &offset);
}
UUID ObjectFileELF::GetUUID() {
@@ -858,7 +881,7 @@ UUID ObjectFileELF::GetUUID() {
return UUID();
core_notes_crc =
- CalculateELFNotesSegmentsCRC32(m_program_headers, m_data);
+ CalculateELFNotesSegmentsCRC32(m_program_headers, *m_data_nsp.get());
if (core_notes_crc) {
// Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it
@@ -869,7 +892,7 @@ UUID ObjectFileELF::GetUUID() {
}
} else {
if (!m_gnu_debuglink_crc)
- m_gnu_debuglink_crc = calc_crc32(0, m_data);
+ m_gnu_debuglink_crc = calc_crc32(0, *m_data_nsp.get());
if (m_gnu_debuglink_crc) {
// Use 4 bytes of crc from the .gnu_debuglink section.
u32le data(m_gnu_debuglink_crc);
@@ -1055,7 +1078,8 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
// ParseProgramHeaders
bool ObjectFileELF::ParseProgramHeaders() {
- return GetProgramHeaderInfo(m_program_headers, m_data, m_header) != 0;
+ return GetProgramHeaderInfo(m_program_headers, *m_data_nsp.get(), m_header) !=
+ 0;
}
lldb_private::Status
@@ -1645,8 +1669,8 @@ ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const {
// ParseSectionHeaders
size_t ObjectFileELF::ParseSectionHeaders() {
- return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid,
- m_gnu_debuglink_file, m_gnu_debuglink_crc,
+ return GetSectionHeaderInfo(m_section_headers, *m_data_nsp.get(), m_header,
+ m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc,
m_arch_spec);
}
@@ -1678,7 +1702,7 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
.Case(".ARM.exidx", eSectionTypeARMexidx)
.Case(".ARM.extab", eSectionTypeARMextab)
.Case(".ctf", eSectionTypeDebug)
- .Cases(".data", ".tdata", eSectionTypeData)
+ .Cases({".data", ".tdata"}, eSectionTypeData)
.Case(".eh_frame", eSectionTypeEHFrame)
.Case(".gnu_debugaltlink", eSectionTypeDWARFGNUDebugAltLink)
.Case(".gosymtab", eSectionTypeGoSymtab)
@@ -1967,10 +1991,10 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) {
provider.AddSection(std::move(*InfoOr), std::move(section_sp));
}
- // For eTypeDebugInfo files, the Symbol Vendor will take care of updating the
- // unified section list.
- if (GetType() != eTypeDebugInfo)
- unified_section_list = *m_sections_up;
+ // Merge the two adding any new sections, and overwriting any existing
+ // sections that are SHT_NOBITS
+ unified_section_list =
+ SectionList::Merge(unified_section_list, *m_sections_up, MergeSections);
// If there's a .gnu_debugdata section, we'll try to read the .symtab that's
// embedded in there and replace the one in the original object file (if any).
@@ -2735,9 +2759,8 @@ static void ApplyELF64ABS64Relocation(Symtab *symtab, ELFRelocation &rel,
// ObjectFileELF creates a WritableDataBuffer in CreateInstance.
WritableDataBuffer *data_buffer =
llvm::cast<WritableDataBuffer>(data_buffer_sp.get());
- uint64_t *dst = reinterpret_cast<uint64_t *>(
- data_buffer->GetBytes() + rel_section->GetFileOffset() +
- ELFRelocation::RelocOffset64(rel));
+ void *const dst = data_buffer->GetBytes() + rel_section->GetFileOffset() +
+ ELFRelocation::RelocOffset64(rel);
uint64_t val_offset = value + ELFRelocation::RelocAddend64(rel);
memcpy(dst, &val_offset, sizeof(uint64_t));
}
@@ -2762,9 +2785,8 @@ static void ApplyELF64ABS32Relocation(Symtab *symtab, ELFRelocation &rel,
// ObjectFileELF creates a WritableDataBuffer in CreateInstance.
WritableDataBuffer *data_buffer =
llvm::cast<WritableDataBuffer>(data_buffer_sp.get());
- uint32_t *dst = reinterpret_cast<uint32_t *>(
- data_buffer->GetBytes() + rel_section->GetFileOffset() +
- ELFRelocation::RelocOffset32(rel));
+ void *const dst = data_buffer->GetBytes() + rel_section->GetFileOffset() +
+ ELFRelocation::RelocOffset32(rel);
memcpy(dst, &truncated_addr, sizeof(uint32_t));
}
}
@@ -3657,7 +3679,8 @@ ArchSpec ObjectFileELF::GetArchitecture() {
if (H.p_type != PT_NOTE || H.p_offset == 0 || H.p_filesz == 0)
continue;
DataExtractor data;
- if (data.SetData(m_data, H.p_offset, H.p_filesz) == H.p_filesz) {
+ if (data.SetData(*m_data_nsp.get(), H.p_offset, H.p_filesz) ==
+ H.p_filesz) {
UUID uuid;
RefineModuleDetailsFromNote(data, m_arch_spec, uuid);
}
@@ -3812,10 +3835,10 @@ llvm::ArrayRef<ELFProgramHeader> ObjectFileELF::ProgramHeaders() {
}
DataExtractor ObjectFileELF::GetSegmentData(const ELFProgramHeader &H) {
- // Try and read the program header from our cached m_data which can come from
- // the file on disk being mmap'ed or from the initial part of the ELF file we
- // read from memory and cached.
- DataExtractor data = DataExtractor(m_data, H.p_offset, H.p_filesz);
+ // Try and read the program header from our cached m_data_nsp which can come
+ // from the file on disk being mmap'ed or from the initial part of the ELF
+ // file we read from memory and cached.
+ DataExtractor data = DataExtractor(*m_data_nsp.get(), H.p_offset, H.p_filesz);
if (data.GetByteSize() == H.p_filesz)
return data;
if (IsInMemory()) {
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 9cdb846..dff9eab 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -1012,35 +1012,35 @@ bool ObjectFileMachO::ParseHeader() {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
bool can_parse = false;
lldb::offset_t offset = 0;
- m_data.SetByteOrder(endian::InlHostByteOrder());
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder());
// Leave magic in the original byte order
- m_header.magic = m_data.GetU32(&offset);
+ m_header.magic = m_data_nsp->GetU32(&offset);
switch (m_header.magic) {
case MH_MAGIC:
- m_data.SetByteOrder(endian::InlHostByteOrder());
- m_data.SetAddressByteSize(4);
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder());
+ m_data_nsp->SetAddressByteSize(4);
can_parse = true;
break;
case MH_MAGIC_64:
- m_data.SetByteOrder(endian::InlHostByteOrder());
- m_data.SetAddressByteSize(8);
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder());
+ m_data_nsp->SetAddressByteSize(8);
can_parse = true;
break;
case MH_CIGAM:
- m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
- ? eByteOrderLittle
- : eByteOrderBig);
- m_data.SetAddressByteSize(4);
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+ ? eByteOrderLittle
+ : eByteOrderBig);
+ m_data_nsp->SetAddressByteSize(4);
can_parse = true;
break;
case MH_CIGAM_64:
- m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
- ? eByteOrderLittle
- : eByteOrderBig);
- m_data.SetAddressByteSize(8);
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+ ? eByteOrderLittle
+ : eByteOrderBig);
+ m_data_nsp->SetAddressByteSize(8);
can_parse = true;
break;
@@ -1049,12 +1049,13 @@ bool ObjectFileMachO::ParseHeader() {
}
if (can_parse) {
- m_data.GetU32(&offset, &m_header.cputype, 6);
+ m_data_nsp->GetU32(&offset, &m_header.cputype, 6);
ModuleSpecList all_specs;
ModuleSpec base_spec;
- GetAllArchSpecs(m_header, m_data, MachHeaderSizeFromMagic(m_header.magic),
- base_spec, all_specs);
+ GetAllArchSpecs(m_header, *m_data_nsp.get(),
+ MachHeaderSizeFromMagic(m_header.magic), base_spec,
+ all_specs);
for (unsigned i = 0, e = all_specs.GetSize(); i != e; ++i) {
ArchSpec mach_arch =
@@ -1068,7 +1069,7 @@ bool ObjectFileMachO::ParseHeader() {
if (SetModulesArchitecture(mach_arch)) {
const size_t header_and_lc_size =
m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic);
- if (m_data.GetByteSize() < header_and_lc_size) {
+ if (m_data_nsp->GetByteSize() < header_and_lc_size) {
DataBufferSP data_sp;
ProcessSP process_sp(m_process_wp.lock());
if (process_sp) {
@@ -1080,7 +1081,7 @@ bool ObjectFileMachO::ParseHeader() {
continue;
}
if (data_sp)
- m_data.SetData(data_sp);
+ m_data_nsp->SetData(data_sp);
}
}
return true;
@@ -1094,7 +1095,7 @@ bool ObjectFileMachO::ParseHeader() {
}
ByteOrder ObjectFileMachO::GetByteOrder() const {
- return m_data.GetByteOrder();
+ return m_data_nsp->GetByteOrder();
}
bool ObjectFileMachO::IsExecutable() const {
@@ -1114,7 +1115,7 @@ bool ObjectFileMachO::IsKext() const {
}
uint32_t ObjectFileMachO::GetAddressByteSize() const {
- return m_data.GetAddressByteSize();
+ return m_data_nsp->GetAddressByteSize();
}
AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) {
@@ -1297,13 +1298,13 @@ bool ObjectFileMachO::IsStripped() {
const lldb::offset_t load_cmd_offset = offset;
llvm::MachO::load_command lc = {};
- if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &lc.cmd, 2) == nullptr)
break;
if (lc.cmd == LC_DYSYMTAB) {
m_dysymtab.cmd = lc.cmd;
m_dysymtab.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &m_dysymtab.ilocalsym,
- (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) ==
+ if (m_data_nsp->GetU32(&offset, &m_dysymtab.ilocalsym,
+ (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) ==
nullptr) {
// Clear m_dysymtab if we were unable to read all items from the
// load command
@@ -1326,14 +1327,14 @@ ObjectFileMachO::EncryptedFileRanges ObjectFileMachO::GetEncryptedFileRanges() {
llvm::MachO::encryption_info_command encryption_cmd;
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const lldb::offset_t load_cmd_offset = offset;
- if (m_data.GetU32(&offset, &encryption_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &encryption_cmd, 2) == nullptr)
break;
// LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for the
// 3 fields we care about, so treat them the same.
if (encryption_cmd.cmd == LC_ENCRYPTION_INFO ||
encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) {
- if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) {
+ if (m_data_nsp->GetU32(&offset, &encryption_cmd.cryptoff, 3)) {
if (encryption_cmd.cryptid != 0) {
EncryptedFileRanges::Entry entry;
entry.SetRangeBase(encryption_cmd.cryptoff);
@@ -1562,7 +1563,7 @@ void ObjectFileMachO::ProcessSegmentCommand(
llvm::MachO::segment_command_64 load_cmd;
memcpy(&load_cmd, &load_cmd_, sizeof(load_cmd_));
- if (!m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16))
+ if (!m_data_nsp->GetU8(&offset, (uint8_t *)load_cmd.segname, 16))
return;
ModuleSP module_sp = GetModule();
@@ -1586,11 +1587,11 @@ void ObjectFileMachO::ProcessSegmentCommand(
add_section = false;
}
}
- load_cmd.vmaddr = m_data.GetAddress(&offset);
- load_cmd.vmsize = m_data.GetAddress(&offset);
- load_cmd.fileoff = m_data.GetAddress(&offset);
- load_cmd.filesize = m_data.GetAddress(&offset);
- if (!m_data.GetU32(&offset, &load_cmd.maxprot, 4))
+ load_cmd.vmaddr = m_data_nsp->GetAddress(&offset);
+ load_cmd.vmsize = m_data_nsp->GetAddress(&offset);
+ load_cmd.fileoff = m_data_nsp->GetAddress(&offset);
+ load_cmd.filesize = m_data_nsp->GetAddress(&offset);
+ if (!m_data_nsp->GetU32(&offset, &load_cmd.maxprot, 4))
return;
SanitizeSegmentCommand(load_cmd, cmd_idx);
@@ -1674,19 +1675,23 @@ void ObjectFileMachO::ProcessSegmentCommand(
uint32_t segment_sect_idx;
const lldb::user_id_t first_segment_sectID = context.NextSectionIdx + 1;
+ // 64 bit mach-o files have sections with 32 bit file offsets. If any section
+ // data end will exceed UINT32_MAX, then we need to do some bookkeeping to
+ // ensure we can access this data correctly.
+ uint64_t section_offset_adjust = 0;
const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects;
++segment_sect_idx) {
- if (m_data.GetU8(&offset, (uint8_t *)sect64.sectname,
- sizeof(sect64.sectname)) == nullptr)
+ if (m_data_nsp->GetU8(&offset, (uint8_t *)sect64.sectname,
+ sizeof(sect64.sectname)) == nullptr)
break;
- if (m_data.GetU8(&offset, (uint8_t *)sect64.segname,
- sizeof(sect64.segname)) == nullptr)
+ if (m_data_nsp->GetU8(&offset, (uint8_t *)sect64.segname,
+ sizeof(sect64.segname)) == nullptr)
break;
- sect64.addr = m_data.GetAddress(&offset);
- sect64.size = m_data.GetAddress(&offset);
+ sect64.addr = m_data_nsp->GetAddress(&offset);
+ sect64.size = m_data_nsp->GetAddress(&offset);
- if (m_data.GetU32(&offset, &sect64.offset, num_u32s) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &sect64.offset, num_u32s) == nullptr)
break;
if (IsSharedCacheBinary() && !IsInMemory()) {
@@ -1697,6 +1702,16 @@ void ObjectFileMachO::ProcessSegmentCommand(
// isn't stored in the abstracted Sections.
m_mach_sections.push_back(sect64);
+ // Make sure we can load sections in mach-o files where some sections cross
+ // a 4GB boundary. llvm::MachO::section_64 have only 32 bit file offsets
+ // for the file offset of the section contents, so we need to track and
+ // sections that overflow and adjust the offsets accordingly.
+ const uint64_t section_file_offset =
+ (uint64_t)sect64.offset + section_offset_adjust;
+ const uint64_t end_section_offset = (uint64_t)sect64.offset + sect64.size;
+ if (end_section_offset >= UINT32_MAX)
+ section_offset_adjust += end_section_offset & 0xFFFFFFFF00000000ull;
+
if (add_section) {
ConstString section_name(
sect64.sectname, strnlen(sect64.sectname, sizeof(sect64.sectname)));
@@ -1736,13 +1751,13 @@ void ObjectFileMachO::ProcessSegmentCommand(
}
// Grow the section size as needed.
- if (sect64.offset) {
+ if (section_file_offset) {
const lldb::addr_t segment_min_file_offset =
segment->GetFileOffset();
const lldb::addr_t segment_max_file_offset =
segment_min_file_offset + segment->GetFileSize();
- const lldb::addr_t section_min_file_offset = sect64.offset;
+ const lldb::addr_t section_min_file_offset = section_file_offset;
const lldb::addr_t section_max_file_offset =
section_min_file_offset + sect64.size;
const lldb::addr_t new_file_offset =
@@ -1769,10 +1784,10 @@ void ObjectFileMachO::ProcessSegmentCommand(
// other sections.
sect64.addr, // File VM address == addresses as they are
// found in the object file
- sect64.size, // VM size in bytes of this section
- sect64.offset, // Offset to the data for this section in
+ sect64.size, // VM size in bytes of this section
+ section_file_offset, // Offset to the data for this section in
// the file
- sect64.offset ? sect64.size : 0, // Size in bytes of
+ section_file_offset ? sect64.size : 0, // Size in bytes of
// this section as
// found in the file
sect64.align,
@@ -1792,14 +1807,14 @@ void ObjectFileMachO::ProcessSegmentCommand(
SectionSP section_sp(new Section(
segment_sp, module_sp, this, ++context.NextSectionIdx, section_name,
sect_type, sect64.addr - segment_sp->GetFileAddress(), sect64.size,
- sect64.offset, sect64.offset == 0 ? 0 : sect64.size, sect64.align,
- sect64.flags));
+ section_file_offset, section_file_offset == 0 ? 0 : sect64.size,
+ sect64.align, sect64.flags));
// Set the section to be encrypted to match the segment
bool section_is_encrypted = false;
if (!segment_is_encrypted && load_cmd.filesize != 0)
section_is_encrypted = context.EncryptedRanges.FindEntryThatContains(
- sect64.offset) != nullptr;
+ section_file_offset) != nullptr;
section_sp->SetIsEncrypted(segment_is_encrypted || section_is_encrypted);
section_sp->SetPermissions(segment_permissions);
@@ -1841,8 +1856,8 @@ void ObjectFileMachO::ProcessDysymtabCommand(
const llvm::MachO::load_command &load_cmd, lldb::offset_t offset) {
m_dysymtab.cmd = load_cmd.cmd;
m_dysymtab.cmdsize = load_cmd.cmdsize;
- m_data.GetU32(&offset, &m_dysymtab.ilocalsym,
- (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
+ m_data_nsp->GetU32(&offset, &m_dysymtab.ilocalsym,
+ (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
}
void ObjectFileMachO::CreateSections(SectionList &unified_section_list) {
@@ -1861,7 +1876,7 @@ void ObjectFileMachO::CreateSections(SectionList &unified_section_list) {
llvm::MachO::load_command load_cmd;
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const lldb::offset_t load_cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd, 2) == nullptr)
break;
if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64)
@@ -2226,13 +2241,13 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
const lldb::offset_t cmd_offset = offset;
// Read in the load command and load command size
llvm::MachO::load_command lc;
- if (m_data.GetU32(&offset, &lc, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &lc, 2) == nullptr)
break;
// Watch for the symbol table load command
switch (lc.cmd) {
case LC_SYMTAB: {
llvm::MachO::symtab_command lc_obj;
- if (m_data.GetU32(&offset, &lc_obj.symoff, 4)) {
+ if (m_data_nsp->GetU32(&offset, &lc_obj.symoff, 4)) {
lc_obj.cmd = lc.cmd;
lc_obj.cmdsize = lc.cmdsize;
symtab_load_command = lc_obj;
@@ -2242,7 +2257,7 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
case LC_DYLD_INFO:
case LC_DYLD_INFO_ONLY: {
llvm::MachO::dyld_info_command lc_obj;
- if (m_data.GetU32(&offset, &lc_obj.rebase_off, 10)) {
+ if (m_data_nsp->GetU32(&offset, &lc_obj.rebase_off, 10)) {
lc_obj.cmd = lc.cmd;
lc_obj.cmdsize = lc.cmdsize;
dyld_info = lc_obj;
@@ -2254,8 +2269,8 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
case LC_REEXPORT_DYLIB:
case LC_LOADFVMLIB:
case LC_LOAD_UPWARD_DYLIB: {
- uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
- const char *path = m_data.PeekCStr(name_offset);
+ uint32_t name_offset = cmd_offset + m_data_nsp->GetU32(&offset);
+ const char *path = m_data_nsp->PeekCStr(name_offset);
if (path) {
FileSpec file_spec(path);
// Strip the path if there is @rpath, @executable, etc so we just use
@@ -2275,19 +2290,19 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
llvm::MachO::linkedit_data_command lc_obj;
lc_obj.cmd = lc.cmd;
lc_obj.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &lc_obj.dataoff, 2))
+ if (m_data_nsp->GetU32(&offset, &lc_obj.dataoff, 2))
exports_trie_load_command = lc_obj;
} break;
case LC_FUNCTION_STARTS: {
llvm::MachO::linkedit_data_command lc_obj;
lc_obj.cmd = lc.cmd;
lc_obj.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &lc_obj.dataoff, 2))
+ if (m_data_nsp->GetU32(&offset, &lc_obj.dataoff, 2))
function_starts_load_command = lc_obj;
} break;
case LC_UUID: {
- const uint8_t *uuid_bytes = m_data.PeekData(offset, 16);
+ const uint8_t *uuid_bytes = m_data_nsp->PeekData(offset, 16);
if (uuid_bytes)
image_uuid = UUID(uuid_bytes, 16);
@@ -2307,8 +2322,8 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
if (section_list == nullptr)
return;
- const uint32_t addr_byte_size = m_data.GetAddressByteSize();
- const ByteOrder byte_order = m_data.GetByteOrder();
+ const uint32_t addr_byte_size = m_data_nsp->GetAddressByteSize();
+ const ByteOrder byte_order = m_data_nsp->GetByteOrder();
bool bit_width_32 = addr_byte_size == 4;
const size_t nlist_byte_size =
bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64);
@@ -2473,9 +2488,9 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
exports_trie_load_command.dataoff += linkedit_slide;
}
- nlist_data.SetData(m_data, symtab_load_command.symoff,
+ nlist_data.SetData(*m_data_nsp.get(), symtab_load_command.symoff,
nlist_data_byte_size);
- strtab_data.SetData(m_data, symtab_load_command.stroff,
+ strtab_data.SetData(*m_data_nsp.get(), symtab_load_command.stroff,
strtab_data_byte_size);
// We shouldn't have exports data from both the LC_DYLD_INFO command
@@ -2483,19 +2498,22 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
lldbassert(!((dyld_info.export_size > 0)
&& (exports_trie_load_command.datasize > 0)));
if (dyld_info.export_size > 0) {
- dyld_trie_data.SetData(m_data, dyld_info.export_off,
+ dyld_trie_data.SetData(*m_data_nsp.get(), dyld_info.export_off,
dyld_info.export_size);
} else if (exports_trie_load_command.datasize > 0) {
- dyld_trie_data.SetData(m_data, exports_trie_load_command.dataoff,
+ dyld_trie_data.SetData(*m_data_nsp.get(),
+ exports_trie_load_command.dataoff,
exports_trie_load_command.datasize);
}
if (dysymtab.nindirectsyms != 0) {
- indirect_symbol_index_data.SetData(m_data, dysymtab.indirectsymoff,
+ indirect_symbol_index_data.SetData(*m_data_nsp.get(),
+ dysymtab.indirectsymoff,
dysymtab.nindirectsyms * 4);
}
if (function_starts_load_command.cmd) {
- function_starts_data.SetData(m_data, function_starts_load_command.dataoff,
+ function_starts_data.SetData(*m_data_nsp.get(),
+ function_starts_load_command.dataoff,
function_starts_load_command.datasize);
}
}
@@ -4547,8 +4565,9 @@ void ObjectFileMachO::Dump(Stream *s) {
*s << ", file = '" << m_file;
ModuleSpecList all_specs;
ModuleSpec base_spec;
- GetAllArchSpecs(m_header, m_data, MachHeaderSizeFromMagic(m_header.magic),
- base_spec, all_specs);
+ GetAllArchSpecs(m_header, *m_data_nsp.get(),
+ MachHeaderSizeFromMagic(m_header.magic), base_spec,
+ all_specs);
for (unsigned i = 0, e = all_specs.GetSize(); i != e; ++i) {
*s << "', triple";
if (e)
@@ -4854,7 +4873,7 @@ UUID ObjectFileMachO::GetUUID() {
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- return GetUUID(m_header, m_data, offset);
+ return GetUUID(m_header, *m_data_nsp.get(), offset);
}
return UUID();
}
@@ -4874,7 +4893,7 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
uint32_t i;
for (i = 0; i < m_header.ncmds; ++i) {
const uint32_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd, 2) == nullptr)
break;
switch (load_cmd.cmd) {
@@ -4885,17 +4904,17 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
case LC_LOAD_DYLINKER:
case LC_LOADFVMLIB:
case LC_LOAD_UPWARD_DYLIB: {
- uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ uint32_t name_offset = cmd_offset + m_data_nsp->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);
+ uint32_t use_command_marker = m_data_nsp->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);
+ uint32_t flags = m_data_nsp->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,
@@ -4903,7 +4922,7 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
if (flags & 0x08 /* DYLIB_USE_DELAYED_INIT */)
is_delayed_init = true;
}
- const char *path = m_data.PeekCStr(name_offset);
+ const char *path = m_data_nsp->PeekCStr(name_offset);
if (path && !is_delayed_init) {
if (load_cmd.cmd == LC_RPATH)
rpath_paths.push_back(path);
@@ -5023,15 +5042,15 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
for (i = 0; i < m_header.ncmds; ++i) {
const lldb::offset_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd, 2) == nullptr)
break;
switch (load_cmd.cmd) {
case LC_UNIXTHREAD:
case LC_THREAD: {
while (offset < cmd_offset + load_cmd.cmdsize) {
- uint32_t flavor = m_data.GetU32(&offset);
- uint32_t count = m_data.GetU32(&offset);
+ uint32_t flavor = m_data_nsp->GetU32(&offset);
+ uint32_t count = m_data_nsp->GetU32(&offset);
if (count == 0) {
// We've gotten off somehow, log and exit;
return m_entry_point_address;
@@ -5045,7 +5064,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
{
offset += 60; // This is the offset of pc in the GPR thread state
// data structure.
- start_address = m_data.GetU32(&offset);
+ start_address = m_data_nsp->GetU32(&offset);
done = true;
}
break;
@@ -5055,7 +5074,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
{
offset += 256; // This is the offset of pc in the GPR thread state
// data structure.
- start_address = m_data.GetU64(&offset);
+ start_address = m_data_nsp->GetU64(&offset);
done = true;
}
break;
@@ -5065,7 +5084,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
{
offset += 16 * 8; // This is the offset of rip in the GPR thread
// state data structure.
- start_address = m_data.GetU64(&offset);
+ start_address = m_data_nsp->GetU64(&offset);
done = true;
}
break;
@@ -5080,7 +5099,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
}
} break;
case LC_MAIN: {
- uint64_t entryoffset = m_data.GetU64(&offset);
+ uint64_t entryoffset = m_data_nsp->GetU64(&offset);
SectionSP text_segment_sp =
GetSectionList()->FindSectionByName(GetSegmentNameTEXT());
if (text_segment_sp) {
@@ -5164,7 +5183,7 @@ uint32_t ObjectFileMachO::GetNumThreadContexts() {
llvm::MachO::thread_command thread_cmd;
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const uint32_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &thread_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &thread_cmd, 2) == nullptr)
break;
if (thread_cmd.cmd == LC_THREAD) {
@@ -5190,17 +5209,17 @@ ObjectFileMachO::FindLC_NOTEByName(std::string name) {
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const uint32_t cmd_offset = offset;
llvm::MachO::load_command lc = {};
- if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &lc.cmd, 2) == nullptr)
break;
if (lc.cmd == LC_NOTE) {
char data_owner[17];
- m_data.CopyData(offset, 16, data_owner);
+ m_data_nsp->CopyData(offset, 16, data_owner);
data_owner[16] = '\0';
offset += 16;
if (name == data_owner) {
- offset_t payload_offset = m_data.GetU64_unchecked(&offset);
- offset_t payload_size = m_data.GetU64_unchecked(&offset);
+ offset_t payload_offset = m_data_nsp->GetU64_unchecked(&offset);
+ offset_t payload_size = m_data_nsp->GetU64_unchecked(&offset);
results.push_back({payload_offset, payload_size});
}
}
@@ -5222,11 +5241,11 @@ std::string ObjectFileMachO::GetIdentifierString() {
offset_t payload_offset = std::get<0>(lc_note);
offset_t payload_size = std::get<1>(lc_note);
uint32_t version;
- if (m_data.GetU32(&payload_offset, &version, 1) != nullptr) {
+ if (m_data_nsp->GetU32(&payload_offset, &version, 1) != nullptr) {
if (version == 1) {
uint32_t strsize = payload_size - sizeof(uint32_t);
std::string result(strsize, '\0');
- m_data.CopyData(payload_offset, strsize, result.data());
+ m_data_nsp->CopyData(payload_offset, strsize, result.data());
LLDB_LOGF(log, "LC_NOTE 'kern ver str' found with text '%s'",
result.c_str());
return result;
@@ -5240,12 +5259,12 @@ std::string ObjectFileMachO::GetIdentifierString() {
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const uint32_t cmd_offset = offset;
llvm::MachO::ident_command ident_command;
- if (m_data.GetU32(&offset, &ident_command, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &ident_command, 2) == nullptr)
break;
if (ident_command.cmd == LC_IDENT && ident_command.cmdsize != 0) {
std::string result(ident_command.cmdsize, '\0');
- if (m_data.CopyData(offset, ident_command.cmdsize, result.data()) ==
- ident_command.cmdsize) {
+ if (m_data_nsp->CopyData(offset, ident_command.cmdsize,
+ result.data()) == ident_command.cmdsize) {
LLDB_LOGF(log, "LC_IDENT found with text '%s'", result.c_str());
return result;
}
@@ -5267,9 +5286,10 @@ AddressableBits ObjectFileMachO::GetAddressableBits() {
for (auto lc_note : lc_notes) {
offset_t payload_offset = std::get<0>(lc_note);
uint32_t version;
- if (m_data.GetU32(&payload_offset, &version, 1) != nullptr) {
+ if (m_data_nsp->GetU32(&payload_offset, &version, 1) != nullptr) {
if (version == 3) {
- uint32_t num_addr_bits = m_data.GetU32_unchecked(&payload_offset);
+ uint32_t num_addr_bits =
+ m_data_nsp->GetU32_unchecked(&payload_offset);
addressable_bits.SetAddressableBits(num_addr_bits);
LLDB_LOGF(log,
"LC_NOTE 'addrable bits' v3 found, value %d "
@@ -5277,8 +5297,8 @@ AddressableBits ObjectFileMachO::GetAddressableBits() {
num_addr_bits);
}
if (version == 4) {
- uint32_t lo_addr_bits = m_data.GetU32_unchecked(&payload_offset);
- uint32_t hi_addr_bits = m_data.GetU32_unchecked(&payload_offset);
+ uint32_t lo_addr_bits = m_data_nsp->GetU32_unchecked(&payload_offset);
+ uint32_t hi_addr_bits = m_data_nsp->GetU32_unchecked(&payload_offset);
if (lo_addr_bits == hi_addr_bits)
addressable_bits.SetAddressableBits(lo_addr_bits);
@@ -5349,25 +5369,26 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value,
// uint32_t unused [ for alignment ]
uint32_t version;
- if (m_data.GetU32(&payload_offset, &version, 1) != nullptr &&
+ if (m_data_nsp->GetU32(&payload_offset, &version, 1) != nullptr &&
version <= 2) {
uint32_t binspec_type = 0;
uuid_t raw_uuid;
memset(raw_uuid, 0, sizeof(uuid_t));
- if (!m_data.GetU32(&payload_offset, &binspec_type, 1))
+ if (!m_data_nsp->GetU32(&payload_offset, &binspec_type, 1))
return false;
- if (!m_data.GetU64(&payload_offset, &value, 1))
+ if (!m_data_nsp->GetU64(&payload_offset, &value, 1))
return false;
uint64_t slide = LLDB_INVALID_ADDRESS;
- if (version > 1 && !m_data.GetU64(&payload_offset, &slide, 1))
+ if (version > 1 && !m_data_nsp->GetU64(&payload_offset, &slide, 1))
return false;
if (value == LLDB_INVALID_ADDRESS && slide != LLDB_INVALID_ADDRESS) {
value = slide;
value_is_offset = true;
}
- if (m_data.CopyData(payload_offset, sizeof(uuid_t), raw_uuid) != 0) {
+ if (m_data_nsp->CopyData(payload_offset, sizeof(uuid_t), raw_uuid) !=
+ 0) {
uuid = UUID(raw_uuid, sizeof(uuid_t));
// convert the "main bin spec" type into our
// ObjectFile::BinaryType enum
@@ -5401,9 +5422,9 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value,
version, type, typestr, value,
value_is_offset ? "true" : "false",
uuid.GetAsString().c_str());
- if (!m_data.GetU32(&payload_offset, &log2_pagesize, 1))
+ if (!m_data_nsp->GetU32(&payload_offset, &log2_pagesize, 1))
return false;
- if (version > 1 && !m_data.GetU32(&payload_offset, &platform, 1))
+ if (version > 1 && !m_data_nsp->GetU32(&payload_offset, &platform, 1))
return false;
return true;
}
@@ -5483,7 +5504,7 @@ StructuredData::ObjectSP ObjectFileMachO::GetCorefileProcessMetadata() {
auto [payload_offset, strsize] = lc_notes[0];
std::string buf(strsize, '\0');
- if (m_data.CopyData(payload_offset, strsize, buf.data()) != strsize) {
+ if (m_data_nsp->CopyData(payload_offset, strsize, buf.data()) != strsize) {
LLDB_LOGF(log,
"Unable to read %" PRIu64
" bytes of 'process metadata' LC_NOTE JSON contents",
@@ -5523,7 +5544,8 @@ ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx,
m_thread_context_offsets.GetEntryAtIndex(idx);
if (thread_context_file_range) {
- DataExtractor data(m_data, thread_context_file_range->GetRangeBase(),
+ DataExtractor data(*m_data_nsp.get(),
+ thread_context_file_range->GetRangeBase(),
thread_context_file_range->GetByteSize());
switch (m_header.cputype) {
@@ -5663,13 +5685,13 @@ llvm::VersionTuple ObjectFileMachO::GetVersion() {
uint32_t i;
for (i = 0; i < m_header.ncmds; ++i) {
const lldb::offset_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd, 2) == nullptr)
break;
if (load_cmd.cmd == LC_ID_DYLIB) {
if (version_cmd == 0) {
version_cmd = load_cmd.cmd;
- if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd.dylib, 4) == nullptr)
break;
version = load_cmd.dylib.current_version;
}
@@ -5695,7 +5717,7 @@ ArchSpec ObjectFileMachO::GetArchitecture() {
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- return GetArchitecture(module_sp, m_header, m_data,
+ return GetArchitecture(module_sp, m_header, *m_data_nsp.get(),
MachHeaderSizeFromMagic(m_header.magic));
}
return arch;
@@ -5866,14 +5888,16 @@ static llvm::VersionTuple FindMinimumVersionInfo(DataExtractor &data,
llvm::VersionTuple ObjectFileMachO::GetMinimumOSVersion() {
if (!m_min_os_version)
m_min_os_version = FindMinimumVersionInfo(
- m_data, MachHeaderSizeFromMagic(m_header.magic), m_header.ncmds);
+ *m_data_nsp.get(), MachHeaderSizeFromMagic(m_header.magic),
+ m_header.ncmds);
return *m_min_os_version;
}
llvm::VersionTuple ObjectFileMachO::GetSDKVersion() {
if (!m_sdk_versions)
m_sdk_versions = FindMinimumVersionInfo(
- m_data, MachHeaderSizeFromMagic(m_header.magic), m_header.ncmds);
+ *m_data_nsp.get(), MachHeaderSizeFromMagic(m_header.magic),
+ m_header.ncmds);
return *m_sdk_versions;
}
@@ -5922,6 +5946,20 @@ Section *ObjectFileMachO::GetMachHeaderSection() {
return nullptr;
}
+bool ObjectFileMachO::IsGOTSection(const lldb_private::Section &section) const {
+ assert(section.GetObjectFile() == this && "Wrong object file!");
+ SectionSP segment = section.GetParent();
+ if (!segment)
+ return false;
+
+ const bool is_data_const_got =
+ segment->GetName() == "__DATA_CONST" && section.GetName() == "__got";
+ const bool is_auth_const_ptr =
+ segment->GetName() == "__AUTH_CONST" &&
+ (section.GetName() == "__auth_got" || section.GetName() == "__auth_ptr");
+ return is_data_const_got || is_auth_const_ptr;
+}
+
bool ObjectFileMachO::SectionIsLoadable(const Section *section) {
if (!section)
return false;
@@ -6674,12 +6712,12 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
for (auto lc_note : lc_notes) {
offset_t payload_offset = std::get<0>(lc_note);
// Read the struct all_image_infos_header.
- uint32_t version = m_data.GetU32(&payload_offset);
+ uint32_t version = m_data_nsp->GetU32(&payload_offset);
if (version != 1) {
return image_infos;
}
- uint32_t imgcount = m_data.GetU32(&payload_offset);
- uint64_t entries_fileoff = m_data.GetU64(&payload_offset);
+ uint32_t imgcount = m_data_nsp->GetU32(&payload_offset);
+ uint64_t entries_fileoff = m_data_nsp->GetU64(&payload_offset);
// 'entries_size' is not used, nor is the 'unused' entry.
// offset += 4; // uint32_t entries_size;
// offset += 4; // uint32_t unused;
@@ -6689,17 +6727,18 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
payload_offset = entries_fileoff;
for (uint32_t i = 0; i < imgcount; i++) {
// Read the struct image_entry.
- offset_t filepath_offset = m_data.GetU64(&payload_offset);
+ offset_t filepath_offset = m_data_nsp->GetU64(&payload_offset);
uuid_t uuid;
- memcpy(&uuid, m_data.GetData(&payload_offset, sizeof(uuid_t)),
+ memcpy(&uuid, m_data_nsp->GetData(&payload_offset, sizeof(uuid_t)),
sizeof(uuid_t));
- uint64_t load_address = m_data.GetU64(&payload_offset);
- offset_t seg_addrs_offset = m_data.GetU64(&payload_offset);
- uint32_t segment_count = m_data.GetU32(&payload_offset);
- uint32_t currently_executing = m_data.GetU32(&payload_offset);
+ uint64_t load_address = m_data_nsp->GetU64(&payload_offset);
+ offset_t seg_addrs_offset = m_data_nsp->GetU64(&payload_offset);
+ uint32_t segment_count = m_data_nsp->GetU32(&payload_offset);
+ uint32_t currently_executing = m_data_nsp->GetU32(&payload_offset);
MachOCorefileImageEntry image_entry;
- image_entry.filename = (const char *)m_data.GetCStr(&filepath_offset);
+ image_entry.filename =
+ (const char *)m_data_nsp->GetCStr(&filepath_offset);
image_entry.uuid = UUID(uuid, sizeof(uuid_t));
image_entry.load_address = load_address;
image_entry.currently_executing = currently_executing;
@@ -6707,10 +6746,10 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
offset_t seg_vmaddrs_offset = seg_addrs_offset;
for (uint32_t j = 0; j < segment_count; j++) {
char segname[17];
- m_data.CopyData(seg_vmaddrs_offset, 16, segname);
+ m_data_nsp->CopyData(seg_vmaddrs_offset, 16, segname);
segname[16] = '\0';
seg_vmaddrs_offset += 16;
- uint64_t vmaddr = m_data.GetU64(&seg_vmaddrs_offset);
+ uint64_t vmaddr = m_data_nsp->GetU64(&seg_vmaddrs_offset);
seg_vmaddrs_offset += 8; /* unused */
std::tuple<ConstString, addr_t> new_seg{ConstString(segname), vmaddr};
@@ -6729,14 +6768,14 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
lc_notes = FindLC_NOTEByName("load binary");
for (auto lc_note : lc_notes) {
offset_t payload_offset = std::get<0>(lc_note);
- uint32_t version = m_data.GetU32(&payload_offset);
+ uint32_t version = m_data_nsp->GetU32(&payload_offset);
if (version == 1) {
uuid_t uuid;
- memcpy(&uuid, m_data.GetData(&payload_offset, sizeof(uuid_t)),
+ memcpy(&uuid, m_data_nsp->GetData(&payload_offset, sizeof(uuid_t)),
sizeof(uuid_t));
- uint64_t load_address = m_data.GetU64(&payload_offset);
- uint64_t slide = m_data.GetU64(&payload_offset);
- std::string filename = m_data.GetCStr(&payload_offset);
+ uint64_t load_address = m_data_nsp->GetU64(&payload_offset);
+ uint64_t slide = m_data_nsp->GetU64(&payload_offset);
+ std::string filename = m_data_nsp->GetCStr(&payload_offset);
MachOCorefileImageEntry image_entry;
image_entry.filename = filename;
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
index 25643aa..5456f03 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -162,6 +162,8 @@ public:
lldb_private::Section *GetMachHeaderSection();
+ bool IsGOTSection(const lldb_private::Section &section) const override;
+
// PluginInterface protocol
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
index 4984445..f25ed51 100644
--- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
@@ -396,7 +396,7 @@ bool ObjectFilePECOFF::CreateBinary() {
Log *log = GetLog(LLDBLog::Object);
auto binary = llvm::object::createBinary(llvm::MemoryBufferRef(
- toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()));
+ toStringRef(m_data_nsp->GetData()), m_file.GetFilename().GetStringRef()));
if (!binary) {
LLDB_LOG_ERROR(log, binary.takeError(),
"Failed to create binary for file ({1}): {0}", m_file);
@@ -442,20 +442,20 @@ bool ObjectFilePECOFF::ParseHeader() {
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
m_sect_headers.clear();
- m_data.SetByteOrder(eByteOrderLittle);
+ m_data_nsp->SetByteOrder(eByteOrderLittle);
lldb::offset_t offset = 0;
- if (ParseDOSHeader(m_data, m_dos_header)) {
+ if (ParseDOSHeader(*m_data_nsp.get(), m_dos_header)) {
offset = m_dos_header.e_lfanew;
- uint32_t pe_signature = m_data.GetU32(&offset);
+ uint32_t pe_signature = m_data_nsp->GetU32(&offset);
if (pe_signature != IMAGE_NT_SIGNATURE)
return false;
- if (ParseCOFFHeader(m_data, &offset, m_coff_header)) {
+ if (ParseCOFFHeader(*m_data_nsp.get(), &offset, m_coff_header)) {
if (m_coff_header.hdrsize > 0)
ParseCOFFOptionalHeader(&offset);
ParseSectionHeaders(offset);
}
- m_data.SetAddressByteSize(GetAddressByteSize());
+ m_data_nsp->SetAddressByteSize(GetAddressByteSize());
return true;
}
}
@@ -602,57 +602,63 @@ bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) {
const lldb::offset_t end_offset = *offset_ptr + m_coff_header.hdrsize;
if (*offset_ptr < end_offset) {
success = true;
- m_coff_header_opt.magic = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_linker_version = m_data.GetU8(offset_ptr);
- m_coff_header_opt.minor_linker_version = m_data.GetU8(offset_ptr);
- m_coff_header_opt.code_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.data_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.bss_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.entry = m_data.GetU32(offset_ptr);
- m_coff_header_opt.code_offset = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.magic = m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.major_linker_version = m_data_nsp->GetU8(offset_ptr);
+ m_coff_header_opt.minor_linker_version = m_data_nsp->GetU8(offset_ptr);
+ m_coff_header_opt.code_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.data_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.bss_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.entry = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.code_offset = m_data_nsp->GetU32(offset_ptr);
const uint32_t addr_byte_size = GetAddressByteSize();
if (*offset_ptr < end_offset) {
if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) {
// PE32 only
- m_coff_header_opt.data_offset = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.data_offset = m_data_nsp->GetU32(offset_ptr);
} else
m_coff_header_opt.data_offset = 0;
if (*offset_ptr < end_offset) {
m_coff_header_opt.image_base =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.sect_alignment = m_data.GetU32(offset_ptr);
- m_coff_header_opt.file_alignment = m_data.GetU32(offset_ptr);
- m_coff_header_opt.major_os_system_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_os_system_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_image_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_image_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_subsystem_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_subsystem_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.reserved1 = m_data.GetU32(offset_ptr);
- m_coff_header_opt.image_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.header_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.checksum = m_data.GetU32(offset_ptr);
- m_coff_header_opt.subsystem = m_data.GetU16(offset_ptr);
- m_coff_header_opt.dll_flags = m_data.GetU16(offset_ptr);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
+ m_coff_header_opt.sect_alignment = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.file_alignment = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.major_os_system_version =
+ m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.minor_os_system_version =
+ m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.major_image_version = m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.minor_image_version = m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.major_subsystem_version =
+ m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.minor_subsystem_version =
+ m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.reserved1 = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.image_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.header_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.checksum = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.subsystem = m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.dll_flags = m_data_nsp->GetU16(offset_ptr);
m_coff_header_opt.stack_reserve_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
m_coff_header_opt.stack_commit_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
m_coff_header_opt.heap_reserve_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
m_coff_header_opt.heap_commit_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.loader_flags = m_data.GetU32(offset_ptr);
- uint32_t num_data_dir_entries = m_data.GetU32(offset_ptr);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
+ m_coff_header_opt.loader_flags = m_data_nsp->GetU32(offset_ptr);
+ uint32_t num_data_dir_entries = m_data_nsp->GetU32(offset_ptr);
m_coff_header_opt.data_dirs.clear();
m_coff_header_opt.data_dirs.resize(num_data_dir_entries);
uint32_t i;
for (i = 0; i < num_data_dir_entries; i++) {
- m_coff_header_opt.data_dirs[i].vmaddr = m_data.GetU32(offset_ptr);
- m_coff_header_opt.data_dirs[i].vmsize = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.data_dirs[i].vmaddr =
+ m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.data_dirs[i].vmsize =
+ m_data_nsp->GetU32(offset_ptr);
}
m_image_base = m_coff_header_opt.image_base;
@@ -684,8 +690,8 @@ DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) {
if (!size)
return {};
- if (m_data.ValidOffsetForDataOfSize(offset, size))
- return DataExtractor(m_data, offset, size);
+ if (m_data_nsp->ValidOffsetForDataOfSize(offset, size))
+ return DataExtractor(*m_data_nsp.get(), offset, size);
ProcessSP process_sp(m_process_wp.lock());
DataExtractor data;
@@ -759,7 +765,7 @@ llvm::StringRef ObjectFilePECOFF::GetSectionName(const section_header_t &sect) {
return "";
lldb::offset_t string_file_offset =
m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff;
- if (const char *name = m_data.GetCStr(&string_file_offset))
+ if (const char *name = m_data_nsp->GetCStr(&string_file_offset))
return name;
return "";
}
@@ -985,7 +991,7 @@ SectionType ObjectFilePECOFF::GetSectionType(llvm::StringRef sect_name,
.Case(".stabstr", eSectionTypeDataCString)
.Case(".reloc", eSectionTypeOther)
// .eh_frame can be truncated to 8 chars.
- .Cases(".eh_frame", ".eh_fram", eSectionTypeEHFrame)
+ .Cases({".eh_frame", ".eh_fram"}, eSectionTypeEHFrame)
.Case(".gosymtab", eSectionTypeGoSymtab)
.Case(".lldbsummaries", lldb::eSectionTypeLLDBTypeSummaries)
.Case(".lldbformatters", lldb::eSectionTypeLLDBFormatters)
diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
index d2c46ed..bfe1556 100644
--- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
@@ -94,7 +94,7 @@ bool ObjectFileXCOFF::CreateBinary() {
Log *log = GetLog(LLDBLog::Object);
- auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data.GetData()),
+ auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data_nsp->GetData()),
m_file.GetFilename().GetStringRef());
llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer());
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index 492b441..0bedb5e 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -287,7 +287,7 @@ ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP data_sp,
offset_t offset, offset_t length)
: ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
m_arch("wasm32-unknown-unknown-wasm") {
- m_data.SetAddressByteSize(4);
+ m_data_nsp->SetAddressByteSize(4);
}
ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
@@ -719,11 +719,11 @@ DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
DataBufferSP buffer_sp(data_up.release());
data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
}
- } else if (offset < m_data.GetByteSize()) {
- size =
- std::min(static_cast<uint64_t>(size), m_data.GetByteSize() - offset);
- return DataExtractor(m_data.GetDataStart() + offset, size, GetByteOrder(),
- GetAddressByteSize());
+ } else if (offset < m_data_nsp->GetByteSize()) {
+ size = std::min(static_cast<uint64_t>(size),
+ m_data_nsp->GetByteSize() - offset);
+ return DataExtractor(m_data_nsp->GetDataStart() + offset, size,
+ GetByteOrder(), GetAddressByteSize());
}
}
data.SetByteOrder(GetByteOrder());
diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
index 57d88f6..22b9711 100644
--- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
+++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
@@ -15,6 +15,8 @@
#include "lldb/Utility/UriParser.h"
#include "lldb/ValueObject/ValueObject.h"
+#include "llvm/ADT/DenseMap.h"
+
#include "AdbClient.h"
#include "PlatformAndroid.h"
#include "PlatformAndroidRemoteGDBServer.h"
@@ -479,136 +481,90 @@ std::string PlatformAndroid::GetRunAs() {
return run_as.str();
}
-// Helper function to populate process status information from
-// /proc/[pid]/status
-void PlatformAndroid::PopulateProcessStatusInfo(
- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
- // Read /proc/[pid]/status to get parent PID, UIDs, and GIDs
- Status error;
- AdbClientUP status_adb = GetAdbClient(error);
- if (error.Fail())
- return;
-
- std::string status_output;
- StreamString status_cmd;
- status_cmd.Printf(
- "cat /proc/%llu/status 2>/dev/null | grep -E '^(PPid|Uid|Gid):'",
- static_cast<unsigned long long>(pid));
- Status status_error =
- status_adb->Shell(status_cmd.GetData(), seconds(5), &status_output);
+static bool NeedsCmdlineSupplement(const ProcessInstanceInfo &proc_info) {
+ llvm::StringRef name =
+ proc_info.GetExecutableFile().GetFilename().GetStringRef();
+ return name.contains("app_process") || name.contains("zygote");
+}
- if (status_error.Fail() || status_output.empty())
+// Fetch /proc/PID/cmdline for processes to get actual package names.
+// Android apps often show as "zygote" or "app_process" without this.
+static void SupplementWithCmdlineInfo(ProcessInstanceInfoList &proc_infos,
+ AdbClient *adb) {
+ if (proc_infos.empty())
return;
- llvm::SmallVector<llvm::StringRef, 16> lines;
- llvm::StringRef(status_output).split(lines, '\n');
-
- for (llvm::StringRef line : lines) {
- line = line.trim();
- if (line.starts_with("PPid:")) {
- llvm::StringRef ppid_str = line.substr(5).trim();
- lldb::pid_t ppid;
- if (llvm::to_integer(ppid_str, ppid))
- process_info.SetParentProcessID(ppid);
- } else if (line.starts_with("Uid:")) {
- llvm::SmallVector<llvm::StringRef, 4> uid_parts;
- line.substr(4).trim().split(uid_parts, '\t', -1, false);
- if (uid_parts.size() >= 2) {
- uint32_t uid, euid;
- if (llvm::to_integer(uid_parts[0].trim(), uid))
- process_info.SetUserID(uid);
- if (llvm::to_integer(uid_parts[1].trim(), euid))
- process_info.SetEffectiveUserID(euid);
- }
- } else if (line.starts_with("Gid:")) {
- llvm::SmallVector<llvm::StringRef, 4> gid_parts;
- line.substr(4).trim().split(gid_parts, '\t', -1, false);
- if (gid_parts.size() >= 2) {
- uint32_t gid, egid;
- if (llvm::to_integer(gid_parts[0].trim(), gid))
- process_info.SetGroupID(gid);
- if (llvm::to_integer(gid_parts[1].trim(), egid))
- process_info.SetEffectiveGroupID(egid);
- }
+ llvm::DenseMap<lldb::pid_t, ProcessInstanceInfo *> pid_map;
+ std::string pid_list;
+ for (auto &proc_info : proc_infos) {
+ if (NeedsCmdlineSupplement(proc_info)) {
+ lldb::pid_t pid = proc_info.GetProcessID();
+ pid_map[pid] = &proc_info;
+ if (!pid_list.empty())
+ pid_list += " ";
+ pid_list += std::to_string(pid);
}
}
-}
-// Helper function to populate command line arguments from /proc/[pid]/cmdline
-void PlatformAndroid::PopulateProcessCommandLine(
- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
- // Read /proc/[pid]/cmdline to get command line arguments
- Status error;
- AdbClientUP cmdline_adb = GetAdbClient(error);
- if (error.Fail())
+ if (pid_list.empty())
return;
+ Log *log = GetLog(LLDBLog::Platform);
+
+ // Use xargs -P to parallelize cmdline fetching (up to 8 concurrent reads)
+ StreamString cmd;
+ cmd.Printf(
+ "echo '%s' | xargs -n 1 -P 8 sh -c "
+ "'echo \"$1:$(cat /proc/$1/cmdline 2>/dev/null | tr \"\\0\" \" \")\"' sh",
+ pid_list.c_str());
+
std::string cmdline_output;
- StreamString cmdline_cmd;
- cmdline_cmd.Printf("cat /proc/%llu/cmdline 2>/dev/null | tr '\\000' ' '",
- static_cast<unsigned long long>(pid));
- Status cmdline_error =
- cmdline_adb->Shell(cmdline_cmd.GetData(), seconds(5), &cmdline_output);
+ Status error = adb->Shell(cmd.GetData(), seconds(5), &cmdline_output);
- if (cmdline_error.Fail() || cmdline_output.empty())
+ if (error.Fail() || cmdline_output.empty())
return;
- cmdline_output = llvm::StringRef(cmdline_output).trim().str();
- if (cmdline_output.empty())
- return;
+ llvm::SmallVector<llvm::StringRef, 256> lines;
+ llvm::StringRef(cmdline_output).split(lines, '\n', -1, false);
- llvm::SmallVector<llvm::StringRef, 16> args;
- llvm::StringRef(cmdline_output).split(args, ' ', -1, false);
- if (args.empty())
- return;
+ for (llvm::StringRef line : lines) {
+ line = line.trim();
+ auto [pid_str, cmdline] = line.split(':');
+ if (pid_str.empty() || cmdline.empty())
+ continue;
- process_info.SetArg0(args[0]);
- Args process_args;
- for (size_t i = 1; i < args.size(); i++) {
- if (!args[i].empty())
- process_args.AppendArgument(args[i]);
- }
- process_info.SetArguments(process_args, false);
-}
+ cmdline = cmdline.trim();
-// Helper function to populate architecture from /proc/[pid]/exe
-void PlatformAndroid::PopulateProcessArchitecture(
- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
- // Read /proc/[pid]/exe to get executable path for architecture detection
- Status error;
- AdbClientUP exe_adb = GetAdbClient(error);
- if (error.Fail())
- return;
+ lldb::pid_t pid;
+ if (!llvm::to_integer(pid_str, pid) || cmdline.empty())
+ continue;
- std::string exe_output;
- StreamString exe_cmd;
- exe_cmd.Printf("readlink /proc/%llu/exe 2>/dev/null",
- static_cast<unsigned long long>(pid));
- Status exe_error = exe_adb->Shell(exe_cmd.GetData(), seconds(5), &exe_output);
+ auto it = pid_map.find(pid);
+ if (it == pid_map.end())
+ continue;
- if (exe_error.Fail() || exe_output.empty())
- return;
+ ProcessInstanceInfo *proc_info = it->second;
+ llvm::SmallVector<llvm::StringRef, 16> args;
+ cmdline.split(args, ' ', -1, false);
- exe_output = llvm::StringRef(exe_output).trim().str();
-
- // Determine architecture from exe path
- ArchSpec arch;
- if (exe_output.find("64") != std::string::npos ||
- exe_output.find("arm64") != std::string::npos ||
- exe_output.find("aarch64") != std::string::npos) {
- arch.SetTriple("aarch64-unknown-linux-android");
- } else if (exe_output.find("x86_64") != std::string::npos) {
- arch.SetTriple("x86_64-unknown-linux-android");
- } else if (exe_output.find("x86") != std::string::npos ||
- exe_output.find("i686") != std::string::npos) {
- arch.SetTriple("i686-unknown-linux-android");
- } else {
- // Default to armv7 for 32-bit ARM (most common on Android)
- arch.SetTriple("armv7-unknown-linux-android");
- }
+ if (!args.empty()) {
+ proc_info->GetExecutableFile().SetFile(args[0], FileSpec::Style::posix);
+
+ if (args.size() > 1) {
+ Args process_args;
+ for (size_t i = 1; i < args.size(); ++i) {
+ if (!args[i].empty())
+ process_args.AppendArgument(args[i]);
+ }
+ proc_info->SetArguments(process_args, false);
+ }
- if (arch.IsValid())
- process_info.SetArchitecture(arch);
+ LLDB_LOGF(log,
+ "PlatformAndroid::%s supplemented PID %llu with cmdline: %s",
+ __FUNCTION__, static_cast<unsigned long long>(pid),
+ cmdline.str().c_str());
+ }
+ }
}
uint32_t
@@ -616,109 +572,39 @@ PlatformAndroid::FindProcesses(const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &proc_infos) {
proc_infos.clear();
- // When LLDB is running natively on an Android device (IsHost() == true),
- // use the parent class's standard Linux /proc enumeration. IsHost() is only
- // true when compiled for Android (#if defined(__ANDROID__)), so calling
- // PlatformLinux methods is safe (Android is Linux-based).
if (IsHost())
return PlatformLinux::FindProcesses(match_info, proc_infos);
- // Remote Android platform: implement process name lookup using 'pidof' over
- // adb.
-
- // LLDB stores the search name in GetExecutableFile() (even though it's
- // actually a process name like "com.android.chrome" rather than an
- // executable path). If no search name is provided, we can't use
- // 'pidof', so return early with no results.
- const ProcessInstanceInfo &match_process_info = match_info.GetProcessInfo();
- if (!match_process_info.GetExecutableFile() ||
- match_info.GetNameMatchType() == NameMatch::Ignore) {
- return 0;
- }
-
- // Extract the process name to search for (typically an Android package name
- // like "com.example.app" or binary name like "app_process64")
- std::string process_name = match_process_info.GetExecutableFile().GetPath();
- if (process_name.empty())
- return 0;
-
- // Use adb to find the process by name
- Status error;
- AdbClientUP adb(GetAdbClient(error));
- if (error.Fail()) {
- Log *log = GetLog(LLDBLog::Platform);
- LLDB_LOGF(log, "PlatformAndroid::%s failed to get ADB client: %s",
- __FUNCTION__, error.AsCString());
- return 0;
- }
-
- // Use 'pidof' command to get PIDs for the process name.
- // Quote the process name to handle special characters (spaces, etc.)
- std::string pidof_output;
- StreamString command;
- command.Printf("pidof '%s'", process_name.c_str());
- error = adb->Shell(command.GetData(), seconds(5), &pidof_output);
-
- if (error.Fail()) {
- Log *log = GetLog(LLDBLog::Platform);
- LLDB_LOG(log, "PlatformAndroid::{} 'pidof {}' failed: {}", __FUNCTION__,
- process_name.c_str(), error.AsCString());
- return 0;
- }
-
- // Parse PIDs from pidof output.
- // Note: pidof can return multiple PIDs (space-separated) if multiple
- // instances of the same executable are running.
- pidof_output = llvm::StringRef(pidof_output).trim().str();
- if (pidof_output.empty()) {
- Log *log = GetLog(LLDBLog::Platform);
- LLDB_LOGF(log, "PlatformAndroid::%s no process found with name '%s'",
- __FUNCTION__, process_name.c_str());
+ if (!m_remote_platform_sp)
return 0;
- }
-
- // Split the output by whitespace to handle multiple PIDs
- llvm::SmallVector<llvm::StringRef, 8> pid_strings;
- llvm::StringRef(pidof_output).split(pid_strings, ' ', -1, false);
-
- Log *log = GetLog(LLDBLog::Platform);
-
- // Process each PID and gather information
- uint32_t num_matches = 0;
- for (llvm::StringRef pid_str : pid_strings) {
- pid_str = pid_str.trim();
- if (pid_str.empty())
- continue;
-
- lldb::pid_t pid;
- if (!llvm::to_integer(pid_str, pid)) {
- LLDB_LOGF(log, "PlatformAndroid::%s failed to parse PID from: '%s'",
- __FUNCTION__, pid_str.str().c_str());
- continue;
- }
-
- ProcessInstanceInfo process_info;
- process_info.SetProcessID(pid);
- process_info.GetExecutableFile().SetFile(process_name,
- FileSpec::Style::posix);
-
- // Populate additional process information
- PopulateProcessStatusInfo(pid, process_info);
- PopulateProcessCommandLine(pid, process_info);
- PopulateProcessArchitecture(pid, process_info);
-
- // Check if this process matches the criteria
- if (match_info.Matches(process_info)) {
- proc_infos.push_back(process_info);
- num_matches++;
- LLDB_LOGF(log, "PlatformAndroid::%s found process '%s' with PID %llu",
- __FUNCTION__, process_name.c_str(),
- static_cast<unsigned long long>(pid));
+ // Android-specific process name handling:
+ // Apps spawned from zygote initially appear as "app_process" or "zygote"
+ // in the process list, but their actual package names (e.g.,
+ // "com.example.app") are only available in /proc/PID/cmdline. To support
+ // name-based matching, we must first fetch cmdline info for all processes,
+ // then apply the original name filter.
+ ProcessInstanceInfoMatch broad_match_info = match_info;
+ broad_match_info.SetNameMatchType(NameMatch::Ignore);
+
+ ProcessInstanceInfoList all_procs;
+ uint32_t count =
+ m_remote_platform_sp->FindProcesses(broad_match_info, all_procs);
+
+ if (count > 0) {
+ Status error;
+ AdbClientUP adb(GetAdbClient(error));
+ if (error.Success())
+ SupplementWithCmdlineInfo(all_procs, adb.get());
+
+ // Apply the original name matching against supplemented process info.
+ for (auto &proc_info : all_procs) {
+ if (match_info.Matches(proc_info))
+ proc_infos.push_back(proc_info);
}
}
- return num_matches;
+ return proc_infos.size();
}
std::unique_ptr<AdbSyncService> PlatformAndroid::GetSyncService(Status &error) {
diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h
index e771c6a..c6a412b 100644
--- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h
+++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h
@@ -60,7 +60,7 @@ public:
uint32_t GetDefaultMemoryCacheLineSize() override;
uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info,
- ProcessInstanceInfoList &proc_infos) override;
+ ProcessInstanceInfoList &process_infos) override;
protected:
const char *GetCacheHostname() override;
@@ -86,17 +86,8 @@ public:
protected:
virtual std::unique_ptr<AdbSyncService> GetSyncService(Status &error);
-private:
std::string m_device_id;
uint32_t m_sdk_version;
-
- // Helper functions for process information gathering
- void PopulateProcessStatusInfo(lldb::pid_t pid,
- ProcessInstanceInfo &process_info);
- void PopulateProcessCommandLine(lldb::pid_t pid,
- ProcessInstanceInfo &process_info);
- void PopulateProcessArchitecture(lldb::pid_t pid,
- ProcessInstanceInfo &process_info);
};
} // namespace platform_android
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
index 4cfb0a8..47111c9 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
@@ -90,7 +90,7 @@ void PlatformAppleSimulator::GetStatus(Stream &strm) {
if (!sdk.empty())
strm << " SDK Path: \"" << sdk << "\"\n";
else
- strm << " SDK Path: error: unable to locate SDK\n";
+ strm << " SDK Path: <unable to locate SDK>\n";
#if defined(__APPLE__)
// This will get called by subclasses, so just output status on the current
@@ -420,7 +420,6 @@ Status PlatformAppleSimulator::GetSymbolFile(const FileSpec &platform_file,
Status PlatformAppleSimulator::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
// For iOS/tvOS/watchOS, the SDK files are all cached locally on the
// host system. So first we ask for the file in the cached SDK, then
@@ -432,12 +431,10 @@ Status PlatformAppleSimulator::GetSharedModule(
error = GetSymbolFile(platform_file, module_spec.GetUUIDPtr(),
platform_module_spec.GetFileSpec());
if (error.Success()) {
- error = ResolveExecutable(platform_module_spec, module_sp,
- module_search_paths_ptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
} else {
const bool always_create = false;
- error = ModuleList::GetSharedModule(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ error = ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
did_create_ptr, always_create);
}
if (module_sp)
@@ -660,4 +657,3 @@ void PlatformAppleSimulator::Terminate() {
PlatformDarwin::Terminate();
}
}
-
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
index 7fcf2c5..77d2a3b 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
@@ -89,7 +89,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index 5aad447..bfbd85e 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -56,7 +56,7 @@ using namespace lldb;
using namespace lldb_private;
#define OPTTABLE_STR_TABLE_CODE
-#include "clang/Driver/Options.inc"
+#include "clang/Options/Options.inc"
#undef OPTTABLE_STR_TABLE_CODE
static Status ExceptionMaskValidator(const char *string, void *unused) {
@@ -331,7 +331,6 @@ Status PlatformDarwin::ResolveSymbolFile(Target &target,
Status PlatformDarwin::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
Status error;
module_sp.reset();
@@ -341,19 +340,22 @@ Status PlatformDarwin::GetSharedModule(
// module first.
if (m_remote_platform_sp) {
error = m_remote_platform_sp->GetSharedModule(
- module_spec, process, module_sp, module_search_paths_ptr, old_modules,
- did_create_ptr);
+ module_spec, process, module_sp, old_modules, did_create_ptr);
}
}
if (!module_sp) {
// Fall back to the local platform and find the file locally
error = Platform::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
const FileSpec &platform_file = module_spec.GetFileSpec();
- if (!module_sp && module_search_paths_ptr && platform_file) {
+ // Get module search paths from the target if available.
+ TargetSP target_sp = module_spec.GetTargetSP();
+ FileSpecList module_search_paths;
+ if (target_sp)
+ module_search_paths = target_sp->GetExecutableSearchPaths();
+ if (!module_sp && !module_search_paths.IsEmpty() && platform_file) {
// We can try to pull off part of the file path up to the bundle
// directory level and try any module search paths...
FileSpec bundle_directory;
@@ -362,9 +364,9 @@ Status PlatformDarwin::GetSharedModule(
ModuleSpec new_module_spec(module_spec);
new_module_spec.GetFileSpec() = bundle_directory;
if (Host::ResolveExecutableInBundle(new_module_spec.GetFileSpec())) {
- Status new_error(Platform::GetSharedModule(
- new_module_spec, process, module_sp, nullptr, old_modules,
- did_create_ptr));
+ Status new_error(Platform::GetSharedModule(new_module_spec, process,
+ module_sp, old_modules,
+ did_create_ptr));
if (module_sp)
return new_error;
@@ -376,10 +378,10 @@ Status PlatformDarwin::GetSharedModule(
const size_t bundle_directory_len =
bundle_directory.GetPath(bundle_dir, sizeof(bundle_dir));
char new_path[PATH_MAX];
- size_t num_module_search_paths = module_search_paths_ptr->GetSize();
+ size_t num_module_search_paths = module_search_paths.GetSize();
for (size_t i = 0; i < num_module_search_paths; ++i) {
const size_t search_path_len =
- module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath(
+ module_search_paths.GetFileSpecAtIndex(i).GetPath(
new_path, sizeof(new_path));
if (search_path_len < sizeof(new_path)) {
snprintf(new_path + search_path_len,
@@ -390,7 +392,7 @@ Status PlatformDarwin::GetSharedModule(
ModuleSpec new_module_spec(module_spec);
new_module_spec.GetFileSpec() = new_file_spec;
Status new_error(Platform::GetSharedModule(
- new_module_spec, process, module_sp, nullptr, old_modules,
+ new_module_spec, process, module_sp, old_modules,
did_create_ptr));
if (module_sp) {
@@ -1122,7 +1124,7 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(
#define OPTION(PREFIX_OFFSET, NAME_OFFSET, VAR, ...) \
llvm::StringRef opt_##VAR = OptionStrTable[NAME_OFFSET]; \
(void)opt_##VAR;
-#include "clang/Driver/Options.inc"
+#include "clang/Options/Options.inc"
#undef OPTION
minimum_version_option << '-';
switch (sdk_type) {
@@ -1303,12 +1305,15 @@ PlatformDarwin::LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) {
lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
const FileSpec &platform_file = module_spec.GetFileSpec();
- // See if the file is present in any of the module_search_paths_ptr
+ TargetSP target_sp = module_spec.GetTargetSP();
+ FileSpecList module_search_paths;
+ if (target_sp)
+ module_search_paths = target_sp->GetExecutableSearchPaths();
+ // See if the file is present in any of the module_search_paths
// directories.
- if (!module_sp && module_search_paths_ptr && platform_file) {
+ if (!module_sp && !module_search_paths.IsEmpty() && platform_file) {
// create a vector of all the file / directory names in platform_file e.g.
// this might be
// /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation
@@ -1322,21 +1327,21 @@ lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths(
std::reverse(path_parts.begin(), path_parts.end());
const size_t path_parts_size = path_parts.size();
- size_t num_module_search_paths = module_search_paths_ptr->GetSize();
+ size_t num_module_search_paths = module_search_paths.GetSize();
for (size_t i = 0; i < num_module_search_paths; ++i) {
Log *log_verbose = GetLog(LLDBLog::Host);
LLDB_LOGF(
log_verbose,
"PlatformRemoteDarwinDevice::GetSharedModule searching for binary in "
"search-path %s",
- module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath().c_str());
+ module_search_paths.GetFileSpecAtIndex(i).GetPath().c_str());
// Create a new FileSpec with this module_search_paths_ptr plus just the
// filename ("UIFoundation"), then the parent dir plus filename
// ("UIFoundation.framework/UIFoundation") etc - up to four names (to
// handle "Foo.framework/Contents/MacOS/Foo")
for (size_t j = 0; j < 4 && j < path_parts_size - 1; ++j) {
- FileSpec path_to_try(module_search_paths_ptr->GetFileSpecAtIndex(i));
+ FileSpec path_to_try(module_search_paths.GetFileSpecAtIndex(i));
// Add the components backwards. For
// .../PrivateFrameworks/UIFoundation.framework/UIFoundation path_parts
@@ -1356,9 +1361,9 @@ lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths(
if (FileSystem::Instance().Exists(path_to_try)) {
ModuleSpec new_module_spec(module_spec);
new_module_spec.GetFileSpec() = path_to_try;
- Status new_error(
- Platform::GetSharedModule(new_module_spec, process, module_sp,
- nullptr, old_modules, did_create_ptr));
+ Status new_error(Platform::GetSharedModule(new_module_spec, process,
+ module_sp, old_modules,
+ did_create_ptr));
if (module_sp) {
module_sp->SetPlatformFileSpec(path_to_try);
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
index f8a62ce..82e69e3 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
@@ -73,7 +73,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
@@ -189,7 +188,7 @@ protected:
Status FindBundleBinaryInExecSearchPaths(
const ModuleSpec &module_spec, Process *process,
- lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP &module_sp,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr);
// The OSType where lldb is running.
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
index 68ef817..a72d94e 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
@@ -295,7 +295,6 @@ BringInRemoteFile(Platform *platform,
lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
- const lldb_private::FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
Log *log = GetLog(LLDBLog::Platform);
@@ -329,8 +328,7 @@ lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
image_info.data_sp);
err = ModuleList::GetSharedModule(shared_cache_spec, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
if (module_sp) {
LLDB_LOGF(log, "[%s] module %s was found in the in-memory shared cache",
(IsHost() ? "host" : "remote"),
@@ -348,8 +346,7 @@ lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
FileSystem::Instance().Resolve(device_support_spec);
if (FileSystem::Instance().Exists(device_support_spec)) {
ModuleSpec local_spec(device_support_spec, module_spec.GetUUID());
- err = ModuleList::GetSharedModule(local_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ err = ModuleList::GetSharedModule(local_spec, module_sp, old_modules,
did_create_ptr);
if (module_sp) {
LLDB_LOGF(log,
@@ -363,8 +360,7 @@ lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
}
}
- err = ModuleList::GetSharedModule(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ err = ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
did_create_ptr);
if (module_sp)
return err;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h
index e1eba08f..e0142ab 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h
@@ -26,7 +26,6 @@ public:
protected:
virtual Status GetSharedModuleWithLocalCache(
const ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr);
struct SDKDirectoryInfo {
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
index 07c5a52..04e87b9d 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
@@ -719,7 +719,6 @@ void PlatformDarwinKernel::UpdateKextandKernelsLocalScan() {
Status PlatformDarwinKernel::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
Status error;
module_sp.reset();
@@ -734,14 +733,12 @@ Status PlatformDarwinKernel::GetSharedModule(
// UUID search can get here with no name - and it may be a kernel.
if (kext_bundle_id == "mach_kernel" || kext_bundle_id.empty()) {
error = GetSharedModuleKernel(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
if (error.Success() && module_sp) {
return error;
}
} else {
- return GetSharedModuleKext(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
+ return GetSharedModuleKext(module_spec, process, module_sp, old_modules,
did_create_ptr);
}
}
@@ -749,13 +746,11 @@ Status PlatformDarwinKernel::GetSharedModule(
// Give the generic methods, including possibly calling into DebugSymbols
// framework on macOS systems, a chance.
return PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
}
Status PlatformDarwinKernel::GetSharedModuleKext(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
Status error;
module_sp.reset();
@@ -782,8 +777,7 @@ Status PlatformDarwinKernel::GetSharedModuleKext(
// Give the generic methods, including possibly calling into DebugSymbols
// framework on macOS systems, a chance.
error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
if (error.Success() && module_sp.get()) {
return error;
}
@@ -793,7 +787,6 @@ Status PlatformDarwinKernel::GetSharedModuleKext(
Status PlatformDarwinKernel::GetSharedModuleKernel(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
assert(module_sp.get() == nullptr);
UpdateKextandKernelsLocalScan();
@@ -848,8 +841,7 @@ Status PlatformDarwinKernel::GetSharedModuleKernel(
// Give the generic methods, including possibly calling into DebugSymbols
// framework on macOS systems, a chance.
return PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
}
std::vector<lldb_private::FileSpec>
@@ -888,8 +880,8 @@ Status PlatformDarwinKernel::ExamineKextForMatchingUUID(
ModuleSP module_sp(new Module(exe_spec));
if (module_sp && module_sp->GetObjectFile() &&
module_sp->MatchesModuleSpec(exe_spec)) {
- Status error = ModuleList::GetSharedModule(exe_spec, exe_module_sp,
- NULL, NULL, NULL);
+ Status error =
+ ModuleList::GetSharedModule(exe_spec, exe_module_sp, NULL, NULL);
if (exe_module_sp && exe_module_sp->GetObjectFile()) {
return error;
}
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h
index 9db9c00..b5cf701 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h
@@ -60,7 +60,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
@@ -142,14 +141,14 @@ protected:
Status GetSharedModuleKext(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr);
- Status GetSharedModuleKernel(
- const ModuleSpec &module_spec, Process *process,
- lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr,
- llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr);
+ Status
+ GetSharedModuleKernel(const ModuleSpec &module_spec, Process *process,
+ lldb::ModuleSP &module_sp,
+ llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
+ bool *did_create_ptr);
Status ExamineKextForMatchingUUID(const FileSpec &kext_bundle_path,
const UUID &uuid, const ArchSpec &arch,
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
index dad6dcd..e6ea75a 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
@@ -182,10 +182,8 @@ PlatformMacOSX::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
lldb_private::Status PlatformMacOSX::GetSharedModule(
const lldb_private::ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const lldb_private::FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
Status error = GetSharedModuleWithLocalCache(module_spec, module_sp,
- module_search_paths_ptr,
old_modules, did_create_ptr);
if (module_sp) {
@@ -199,9 +197,9 @@ lldb_private::Status PlatformMacOSX::GetSharedModule(
lldb::ModuleSP x86_64_module_sp;
llvm::SmallVector<lldb::ModuleSP, 1> old_x86_64_modules;
bool did_create = false;
- Status x86_64_error = GetSharedModuleWithLocalCache(
- module_spec_x86_64, x86_64_module_sp, module_search_paths_ptr,
- &old_x86_64_modules, &did_create);
+ Status x86_64_error =
+ GetSharedModuleWithLocalCache(module_spec_x86_64, x86_64_module_sp,
+ &old_x86_64_modules, &did_create);
if (x86_64_module_sp && x86_64_module_sp->GetObjectFile()) {
module_sp = x86_64_module_sp;
if (old_modules)
@@ -217,7 +215,6 @@ lldb_private::Status PlatformMacOSX::GetSharedModule(
if (!module_sp) {
error = FindBundleBinaryInExecSearchPaths(module_spec, process, module_sp,
- module_search_paths_ptr,
old_modules, did_create_ptr);
}
return error;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
index be84485..9555b16 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
@@ -48,7 +48,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
index b83d07b..53fab93 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
@@ -53,7 +53,7 @@ void PlatformRemoteDarwinDevice::GetStatus(Stream &strm) {
if (sdk_directory)
strm.Printf(" SDK Path: \"%s\"\n", sdk_directory);
else
- strm.PutCString(" SDK Path: error: unable to locate SDK\n");
+ strm.PutCString(" SDK Path: <unable to locate SDK>\n");
const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
for (uint32_t i = 0; i < num_sdk_infos; ++i) {
@@ -158,7 +158,6 @@ Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file,
Status PlatformRemoteDarwinDevice::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
// For iOS, the SDK files are all cached locally on the host system. So first
// we ask for the file in the cached SDK, then we attempt to get a shared
@@ -185,7 +184,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
if (GetFileInSDK(platform_file_path, connected_sdk_idx,
platform_module_spec.GetFileSpec())) {
module_sp.reset();
- error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
if (module_sp) {
m_last_module_sdk_idx = connected_sdk_idx;
error.Clear();
@@ -202,7 +201,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
if (GetFileInSDK(platform_file_path, m_last_module_sdk_idx,
platform_module_spec.GetFileSpec())) {
module_sp.reset();
- error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
if (module_sp) {
error.Clear();
return error;
@@ -224,7 +223,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
if (GetFileInSDK(platform_file_path, current_sdk_idx,
platform_module_spec.GetFileSpec())) {
module_sp.reset();
- error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
if (module_sp) {
m_last_module_sdk_idx = current_sdk_idx;
error.Clear();
@@ -245,7 +244,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
platform_module_spec.GetFileSpec())) {
// printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
- error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
if (module_sp) {
// Remember the index of the last SDK that we found a file in in case
// the wrong SDK was selected.
@@ -261,8 +260,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
// This may not be an SDK-related module. Try whether we can bring in the
// thing to our local cache.
- error = GetSharedModuleWithLocalCache(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ error = GetSharedModuleWithLocalCache(module_spec, module_sp, old_modules,
did_create_ptr);
if (error.Success())
return error;
@@ -271,15 +269,13 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
// directories.
if (!module_sp)
error = PlatformDarwin::FindBundleBinaryInExecSearchPaths(
- module_spec, process, module_sp, module_search_paths_ptr, old_modules,
- did_create_ptr);
+ module_spec, process, module_sp, old_modules, did_create_ptr);
if (error.Success())
return error;
const bool always_create = false;
- error = ModuleList::GetSharedModule(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ error = ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
did_create_ptr, always_create);
if (module_sp)
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
index 557f487..4abd74e 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
@@ -47,7 +47,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index 0fecefe..4cc39f9 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -79,8 +79,10 @@ namespace lldb_private {
ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
- const FileSpec *,
+ const FileSpec *crash_file_path,
bool can_connect) {
+ if (crash_file_path)
+ return nullptr; // Cannot create a Windows process from a crash_file.
return ProcessSP(new ProcessWindows(target_sp, listener_sp));
}
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index b7029fb..f8e33ea 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -84,8 +84,9 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
// For now we are just making sure the file exists for a given module
if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) {
ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture());
+ core_module_spec.SetTarget(target_sp);
Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
- nullptr, nullptr, nullptr));
+ nullptr, nullptr));
if (m_core_module_sp) {
ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 3c4d9a1..cde68b5 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -210,11 +210,9 @@ void ProcessGDBRemote::Terminate() {
lldb::ProcessSP ProcessGDBRemote::CreateInstance(
lldb::TargetSP target_sp, ListenerSP listener_sp,
const FileSpec *crash_file_path, bool can_connect) {
- lldb::ProcessSP process_sp;
- if (crash_file_path == nullptr)
- process_sp = std::shared_ptr<ProcessGDBRemote>(
- new ProcessGDBRemote(target_sp, listener_sp));
- return process_sp;
+ if (crash_file_path)
+ return nullptr; // Cannot create a GDBRemote process from a crash_file.
+ return lldb::ProcessSP(new ProcessGDBRemote(target_sp, listener_sp));
}
void ProcessGDBRemote::DumpPluginHistory(Stream &s) {
@@ -441,8 +439,16 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
if (!arch_to_use.IsValid())
arch_to_use = target_arch;
- if (GetGDBServerRegisterInfo(arch_to_use))
+ llvm::Error register_info_err = GetGDBServerRegisterInfo(arch_to_use);
+ if (!register_info_err) {
+ // We got the registers from target XML.
return;
+ }
+
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOG_ERROR(log, std::move(register_info_err),
+ "Failed to read register information from target XML: {0}");
+ LLDB_LOG(log, "Now trying to use qRegisterInfo instead.");
char packet[128];
std::vector<DynamicRegisterInfo::Register> registers;
@@ -541,7 +547,23 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
assert(reg_info.byte_size != 0);
registers.push_back(reg_info);
} else {
- break; // ensure exit before reg_num is incremented
+ // Only warn if we were offered Target XML and could not use it, and
+ // the qRegisterInfo fallback failed. This is something a user could
+ // take action on by getting an lldb with libxml2.
+ //
+ // It's possible we weren't offered Target XML and qRegisterInfo failed,
+ // but there's no much a user can do about that. It may be the intended
+ // way the debug stub works, so we do not warn for that case.
+ if (response_type == StringExtractorGDBRemote::eUnsupported &&
+ m_gdb_comm.GetQXferFeaturesReadSupported() &&
+ !XMLDocument::XMLEnabled()) {
+ Debugger::ReportWarning(
+ "the debug server supports Target Description XML but LLDB does "
+ "not have XML parsing enabled. Using \"qRegisterInfo\" was also "
+ "not possible. Register information may be incorrect or missing.",
+ GetTarget().GetDebugger().GetID());
+ }
+ break;
}
} else {
break;
@@ -5137,14 +5159,19 @@ void ProcessGDBRemote::AddRemoteRegisters(
// query the target of gdb-remote for extended target information returns
// true on success (got register definitions), false on failure (did not).
-bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
- // Make sure LLDB has an XML parser it can use first
- if (!XMLDocument::XMLEnabled())
- return false;
-
- // check that we have extended feature read support
+llvm::Error ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
+ // If the remote does not offer XML, does not matter if we would have been
+ // able to parse it.
if (!m_gdb_comm.GetQXferFeaturesReadSupported())
- return false;
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "the debug server does not support \"qXfer:features:read\"");
+
+ if (!XMLDocument::XMLEnabled())
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "the debug server supports \"qXfer:features:read\", but LLDB does not "
+ "have XML parsing enabled (check LLLDB_ENABLE_LIBXML2)");
// These hold register type information for the whole of target.xml.
// target.xml may include further documents that
@@ -5161,7 +5188,11 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
!registers.empty())
AddRemoteRegisters(registers, arch_to_use);
- return m_register_info_sp->GetNumRegisters() > 0;
+ return m_register_info_sp->GetNumRegisters() > 0
+ ? llvm::ErrorSuccess()
+ : llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "the debug server did not describe any registers");
}
llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index eb33b52..b7e8777 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -416,7 +416,7 @@ protected:
void AddRemoteRegisters(std::vector<DynamicRegisterInfo::Register> &registers,
const ArchSpec &arch_to_use);
// Query remote GDBServer for register information
- bool GetGDBServerRegisterInfo(ArchSpec &arch);
+ llvm::Error GetGDBServerRegisterInfo(ArchSpec &arch);
lldb::ModuleSP LoadModuleAtAddress(const FileSpec &file,
lldb::addr_t link_map,
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index a780b3f..83d684e 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -95,8 +95,9 @@ bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp,
// header but we should still try to use it -
// ModuleSpecList::FindMatchingModuleSpec enforces a strict arch mach.
ModuleSpec core_module_spec(m_core_file);
+ core_module_spec.SetTarget(target_sp);
Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
- nullptr, nullptr, nullptr));
+ nullptr, nullptr));
if (m_core_module_sp) {
ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
index 6519df9..70ce101 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
@@ -7,42 +7,77 @@
//===----------------------------------------------------------------------===//
#include "ScriptedFrame.h"
-
+#include "Plugins/Process/Utility/RegisterContextMemory.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedThreadInterface.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
+char ScriptedFrame::ID;
+
void ScriptedFrame::CheckInterpreterAndScriptObject() const {
lldbassert(m_script_object_sp && "Invalid Script Object.");
lldbassert(GetInterface() && "Invalid Scripted Frame Interface.");
}
llvm::Expected<std::shared_ptr<ScriptedFrame>>
-ScriptedFrame::Create(ScriptedThread &thread,
+ScriptedFrame::Create(ThreadSP thread_sp,
+ ScriptedThreadInterfaceSP scripted_thread_interface_sp,
StructuredData::DictionarySP args_sp,
StructuredData::Generic *script_object) {
- if (!thread.IsValid())
- return llvm::createStringError("Invalid scripted thread.");
+ if (!thread_sp || !thread_sp->IsValid())
+ return llvm::createStringError("invalid thread");
+
+ ProcessSP process_sp = thread_sp->GetProcess();
+ if (!process_sp || !process_sp->IsValid())
+ return llvm::createStringError("invalid process");
- thread.CheckInterpreterAndScriptObject();
+ ScriptInterpreter *script_interp =
+ process_sp->GetTarget().GetDebugger().GetScriptInterpreter();
+ if (!script_interp)
+ return llvm::createStringError("no script interpreter");
- auto scripted_frame_interface =
- thread.GetInterface()->CreateScriptedFrameInterface();
+ auto scripted_frame_interface = script_interp->CreateScriptedFrameInterface();
if (!scripted_frame_interface)
return llvm::createStringError("failed to create scripted frame interface");
llvm::StringRef frame_class_name;
if (!script_object) {
- std::optional<std::string> class_name =
- thread.GetInterface()->GetScriptedFramePluginName();
- if (!class_name || class_name->empty())
+ // If no script object is provided and we have a scripted thread interface,
+ // try to get the frame class name from it.
+ if (scripted_thread_interface_sp) {
+ std::optional<std::string> class_name =
+ scripted_thread_interface_sp->GetScriptedFramePluginName();
+ if (!class_name || class_name->empty())
+ return llvm::createStringError(
+ "failed to get scripted frame class name");
+ frame_class_name = *class_name;
+ } else {
return llvm::createStringError(
- "failed to get scripted thread class name");
- frame_class_name = *class_name;
+ "no script object provided and no scripted thread interface");
+ }
}
- ExecutionContext exe_ctx(thread);
+ ExecutionContext exe_ctx(thread_sp);
auto obj_or_err = scripted_frame_interface->CreatePluginObject(
frame_class_name, exe_ctx, args_sp, script_object);
@@ -62,66 +97,43 @@ ScriptedFrame::Create(ScriptedThread &thread,
SymbolContext sc;
Address symbol_addr;
if (pc != LLDB_INVALID_ADDRESS) {
- symbol_addr.SetLoadAddress(pc, &thread.GetProcess()->GetTarget());
+ symbol_addr.SetLoadAddress(pc, &process_sp->GetTarget());
symbol_addr.CalculateSymbolContext(&sc);
}
std::optional<SymbolContext> maybe_sym_ctx =
scripted_frame_interface->GetSymbolContext();
- if (maybe_sym_ctx) {
+ if (maybe_sym_ctx)
sc = *maybe_sym_ctx;
- }
-
- StructuredData::DictionarySP reg_info =
- scripted_frame_interface->GetRegisterInfo();
-
- if (!reg_info)
- return llvm::createStringError(
- "failed to get scripted thread registers info");
-
- std::shared_ptr<DynamicRegisterInfo> register_info_sp =
- DynamicRegisterInfo::Create(
- *reg_info, thread.GetProcess()->GetTarget().GetArchitecture());
lldb::RegisterContextSP reg_ctx_sp;
-
- std::optional<std::string> reg_data =
- scripted_frame_interface->GetRegisterContext();
- if (reg_data) {
- DataBufferSP data_sp(
- std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
-
- if (!data_sp->GetByteSize())
- return llvm::createStringError("failed to copy raw registers data");
-
- std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
- std::make_shared<RegisterContextMemory>(
- thread, frame_id, *register_info_sp, LLDB_INVALID_ADDRESS);
- if (!reg_ctx_memory)
- return llvm::createStringError("failed to create a register context.");
-
- reg_ctx_memory->SetAllRegisterData(data_sp);
- reg_ctx_sp = reg_ctx_memory;
- }
-
- return std::make_shared<ScriptedFrame>(
- thread, scripted_frame_interface, frame_id, pc, sc, reg_ctx_sp,
- register_info_sp, owned_script_object_sp);
+ auto regs_or_err =
+ CreateRegisterContext(*scripted_frame_interface, *thread_sp, frame_id);
+ if (!regs_or_err)
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), regs_or_err.takeError(), "{0}");
+ else
+ reg_ctx_sp = *regs_or_err;
+
+ return std::make_shared<ScriptedFrame>(thread_sp, scripted_frame_interface,
+ frame_id, pc, sc, reg_ctx_sp,
+ owned_script_object_sp);
}
-ScriptedFrame::ScriptedFrame(ScriptedThread &thread,
+ScriptedFrame::ScriptedFrame(ThreadSP thread_sp,
ScriptedFrameInterfaceSP interface_sp,
lldb::user_id_t id, lldb::addr_t pc,
SymbolContext &sym_ctx,
lldb::RegisterContextSP reg_ctx_sp,
- std::shared_ptr<DynamicRegisterInfo> reg_info_sp,
StructuredData::GenericSP script_object_sp)
- : StackFrame(thread.shared_from_this(), /*frame_idx=*/id,
+ : StackFrame(thread_sp, /*frame_idx=*/id,
/*concrete_frame_idx=*/id, /*reg_context_sp=*/reg_ctx_sp,
/*cfa=*/0, /*pc=*/pc,
/*behaves_like_zeroth_frame=*/!id, /*symbol_ctx=*/&sym_ctx),
m_scripted_frame_interface_sp(interface_sp),
- m_script_object_sp(script_object_sp), m_register_info_sp(reg_info_sp) {}
+ m_script_object_sp(script_object_sp) {
+ // FIXME: This should be part of the base class constructor.
+ m_stack_frame_kind = StackFrame::Kind::Synthetic;
+}
ScriptedFrame::~ScriptedFrame() {}
@@ -129,7 +141,7 @@ const char *ScriptedFrame::GetFunctionName() {
CheckInterpreterAndScriptObject();
std::optional<std::string> function_name = GetInterface()->GetFunctionName();
if (!function_name)
- return nullptr;
+ return StackFrame::GetFunctionName();
return ConstString(function_name->c_str()).AsCString();
}
@@ -138,7 +150,7 @@ const char *ScriptedFrame::GetDisplayFunctionName() {
std::optional<std::string> function_name =
GetInterface()->GetDisplayFunctionName();
if (!function_name)
- return nullptr;
+ return StackFrame::GetDisplayFunctionName();
return ConstString(function_name->c_str()).AsCString();
}
@@ -157,35 +169,99 @@ lldb::ScriptedFrameInterfaceSP ScriptedFrame::GetInterface() const {
std::shared_ptr<DynamicRegisterInfo> ScriptedFrame::GetDynamicRegisterInfo() {
CheckInterpreterAndScriptObject();
- if (!m_register_info_sp) {
- StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
+ StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
+
+ Status error;
+ if (!reg_info)
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION, "failed to get scripted frame registers info",
+ error, LLDBLog::Thread);
+
+ ThreadSP thread_sp = m_thread_wp.lock();
+ if (!thread_sp || !thread_sp->IsValid())
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION,
+ "failed to get scripted frame registers info: invalid thread", error,
+ LLDBLog::Thread);
+
+ ProcessSP process_sp = thread_sp->GetProcess();
+ if (!process_sp || !process_sp->IsValid())
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION,
+ "failed to get scripted frame registers info: invalid process", error,
+ LLDBLog::Thread);
+
+ return DynamicRegisterInfo::Create(*reg_info,
+ process_sp->GetTarget().GetArchitecture());
+}
+
+llvm::Expected<lldb::RegisterContextSP>
+ScriptedFrame::CreateRegisterContext(ScriptedFrameInterface &interface,
+ Thread &thread, lldb::user_id_t frame_id) {
+ StructuredData::DictionarySP reg_info = interface.GetRegisterInfo();
+ if (!reg_info)
+ return llvm::createStringError(
+ "failed to get scripted frame registers info");
+
+ std::shared_ptr<DynamicRegisterInfo> register_info_sp =
+ DynamicRegisterInfo::Create(
+ *reg_info, thread.GetProcess()->GetTarget().GetArchitecture());
+
+ lldb::RegisterContextSP reg_ctx_sp;
+
+ std::optional<std::string> reg_data = interface.GetRegisterContext();
+ if (!reg_data)
+ return llvm::createStringError(
+ "failed to get scripted frame registers data");
+
+ DataBufferSP data_sp(
+ std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
+
+ if (!data_sp->GetByteSize())
+ return llvm::createStringError("failed to copy raw registers data");
+
+ std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
+ std::make_shared<RegisterContextMemory>(
+ thread, frame_id, *register_info_sp, LLDB_INVALID_ADDRESS);
+
+ reg_ctx_memory->SetAllRegisterData(data_sp);
+ reg_ctx_sp = reg_ctx_memory;
+
+ return reg_ctx_sp;
+}
+
+lldb::RegisterContextSP ScriptedFrame::GetRegisterContext() {
+ if (!m_reg_context_sp) {
Status error;
- if (!reg_info)
- return ScriptedInterface::ErrorWithMessage<
- std::shared_ptr<DynamicRegisterInfo>>(
- LLVM_PRETTY_FUNCTION, "Failed to get scripted frame registers info.",
+ if (!m_scripted_frame_interface_sp)
+ return ScriptedInterface::ErrorWithMessage<RegisterContextSP>(
+ LLVM_PRETTY_FUNCTION,
+ "failed to get scripted frame registers context: invalid interface",
error, LLDBLog::Thread);
- ThreadSP thread_sp = m_thread_wp.lock();
- if (!thread_sp || !thread_sp->IsValid())
- return ScriptedInterface::ErrorWithMessage<
- std::shared_ptr<DynamicRegisterInfo>>(
+ ThreadSP thread_sp = GetThread();
+ if (!thread_sp)
+ return ScriptedInterface::ErrorWithMessage<RegisterContextSP>(
LLVM_PRETTY_FUNCTION,
- "Failed to get scripted frame registers info: invalid thread.", error,
- LLDBLog::Thread);
+ "failed to get scripted frame registers context: invalid thread",
+ error, LLDBLog::Thread);
- ProcessSP process_sp = thread_sp->GetProcess();
- if (!process_sp || !process_sp->IsValid())
- return ScriptedInterface::ErrorWithMessage<
- std::shared_ptr<DynamicRegisterInfo>>(
+ auto regs_or_err = CreateRegisterContext(*m_scripted_frame_interface_sp,
+ *thread_sp, GetFrameIndex());
+ if (!regs_or_err) {
+ error = Status::FromError(regs_or_err.takeError());
+ return ScriptedInterface::ErrorWithMessage<RegisterContextSP>(
LLVM_PRETTY_FUNCTION,
- "Failed to get scripted frame registers info: invalid process.",
- error, LLDBLog::Thread);
+ "failed to get scripted frame registers context", error,
+ LLDBLog::Thread);
+ }
- m_register_info_sp = DynamicRegisterInfo::Create(
- *reg_info, process_sp->GetTarget().GetArchitecture());
+ m_reg_context_sp = *regs_or_err;
}
- return m_register_info_sp;
+ return m_reg_context_sp;
}
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.h b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
index 6e01e2f..0545548 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
@@ -9,33 +9,50 @@
#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
#define LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
-#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "ScriptedThread.h"
-#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/DynamicRegisterInfo.h"
#include "lldb/Target/StackFrame.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/Support/Error.h"
+#include <memory>
#include <string>
namespace lldb_private {
-class ScriptedThread;
-}
-
-namespace lldb_private {
class ScriptedFrame : public lldb_private::StackFrame {
public:
- ScriptedFrame(ScriptedThread &thread,
+ ScriptedFrame(lldb::ThreadSP thread_sp,
lldb::ScriptedFrameInterfaceSP interface_sp,
lldb::user_id_t frame_idx, lldb::addr_t pc,
SymbolContext &sym_ctx, lldb::RegisterContextSP reg_ctx_sp,
- std::shared_ptr<DynamicRegisterInfo> reg_info_sp,
StructuredData::GenericSP script_object_sp = nullptr);
~ScriptedFrame() override;
+ /// Create a ScriptedFrame from a object instanciated in the script
+ /// interpreter.
+ ///
+ /// \param[in] thread_sp
+ /// The thread this frame belongs to.
+ ///
+ /// \param[in] scripted_thread_interface_sp
+ /// The scripted thread interface (needed for ScriptedThread
+ /// compatibility). Can be nullptr for frames on real threads.
+ ///
+ /// \param[in] args_sp
+ /// Arguments to pass to the frame creation.
+ ///
+ /// \param[in] script_object
+ /// The optional script object representing this frame.
+ ///
+ /// \return
+ /// An Expected containing the ScriptedFrame shared pointer if successful,
+ /// otherwise an error.
static llvm::Expected<std::shared_ptr<ScriptedFrame>>
- Create(ScriptedThread &thread, StructuredData::DictionarySP args_sp,
+ Create(lldb::ThreadSP thread_sp,
+ lldb::ScriptedThreadInterfaceSP scripted_thread_interface_sp,
+ StructuredData::DictionarySP args_sp,
StructuredData::Generic *script_object = nullptr);
bool IsInlined() override;
@@ -44,9 +61,19 @@ public:
const char *GetFunctionName() override;
const char *GetDisplayFunctionName() override;
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || StackFrame::isA(ClassID);
+ }
+ static bool classof(const StackFrame *obj) { return obj->isA(&ID); }
+
private:
void CheckInterpreterAndScriptObject() const;
lldb::ScriptedFrameInterfaceSP GetInterface() const;
+ static llvm::Expected<lldb::RegisterContextSP>
+ CreateRegisterContext(ScriptedFrameInterface &interface, Thread &thread,
+ lldb::user_id_t frame_id);
ScriptedFrame(const ScriptedFrame &) = delete;
const ScriptedFrame &operator=(const ScriptedFrame &) = delete;
@@ -55,7 +82,8 @@ private:
lldb::ScriptedFrameInterfaceSP m_scripted_frame_interface_sp;
lldb_private::StructuredData::GenericSP m_script_object_sp;
- std::shared_ptr<DynamicRegisterInfo> m_register_info_sp;
+
+ static char ID;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
index 491efac..1dd9c48 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -210,7 +210,7 @@ bool ScriptedThread::LoadArtificialStackFrames() {
SymbolContext sc;
symbol_addr.CalculateSymbolContext(&sc);
- return std::make_shared<StackFrame>(this->shared_from_this(), idx, idx, cfa,
+ return std::make_shared<StackFrame>(shared_from_this(), idx, idx, cfa,
cfa_is_valid, pc,
StackFrame::Kind::Synthetic, artificial,
behaves_like_zeroth_frame, &sc);
@@ -231,8 +231,8 @@ bool ScriptedThread::LoadArtificialStackFrames() {
return error.ToError();
}
- auto frame_or_error =
- ScriptedFrame::Create(*this, nullptr, object_sp->GetAsGeneric());
+ auto frame_or_error = ScriptedFrame::Create(
+ shared_from_this(), GetInterface(), nullptr, object_sp->GetAsGeneric());
if (!frame_or_error) {
ScriptedInterface::ErrorWithMessage<bool>(
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
index 0910357..50569cd 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
@@ -23,6 +23,7 @@ add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces PLUGIN
OperatingSystemPythonInterface.cpp
ScriptInterpreterPythonInterfaces.cpp
ScriptedFramePythonInterface.cpp
+ ScriptedFrameProviderPythonInterface.cpp
ScriptedPlatformPythonInterface.cpp
ScriptedProcessPythonInterface.cpp
ScriptedPythonInterface.cpp
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
index d43036d..f6c707b 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
@@ -31,6 +31,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() {
ScriptedStopHookPythonInterface::Initialize();
ScriptedBreakpointPythonInterface::Initialize();
ScriptedThreadPlanPythonInterface::Initialize();
+ ScriptedFrameProviderPythonInterface::Initialize();
}
void ScriptInterpreterPythonInterfaces::Terminate() {
@@ -40,6 +41,7 @@ void ScriptInterpreterPythonInterfaces::Terminate() {
ScriptedStopHookPythonInterface::Terminate();
ScriptedBreakpointPythonInterface::Terminate();
ScriptedThreadPlanPythonInterface::Terminate();
+ ScriptedFrameProviderPythonInterface::Terminate();
}
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
index 3814f46..b2a3479 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
@@ -17,6 +17,7 @@
#include "OperatingSystemPythonInterface.h"
#include "ScriptedBreakpointPythonInterface.h"
+#include "ScriptedFrameProviderPythonInterface.h"
#include "ScriptedFramePythonInterface.h"
#include "ScriptedPlatformPythonInterface.h"
#include "ScriptedProcessPythonInterface.h"
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp
new file mode 100644
index 0000000..3dde503
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp
@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/Core/PluginManager.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Target/Thread.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 "ScriptedFrameProviderPythonInterface.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ScriptedFrameProviderPythonInterface::ScriptedFrameProviderPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedFrameProviderInterface(), ScriptedPythonInterface(interpreter) {}
+
+bool ScriptedFrameProviderPythonInterface::AppliesToThread(
+ llvm::StringRef class_name, lldb::ThreadSP thread_sp) {
+ // If there is any issue with this method, we will just assume it also applies
+ // to this thread which is the default behavior.
+ constexpr bool fail_value = true;
+ Status error;
+ StructuredData::ObjectSP obj =
+ CallStaticMethod(class_name, "applies_to_thread", error, thread_sp);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return fail_value;
+
+ return obj->GetBooleanValue(fail_value);
+}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedFrameProviderPythonInterface::CreatePluginObject(
+ const llvm::StringRef class_name, lldb::StackFrameListSP input_frames,
+ StructuredData::DictionarySP args_sp) {
+ if (!input_frames)
+ return llvm::createStringError("invalid frame list");
+
+ StructuredDataImpl sd_impl(args_sp);
+ return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr,
+ input_frames, sd_impl);
+}
+
+std::string ScriptedFrameProviderPythonInterface::GetDescription(
+ llvm::StringRef class_name) {
+ Status error;
+ StructuredData::ObjectSP obj =
+ CallStaticMethod(class_name, "get_description", error);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetStringValue().str();
+}
+
+StructuredData::ObjectSP
+ScriptedFrameProviderPythonInterface::GetFrameAtIndex(uint32_t index) {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_frame_at_index", error, index);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj;
+}
+
+bool ScriptedFrameProviderPythonInterface::CreateInstance(
+ lldb::ScriptLanguage language, ScriptedInterfaceUsages usages) {
+ if (language != eScriptLanguagePython)
+ return false;
+
+ return true;
+}
+
+void ScriptedFrameProviderPythonInterface::Initialize() {
+ const std::vector<llvm::StringRef> ci_usages = {
+ "target frame-provider register -C <script-name> [-k key -v value ...]",
+ "target frame-provider list",
+ "target frame-provider remove <provider-name>",
+ "target frame-provider clear"};
+ const std::vector<llvm::StringRef> api_usages = {
+ "SBTarget.RegisterScriptedFrameProvider",
+ "SBTarget.RemoveScriptedFrameProvider",
+ "SBTarget.ClearScriptedFrameProvider"};
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(),
+ llvm::StringRef("Provide scripted stack frames for threads"),
+ CreateInstance, eScriptLanguagePython, {ci_usages, api_usages});
+}
+
+void ScriptedFrameProviderPythonInterface::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.h
new file mode 100644
index 0000000..97a5cc7
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.h
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SCRIPTEDFRAMEPROVIDERPYTHONINTERFACE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPROVIDERPYTHONINTERFACE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "ScriptedPythonInterface.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
+#include <optional>
+
+namespace lldb_private {
+class ScriptedFrameProviderPythonInterface
+ : public ScriptedFrameProviderInterface,
+ public ScriptedPythonInterface,
+ public PluginInterface {
+public:
+ ScriptedFrameProviderPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter);
+
+ bool AppliesToThread(llvm::StringRef class_name,
+ lldb::ThreadSP thread_sp) override;
+
+ llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name,
+ lldb::StackFrameListSP input_frames,
+ StructuredData::DictionarySP args_sp) override;
+
+ llvm::SmallVector<AbstractMethodRequirement>
+ GetAbstractMethodRequirements() const override {
+ return llvm::SmallVector<AbstractMethodRequirement>(
+ {{"get_description"}, {"get_frame_at_index"}});
+ }
+
+ std::string GetDescription(llvm::StringRef class_name) override;
+
+ StructuredData::ObjectSP GetFrameAtIndex(uint32_t index) override;
+
+ static void Initialize();
+ static void Terminate();
+
+ static bool CreateInstance(lldb::ScriptLanguage language,
+ ScriptedInterfaceUsages usages);
+
+ static llvm::StringRef GetPluginNameStatic() {
+ return "ScriptedFrameProviderPythonInterface";
+ }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPROVIDERPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index 4fdf2b1..ba4473c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -94,6 +94,19 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>(
}
template <>
+lldb::ThreadSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ThreadSP>(
+ python::PythonObject &p, Status &error) {
+ if (lldb::SBThread *sb_thread = reinterpret_cast<lldb::SBThread *>(
+ python::LLDBSWIGPython_CastPyObjectToSBThread(p.get())))
+ return m_interpreter.GetOpaqueTypeFromSBThread(*sb_thread);
+ error = Status::FromErrorString(
+ "Couldn't cast lldb::SBThread to lldb_private::Thread.");
+
+ return nullptr;
+}
+
+template <>
SymbolContext
ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>(
python::PythonObject &p, Status &error) {
@@ -243,4 +256,21 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>(
return static_cast<lldb::DescriptionLevel>(unsigned_val);
}
+template <>
+lldb::StackFrameListSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameListSP>(
+ python::PythonObject &p, Status &error) {
+
+ lldb::SBFrameList *sb_frame_list = reinterpret_cast<lldb::SBFrameList *>(
+ python::LLDBSWIGPython_CastPyObjectToSBFrameList(p.get()));
+
+ if (!sb_frame_list) {
+ error = Status::FromErrorStringWithFormat(
+ "couldn't cast lldb::SBFrameList to lldb::StackFrameListSP.");
+ return {};
+ }
+
+ return m_interpreter.GetOpaqueTypeFromSBFrameList(*sb_frame_list);
+}
+
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index 2335b2e..b737f94 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -41,7 +41,7 @@ public:
eValid
};
- struct AbstrackMethodCheckerPayload {
+ struct AbstractMethodCheckerPayload {
struct InvalidArgumentCountPayload {
InvalidArgumentCountPayload(size_t required, size_t actual)
@@ -55,13 +55,69 @@ public:
std::variant<std::monostate, InvalidArgumentCountPayload> payload;
};
- llvm::Expected<std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload>>
+ llvm::Expected<FileSpec> GetScriptedModulePath() override {
+ using namespace python;
+ using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ if (!m_object_instance_sp)
+ return llvm::createStringError("scripted Interface has invalid object");
+
+ PythonObject py_obj =
+ PythonObject(PyRefType::Borrowed,
+ static_cast<PyObject *>(m_object_instance_sp->GetValue()));
+
+ if (!py_obj.IsAllocated())
+ return llvm::createStringError(
+ "scripted Interface has invalid python object");
+
+ PythonObject py_obj_class = py_obj.GetAttributeValue("__class__");
+ if (!py_obj_class.IsValid())
+ return llvm::createStringError(
+ "scripted Interface python object is missing '__class__' attribute");
+
+ PythonObject py_obj_module = py_obj_class.GetAttributeValue("__module__");
+ if (!py_obj_module.IsValid())
+ return llvm::createStringError(
+ "scripted Interface python object '__class__' is missing "
+ "'__module__' attribute");
+
+ PythonString py_obj_module_str = py_obj_module.Str();
+ if (!py_obj_module_str.IsValid())
+ return llvm::createStringError(
+ "scripted Interface python object '__class__.__module__' attribute "
+ "is not a string");
+
+ llvm::StringRef py_obj_module_str_ref = py_obj_module_str.GetString();
+ PythonModule py_module = PythonModule::AddModule(py_obj_module_str_ref);
+ if (!py_module.IsValid())
+ return llvm::createStringError("failed to import '%s' module",
+ py_obj_module_str_ref.data());
+
+ PythonObject py_module_file = py_module.GetAttributeValue("__file__");
+ if (!py_module_file.IsValid())
+ return llvm::createStringError(
+ "module '%s' is missing '__file__' attribute",
+ py_obj_module_str_ref.data());
+
+ PythonString py_module_file_str = py_module_file.Str();
+ if (!py_module_file_str.IsValid())
+ return llvm::createStringError(
+ "module '%s.__file__' attribute is not a string",
+ py_obj_module_str_ref.data());
+
+ return FileSpec(py_module_file_str.GetString());
+ }
+
+ llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerPayload>>
CheckAbstractMethodImplementation(
const python::PythonDictionary &class_dict) const {
using namespace python;
- std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload> checker;
+ std::map<llvm::StringLiteral, AbstractMethodCheckerPayload> checker;
#define SET_CASE_AND_CONTINUE(method_name, case) \
{ \
checker[method_name] = {case, {}}; \
@@ -74,7 +130,8 @@ public:
if (!class_dict.HasKey(method_name))
SET_CASE_AND_CONTINUE(method_name,
AbstractMethodCheckerCases::eNotImplemented)
- auto callable_or_err = class_dict.GetItem(method_name);
+ llvm::Expected<PythonObject> callable_or_err =
+ class_dict.GetItem(method_name);
if (!callable_or_err) {
llvm::consumeError(callable_or_err.takeError());
SET_CASE_AND_CONTINUE(method_name,
@@ -102,7 +159,7 @@ public:
} else {
checker[method_name] = {
AbstractMethodCheckerCases::eInvalidArgumentCount,
- AbstrackMethodCheckerPayload::InvalidArgumentCountPayload(
+ AbstractMethodCheckerPayload::InvalidArgumentCountPayload(
requirement.min_arg_count, arg_info.max_positional_args)};
}
}
@@ -188,8 +245,13 @@ public:
// This addresses the cases where the embedded interpreter session
// dictionary is passed to the extension initializer which is not used
// most of the time.
+ // Note, though none of our API's suggest defining the interfaces with
+ // varargs, we have some extant clients that were doing that. To keep
+ // from breaking them, we just say putting a varargs in these signatures
+ // turns off argument checking.
size_t num_args = sizeof...(Args);
- if (num_args != arg_info->max_positional_args) {
+ if (arg_info->max_positional_args != PythonCallable::ArgInfo::UNBOUNDED &&
+ num_args != arg_info->max_positional_args) {
if (num_args != arg_info->max_positional_args - 1)
return create_error("Passed arguments ({0}) doesn't match the number "
"of expected arguments ({1}).",
@@ -286,7 +348,7 @@ public:
case AbstractMethodCheckerCases::eInvalidArgumentCount: {
auto &payload_variant = method_checker.second.payload;
if (!std::holds_alternative<
- AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
+ AbstractMethodCheckerPayload::InvalidArgumentCountPayload>(
payload_variant)) {
abstract_method_errors = llvm::joinErrors(
std::move(abstract_method_errors),
@@ -295,7 +357,7 @@ public:
obj_class_name.GetString(), method_checker.first)));
} else {
auto payload = std::get<
- AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
+ AbstractMethodCheckerPayload::InvalidArgumentCountPayload>(
payload_variant);
abstract_method_errors = llvm::joinErrors(
std::move(abstract_method_errors),
@@ -325,6 +387,112 @@ public:
return m_object_instance_sp;
}
+ /// Call a static method on a Python class without creating an instance.
+ ///
+ /// This method resolves a Python class by name and calls a static method
+ /// on it, returning the result. This is useful for calling class-level
+ /// methods that don't require an instance.
+ ///
+ /// \param class_name The fully-qualified name of the Python class.
+ /// \param method_name The name of the static method to call.
+ /// \param error Output parameter to receive error information if the call
+ /// fails.
+ /// \param args Arguments to pass to the static method.
+ ///
+ /// \return The return value of the static method call, or an error value.
+ template <typename T = StructuredData::ObjectSP, typename... Args>
+ T CallStaticMethod(llvm::StringRef class_name, llvm::StringRef method_name,
+ Status &error, Args &&...args) {
+ using namespace python;
+ using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ std::string caller_signature =
+ llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
+ llvm::Twine(class_name) + llvm::Twine(".") +
+ llvm::Twine(method_name) + llvm::Twine(")"))
+ .str();
+
+ if (class_name.empty())
+ return ErrorWithMessage<T>(caller_signature, "missing script class name",
+ error);
+
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ // Get the interpreter dictionary.
+ auto dict =
+ PythonModule::MainModule().ResolveName<python::PythonDictionary>(
+ m_interpreter.GetDictionaryName());
+ if (!dict.IsAllocated())
+ return ErrorWithMessage<T>(
+ caller_signature,
+ llvm::formatv("could not find interpreter dictionary: {0}",
+ m_interpreter.GetDictionaryName())
+ .str(),
+ error);
+
+ // Resolve the class.
+ auto class_obj =
+ PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
+ class_name, dict);
+ if (!class_obj.IsAllocated())
+ return ErrorWithMessage<T>(
+ caller_signature,
+ llvm::formatv("could not find script class: {0}", class_name).str(),
+ error);
+
+ // Get the static method from the class.
+ if (!class_obj.HasAttribute(method_name))
+ return ErrorWithMessage<T>(
+ caller_signature,
+ llvm::formatv("class {0} does not have method {1}", class_name,
+ method_name)
+ .str(),
+ error);
+
+ PythonCallable method =
+ class_obj.GetAttributeValue(method_name).AsType<PythonCallable>();
+ if (!method.IsAllocated())
+ return ErrorWithMessage<T>(caller_signature,
+ llvm::formatv("method {0}.{1} is not callable",
+ class_name, method_name)
+ .str(),
+ error);
+
+ // Transform the arguments.
+ std::tuple<Args...> original_args = std::forward_as_tuple(args...);
+ auto transformed_args = TransformArgs(original_args);
+
+ // Call the static method.
+ llvm::Expected<PythonObject> expected_return_object =
+ llvm::make_error<llvm::StringError>("Not initialized.",
+ llvm::inconvertibleErrorCode());
+ std::apply(
+ [&method, &expected_return_object](auto &&...args) {
+ llvm::consumeError(expected_return_object.takeError());
+ expected_return_object = method(args...);
+ },
+ transformed_args);
+
+ if (llvm::Error e = expected_return_object.takeError()) {
+ error = Status::FromError(std::move(e));
+ return ErrorWithMessage<T>(
+ caller_signature, "python static method could not be called", error);
+ }
+
+ PythonObject py_return = std::move(expected_return_object.get());
+
+ // Re-assign reference and pointer arguments if needed.
+ if (sizeof...(Args) > 0)
+ if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
+ return ErrorWithMessage<T>(
+ caller_signature,
+ "couldn't re-assign reference and pointer arguments", error);
+
+ // Extract value from Python object (handles unallocated case).
+ return ExtractValueFromPythonObject<T>(py_return, error);
+ }
+
protected:
template <typename T = StructuredData::ObjectSP>
T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
@@ -341,7 +509,7 @@ protected:
llvm::Twine(method_name) + llvm::Twine(")"))
.str();
if (!m_object_instance_sp)
- return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",
+ return ErrorWithMessage<T>(caller_signature, "python object ill-formed",
error);
Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
@@ -353,7 +521,7 @@ protected:
if (!implementor.IsAllocated())
return llvm::is_contained(GetAbstractMethods(), method_name)
? ErrorWithMessage<T>(caller_signature,
- "Python implementor not allocated.",
+ "python implementor not allocated",
error)
: T{};
@@ -374,20 +542,20 @@ protected:
if (llvm::Error e = expected_return_object.takeError()) {
error = Status::FromError(std::move(e));
return ErrorWithMessage<T>(caller_signature,
- "Python method could not be called.", error);
+ "python method could not be called", error);
}
PythonObject py_return = std::move(expected_return_object.get());
// Now that we called the python method with the transformed arguments,
- // we need to interate again over both the original and transformed
+ // we need to iterate again over both the original and transformed
// parameter pack, and transform back the parameter that were passed in
// the original parameter pack as references or pointers.
if (sizeof...(Args) > 0)
if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
return ErrorWithMessage<T>(
caller_signature,
- "Couldn't re-assign reference and pointer arguments.", error);
+ "couldn't re-assign reference and pointer arguments", error);
if (!py_return.IsAllocated())
return {};
@@ -444,6 +612,14 @@ protected:
return python::SWIGBridge::ToSWIGWrapper(arg);
}
+ python::PythonObject Transform(lldb::ThreadSP arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
+ python::PythonObject Transform(lldb::StackFrameListSP arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
python::PythonObject Transform(lldb::ThreadPlanSP arg) {
return python::SWIGBridge::ToSWIGWrapper(arg);
}
@@ -586,6 +762,11 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
python::PythonObject &p, Status &error);
template <>
+lldb::ThreadSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ThreadSP>(
+ python::PythonObject &p, Status &error);
+
+template <>
lldb::StackFrameSP
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>(
python::PythonObject &p, Status &error);
@@ -628,6 +809,11 @@ lldb::DescriptionLevel
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>(
python::PythonObject &p, Status &error);
+template <>
+lldb::StackFrameListSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameListSP>(
+ python::PythonObject &p, Status &error);
+
} // namespace lldb_private
#endif // LLDB_ENABLE_PYTHON
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index a2a287a..d2f795c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -810,6 +810,17 @@ bool PythonCallable::Check(PyObject *py_obj) {
if (!py_obj)
return false;
+ PythonObject python_obj(PyRefType::Borrowed, py_obj);
+
+ // Handle staticmethod/classmethod descriptors by extracting the
+ // `__func__` attribute.
+ if (python_obj.HasAttribute("__func__")) {
+ PythonObject function_obj = python_obj.GetAttributeValue("__func__");
+ if (!function_obj.IsAllocated())
+ return false;
+ return PyCallable_Check(function_obj.release());
+ }
+
return PyCallable_Check(py_obj);
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 7b39d29..32948ff 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -93,6 +93,7 @@ public:
static PythonObject ToSWIGWrapper(const StructuredDataImpl &data_impl);
static PythonObject ToSWIGWrapper(lldb::ThreadSP thread_sp);
static PythonObject ToSWIGWrapper(lldb::StackFrameSP frame_sp);
+ static PythonObject ToSWIGWrapper(lldb::StackFrameListSP frames_sp);
static PythonObject ToSWIGWrapper(lldb::DebuggerSP debugger_sp);
static PythonObject ToSWIGWrapper(lldb::WatchpointSP watchpoint_sp);
static PythonObject ToSWIGWrapper(lldb::BreakpointLocationSP bp_loc_sp);
@@ -158,8 +159,9 @@ public:
static PyObject *LLDBSwigPython_GetChildAtIndex(PyObject *implementor,
uint32_t idx);
- static int LLDBSwigPython_GetIndexOfChildWithName(PyObject *implementor,
- const char *child_name);
+ static uint32_t
+ LLDBSwigPython_GetIndexOfChildWithName(PyObject *implementor,
+ const char *child_name);
static lldb::ValueObjectSP
LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data);
@@ -263,11 +265,13 @@ void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBThread(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBFrame(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBSymbolContext(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBExecutionContext(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBFrameList(PyObject *data);
} // namespace python
} // namespace lldb_private
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 73c5c72..35a772c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -272,6 +272,7 @@ void ScriptInterpreterPython::SharedLibraryDirectoryHelper(
// does.
if (this_file.GetFileNameExtension() == ".pyd") {
this_file.RemoveLastPathComponent(); // _lldb.pyd or _lldb_d.pyd
+ this_file.RemoveLastPathComponent(); // native
this_file.RemoveLastPathComponent(); // lldb
llvm::StringRef libdir = LLDB_PYTHON_RELATIVE_LIBDIR;
for (auto it = llvm::sys::path::begin(libdir),
@@ -1526,6 +1527,11 @@ ScriptInterpreterPythonImpl::CreateScriptedFrameInterface() {
return std::make_shared<ScriptedFramePythonInterface>(*this);
}
+ScriptedFrameProviderInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedFrameProviderInterface() {
+ return std::make_shared<ScriptedFrameProviderPythonInterface>(*this);
+}
+
ScriptedThreadPlanInterfaceSP
ScriptInterpreterPythonImpl::CreateScriptedThreadPlanInterface() {
return std::make_shared<ScriptedThreadPlanPythonInterface>(*this);
@@ -1939,7 +1945,7 @@ lldb::ValueObjectSP ScriptInterpreterPythonImpl::GetChildAtIndex(
return ret_val;
}
-llvm::Expected<int> ScriptInterpreterPythonImpl::GetIndexOfChildWithName(
+llvm::Expected<uint32_t> ScriptInterpreterPythonImpl::GetIndexOfChildWithName(
const StructuredData::ObjectSP &implementor_sp, const char *child_name) {
if (!implementor_sp)
return llvm::createStringError("Type has no child named '%s'", child_name);
@@ -1951,7 +1957,7 @@ llvm::Expected<int> ScriptInterpreterPythonImpl::GetIndexOfChildWithName(
if (!implementor)
return llvm::createStringError("Type has no child named '%s'", child_name);
- int ret_val = INT32_MAX;
+ uint32_t ret_val = UINT32_MAX;
{
Locker py_lock(this,
@@ -1960,7 +1966,7 @@ llvm::Expected<int> ScriptInterpreterPythonImpl::GetIndexOfChildWithName(
child_name);
}
- if (ret_val == INT32_MAX)
+ if (ret_val == UINT32_MAX)
return llvm::createStringError("Type has no child named '%s'", child_name);
return ret_val;
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index dedac28..ad2ddd2 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -101,6 +101,9 @@ public:
lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
+ lldb::ScriptedFrameProviderInterfaceSP
+ CreateScriptedFrameProviderInterface() override;
+
lldb::ScriptedThreadPlanInterfaceSP
CreateScriptedThreadPlanInterface() override;
@@ -122,7 +125,7 @@ public:
GetChildAtIndex(const StructuredData::ObjectSP &implementor,
uint32_t idx) override;
- llvm::Expected<int>
+ llvm::Expected<uint32_t>
GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor,
const char *child_name) override;
diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
index ce2ba69..14932e9 100644
--- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
+++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -437,7 +437,7 @@ void SymbolFileBreakpad::FindFunctions(
sc.comp_unit = cu_sp.get();
sc.function = func_sp.get();
sc.module_sp = func_sp->CalculateSymbolContextModule();
- sc_list.Append(sc);
+ sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/true);
}
}
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 82e9d86..d65aa40 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -450,6 +450,10 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
byte_size = form_value.Unsigned();
break;
+ case DW_AT_bit_size:
+ data_bit_size = form_value.Unsigned();
+ break;
+
case DW_AT_alignment:
alignment = form_value.Unsigned();
break;
@@ -619,6 +623,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
switch (tag) {
case DW_TAG_typedef:
+ case DW_TAG_template_alias:
case DW_TAG_base_type:
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
@@ -744,7 +749,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
TypeSP type_sp;
CompilerType clang_type;
- if (tag == DW_TAG_typedef) {
+ if (tag == DW_TAG_typedef || tag == DW_TAG_template_alias) {
// DeclContext will be populated when the clang type is materialized in
// Type::ResolveCompilerType.
PrepareContextToReceiveMembers(
@@ -810,13 +815,18 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
// there...
[[fallthrough]];
- case DW_TAG_base_type:
+ case DW_TAG_base_type: {
resolve_state = Type::ResolveState::Full;
+ // If a builtin type's size isn't a multiple of a byte, DWARF producers may
+ // add a precise bit-size to the type. Use the most precise bit-size
+ // possible.
+ const uint64_t bit_size = attrs.data_bit_size
+ ? *attrs.data_bit_size
+ : attrs.byte_size.value_or(0) * 8;
clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize(
- attrs.name.GetStringRef(), attrs.encoding,
- attrs.byte_size.value_or(0) * 8);
+ attrs.name.GetStringRef(), attrs.encoding, bit_size);
break;
-
+ }
case DW_TAG_pointer_type:
encoding_data_type = Type::eEncodingIsPointerUID;
break;
@@ -827,6 +837,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
encoding_data_type = Type::eEncodingIsRValueReferenceUID;
break;
case DW_TAG_typedef:
+ case DW_TAG_template_alias:
encoding_data_type = Type::eEncodingIsTypedefUID;
break;
case DW_TAG_const_type:
@@ -1696,8 +1707,11 @@ void DWARFASTParserClang::GetUniqueTypeNameAndDeclaration(
// 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.
- if (!die.IsValid() || !Language::LanguageIsCPlusPlus(language) ||
- unique_typename.IsEmpty())
+ // FIXME: Rust pretends to be C++ for now, so use C++ name qualification rules
+ if (!Language::LanguageIsCPlusPlus(language) &&
+ language != lldb::eLanguageTypeRust)
+ return;
+ if (!die.IsValid() || unique_typename.IsEmpty())
return;
decl_declaration.Clear();
std::string qualified_name;
@@ -1901,6 +1915,17 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
m_ast.CreateClassTemplateSpecializationDecl(
containing_decl_ctx, GetOwningClangModule(die), class_template_decl,
tag_decl_kind, template_param_infos);
+ if (!class_specialization_decl) {
+ if (log) {
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF({0:p}) - Failed to create specialization for "
+ "clang::ClassTemplateDecl({1}, {2:p}).",
+ this, llvm::StringRef(attrs.name), class_template_decl);
+ }
+ return TypeSP();
+ }
+
clang_type =
m_ast.CreateClassTemplateSpecializationType(class_specialization_decl);
@@ -2032,11 +2057,10 @@ static std::optional<clang::APValue> MakeAPValue(const clang::ASTContext &ast,
if (is_integral)
return clang::APValue(apint);
- uint32_t count;
bool is_complex;
// FIXME: we currently support a limited set of floating point types.
// E.g., 16-bit floats are not supported.
- if (!clang_type.IsFloatingPointType(count, is_complex))
+ if (!clang_type.IsFloatingPointType(is_complex))
return std::nullopt;
return clang::APValue(llvm::APFloat(
@@ -3685,12 +3709,10 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
}
}
- DWARFASTParserClang *src_dwarf_ast_parser =
- static_cast<DWARFASTParserClang *>(
- SymbolFileDWARF::GetDWARFParser(*src_class_die.GetCU()));
- DWARFASTParserClang *dst_dwarf_ast_parser =
- static_cast<DWARFASTParserClang *>(
- SymbolFileDWARF::GetDWARFParser(*dst_class_die.GetCU()));
+ auto *src_dwarf_ast_parser = llvm::cast<DWARFASTParserClang>(
+ SymbolFileDWARF::GetDWARFParser(*src_class_die.GetCU()));
+ auto *dst_dwarf_ast_parser = llvm::cast<DWARFASTParserClang>(
+ SymbolFileDWARF::GetDWARFParser(*dst_class_die.GetCU()));
auto link = [&](DWARFDIE src, DWARFDIE dst) {
auto &die_to_type = dst_class_die.GetDWARF()->GetDIEToType();
clang::DeclContext *dst_decl_ctx =
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index da58f4c..6eb2b6b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -47,6 +47,11 @@ public:
~DWARFASTParserClang() override;
+ // LLVM RTTI support
+ static bool classof(const DWARFASTParser *Parser) {
+ return Parser->GetKind() == Kind::DWARFASTParserClang;
+ }
+
// DWARFASTParser interface.
lldb::TypeSP
ParseTypeFromDWARF(const lldb_private::SymbolContext &sc,
@@ -264,10 +269,6 @@ protected:
lldb::ModuleSP
GetModuleForType(const lldb_private::plugin::dwarf::DWARFDIE &die);
- static bool classof(const DWARFASTParser *Parser) {
- return Parser->GetKind() == Kind::DWARFASTParserClang;
- }
-
private:
struct FieldInfo {
/// Size in bits that this field occupies. Can but
@@ -574,6 +575,7 @@ struct ParsedDWARFTypeAttributes {
lldb_private::plugin::dwarf::DWARFFormValue type;
lldb::LanguageType class_language = lldb::eLanguageTypeUnknown;
std::optional<uint64_t> byte_size;
+ std::optional<uint64_t> data_bit_size;
std::optional<uint64_t> alignment;
size_t calling_convention = llvm::dwarf::DW_CC_normal;
uint32_t bit_stride = 0;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
index 64a8005..c4efc06 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
@@ -173,6 +173,14 @@ void DWARFIndex::GetNamespacesWithParents(
});
}
+void DWARFIndex::GetFunctions(
+ const std::vector<Module::LookupInfo> &lookup_infos, SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
+ for (auto &lookup_info : lookup_infos)
+ GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
+}
+
IterationAction DWARFIndex::ProcessNamespaceDieMatchParents(
const CompilerDeclContext &parent_decl_ctx, DWARFDIE die,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
index be73255..eaf1da1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
@@ -86,6 +86,11 @@ public:
const CompilerDeclContext &parent_decl_ctx,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) = 0;
virtual void
+ GetFunctions(const std::vector<Module::LookupInfo> &lookup_infos,
+ SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<IterationAction(DWARFDIE die)> callback);
+ virtual void
GetFunctions(const RegularExpression &regex,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) = 0;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index 94fc2e83..b78e6ce8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -348,6 +348,10 @@ void DWARFUnit::ExtractDIEsRWLocked() {
void DWARFUnit::SetDwoStrOffsetsBase() {
lldb::offset_t baseOffset = 0;
+ // Size of offset for .debug_str_offsets is same as DWARF offset byte size
+ // of the DWARFUnit as a default. We might override this if below if needed.
+ m_str_offset_size = m_header.getDwarfOffsetByteSize();
+
if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {
if (const auto *contribution =
entry->getContribution(llvm::DW_SECT_STR_OFFSETS))
@@ -357,14 +361,17 @@ void DWARFUnit::SetDwoStrOffsetsBase() {
}
if (GetVersion() >= 5) {
- const DWARFDataExtractor &strOffsets =
- GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData();
- uint64_t length = strOffsets.GetU32(&baseOffset);
- if (length == 0xffffffff)
- length = strOffsets.GetU64(&baseOffset);
-
+ const llvm::DWARFDataExtractor &strOffsets = GetSymbolFileDWARF()
+ .GetDWARFContext()
+ .getOrLoadStrOffsetsData()
+ .GetAsLLVMDWARF();
+
+ uint64_t length;
+ llvm::dwarf::DwarfFormat format;
+ std::tie(length, format) = strOffsets.getInitialLength(&baseOffset);
+ m_str_offset_size = format == llvm::dwarf::DwarfFormat::DWARF64 ? 8 : 4;
// Check version.
- if (strOffsets.GetU16(&baseOffset) < 5)
+ if (strOffsets.getU16(&baseOffset) < 5)
return;
// Skip padding.
@@ -409,7 +416,16 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
SetRangesBase(form_value.Unsigned());
break;
case DW_AT_str_offsets_base:
+ // When we have a DW_AT_str_offsets_base attribute, it points us to the
+ // first string offset for this DWARFUnit which is after the string
+ // offsets table header. In this case we use the DWARF32/DWARF64 of the
+ // DWARFUnit to determine the string offset byte size. DWO files do not
+ // use this attribute and they point to the start of the string offsets
+ // table header which can be used to determine the DWARF32/DWARF64 status
+ // of the string table. See SetDwoStrOffsetsBase() for now it figures out
+ // the m_str_offset_size value that should be used.
SetStrOffsetsBase(form_value.Unsigned());
+ m_str_offset_size = m_header.getDwarfOffsetByteSize();
break;
case DW_AT_low_pc:
SetBaseAddress(form_value.Address());
@@ -1079,10 +1095,9 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { return m_header.getSize(); }
std::optional<uint64_t>
DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const {
- lldb::offset_t offset =
- GetStrOffsetsBase() + index * m_header.getDwarfOffsetByteSize();
+ lldb::offset_t offset = GetStrOffsetsBase() + index * m_str_offset_size;
return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64(
- &offset, m_header.getDwarfOffsetByteSize());
+ &offset, m_str_offset_size);
}
llvm::Expected<llvm::DWARFAddressRangesVector>
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index 91a6938..b5199a8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -364,6 +364,7 @@ protected:
dw_offset_t m_line_table_offset = DW_INVALID_OFFSET;
dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base.
+ dw_offset_t m_str_offset_size = 4; // Size in bytes of a string offset.
std::optional<llvm::DWARFDebugRnglistTable> m_rnglist_table;
bool m_rnglist_table_done = false;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
index d90108f..36dee14 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -22,7 +22,6 @@
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/Timer.h"
#include "lldb/lldb-private-enumerations.h"
-#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ThreadPool.h"
#include <atomic>
#include <optional>
@@ -33,10 +32,10 @@ using namespace lldb_private::plugin::dwarf;
using namespace llvm::dwarf;
void ManualDWARFIndex::Index() {
- if (m_indexed)
- return;
- m_indexed = true;
+ std::call_once(m_indexed_flag, [this]() { IndexImpl(); });
+}
+void ManualDWARFIndex::IndexImpl() {
ElapsedTime elapsed(m_index_time);
LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
if (LoadFromCache()) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
index 0b5b2f3..41e0e62 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
@@ -66,8 +66,14 @@ public:
void Dump(Stream &s) override;
private:
+ /// Reads the DWARF debug info to build the index once.
+ ///
+ /// Should be called before attempting to retrieve symbols.
void Index();
+ /// Call `ManualDWARFIndex::Index()` instead.
+ void IndexImpl();
+
/// Decode a serialized version of this object from data.
///
/// \param data
@@ -170,7 +176,7 @@ private:
llvm::DenseSet<uint64_t> m_type_sigs_to_avoid;
IndexSet<NameToDIE> m_set;
- bool m_indexed = false;
+ std::once_flag m_indexed_flag;
};
} // namespace dwarf
} // namespace lldb_private::plugin
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 881268b..b755f3a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -794,12 +794,12 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) {
} else {
ModuleSP module_sp(m_objfile_sp->GetModule());
if (module_sp) {
- auto initialize_cu = [&](lldb::SupportFileSP support_file_sp,
+ auto initialize_cu = [&](SupportFileNSP support_file_nsp,
LanguageType cu_language,
SupportFileList &&support_files = {}) {
BuildCuTranslationTable();
cu_sp = std::make_shared<CompileUnit>(
- module_sp, &dwarf_cu, support_file_sp,
+ module_sp, &dwarf_cu, support_file_nsp,
*GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language,
eLazyBoolCalculate, std::move(support_files));
@@ -1560,8 +1560,8 @@ bool SymbolFileDWARF::HasForwardDeclForCompilerType(
auto clang_type_system = compiler_type.GetTypeSystem<TypeSystemClang>();
if (!clang_type_system)
return false;
- DWARFASTParserClang *ast_parser =
- static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser());
+ auto *ast_parser =
+ llvm::cast<DWARFASTParserClang>(clang_type_system->GetDWARFParser());
return ast_parser->GetClangASTImporter().CanImport(compiler_type);
}
@@ -1569,8 +1569,8 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
auto clang_type_system = compiler_type.GetTypeSystem<TypeSystemClang>();
if (clang_type_system) {
- DWARFASTParserClang *ast_parser =
- static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser());
+ auto *ast_parser =
+ llvm::cast<DWARFASTParserClang>(clang_type_system->GetDWARFParser());
if (ast_parser &&
ast_parser->GetClangASTImporter().CanImport(compiler_type))
return ast_parser->GetClangASTImporter().CompleteType(compiler_type);
@@ -1614,8 +1614,7 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
if (decl_die != def_die) {
GetDIEToType()[def_die.GetDIE()] = type;
- DWARFASTParserClang *ast_parser =
- static_cast<DWARFASTParserClang *>(dwarf_ast);
+ auto *ast_parser = llvm::cast<DWARFASTParserClang>(dwarf_ast);
ast_parser->MapDeclDIEToDefDIE(decl_die, def_die);
}
@@ -2018,7 +2017,7 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
}
Status error = ModuleList::GetSharedModule(dwo_module_spec, module_sp,
- nullptr, nullptr, nullptr);
+ nullptr, nullptr);
if (!module_sp) {
// ReportWarning also rate-limits based on the warning string,
// but in a -gmodules build, each object file has a similar DAG
@@ -2341,7 +2340,7 @@ void SymbolFileDWARF::FindGlobalVariables(
bool name_is_mangled = Mangled::GetManglingScheme(name.GetStringRef()) !=
Mangled::eManglingSchemeNone;
- if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name.GetCString(),
+ if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name.GetStringRef(),
context, basename))
basename = name.GetStringRef();
@@ -2482,7 +2481,7 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
sc.block = function_block.FindBlockByID(inlined_die.GetOffset());
}
- sc_list.Append(sc);
+ sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/true);
return true;
}
@@ -2550,11 +2549,11 @@ SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label,
const DWARFDIE &declaration) {
auto do_lookup = [this](llvm::StringRef lookup_name) -> DWARFDIE {
DWARFDIE found;
- Module::LookupInfo info(ConstString(lookup_name),
- lldb::eFunctionNameTypeFull,
- lldb::eLanguageTypeUnknown);
+ auto lookup_infos = Module::LookupInfo::MakeLookupInfos(
+ ConstString(lookup_name), lldb::eFunctionNameTypeFull,
+ lldb::eLanguageTypeUnknown);
- m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+ m_index->GetFunctions(lookup_infos, *this, {}, [&](DWARFDIE entry) {
if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
return IterationAction::Continue;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index e76b7a3..3bf113a 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -86,6 +86,40 @@ static lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
}
}
+static std::optional<std::string>
+findMatchingPDBFilePath(llvm::StringRef original_pdb_path,
+ llvm::StringRef exe_path) {
+ const FileSystem &fs = FileSystem::Instance();
+
+ if (fs.Exists(original_pdb_path))
+ return std::string(original_pdb_path);
+
+ const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent();
+ // While the exe_path uses the native style, the exe might be compiled on a
+ // different OS, so try to guess the style used.
+ const FileSpec original_pdb_spec(original_pdb_path,
+ FileSpec::GuessPathStyle(original_pdb_path)
+ .value_or(FileSpec::Style::native));
+ const llvm::StringRef pdb_filename = original_pdb_spec.GetFilename();
+
+ // If the file doesn't exist, perhaps the path specified at build time
+ // doesn't match the PDB's current location, so check the location of the
+ // executable.
+ const FileSpec local_pdb = exe_dir.CopyByAppendingPathComponent(pdb_filename);
+ if (fs.Exists(local_pdb))
+ return local_pdb.GetPath();
+
+ // Otherwise, search for one in target.debug-file-search-paths
+ FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
+ for (const FileSpec &search_dir : search_paths) {
+ FileSpec pdb_path = search_dir.CopyByAppendingPathComponent(pdb_filename);
+ if (fs.Exists(pdb_path))
+ return pdb_path.GetPath();
+ }
+
+ return std::nullopt;
+}
+
static std::unique_ptr<PDBFile>
loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
// Try to find a matching PDB for an EXE.
@@ -113,17 +147,14 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
return nullptr;
}
- // If the file doesn't exist, perhaps the path specified at build time
- // doesn't match the PDB's current location, so check the location of the
- // executable.
- if (!FileSystem::Instance().Exists(pdb_file)) {
- const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent();
- const auto pdb_name = FileSpec(pdb_file).GetFilename().GetCString();
- pdb_file = exe_dir.CopyByAppendingPathComponent(pdb_name).GetPathAsConstString().GetStringRef();
- }
+ std::optional<std::string> resolved_pdb_path =
+ findMatchingPDBFilePath(pdb_file, exe_path);
+ if (!resolved_pdb_path)
+ return nullptr;
// If the file is not a PDB or if it doesn't have a matching GUID, fail.
- auto pdb = ObjectFilePDB::loadPDBFile(std::string(pdb_file), allocator);
+ auto pdb =
+ ObjectFilePDB::loadPDBFile(*std::move(resolved_pdb_path), allocator);
if (!pdb)
return nullptr;
@@ -137,6 +168,9 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
if (expected_info->getGuid() != guid)
return nullptr;
+
+ LLDB_LOG(GetLog(LLDBLog::Symbols), "Loading {0} for {1}", pdb->getFilePath(),
+ exe_path);
return pdb;
}
@@ -1126,11 +1160,40 @@ lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) {
}
void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {
- auto *section_list = m_objfile_sp->GetSectionList();
+ auto *section_list =
+ m_objfile_sp->GetModule()->GetObjectFile()->GetSectionList();
if (!section_list)
return;
- for (auto pid : m_index->publics().getPublicsTable()) {
+ PublicSym32 last_sym;
+ size_t last_sym_idx = 0;
+ lldb::SectionSP section_sp;
+
+ // To estimate the size of a symbol, we use the difference to the next symbol.
+ // If there's no next symbol or the section/segment changed, the symbol will
+ // take the remaining space. The estimate can be too high in case there's
+ // padding between symbols. This similar to the algorithm used by the DIA
+ // SDK.
+ auto finish_last_symbol = [&](const PublicSym32 *next) {
+ if (!section_sp)
+ return;
+ Symbol *last = symtab.SymbolAtIndex(last_sym_idx);
+ if (!last)
+ return;
+
+ if (next && last_sym.Segment == next->Segment) {
+ assert(last_sym.Offset <= next->Offset);
+ last->SetByteSize(next->Offset - last_sym.Offset);
+ } else {
+ // the last symbol was the last in its section
+ assert(section_sp->GetByteSize() >= last_sym.Offset);
+ assert(!next || next->Segment > last_sym.Segment);
+ last->SetByteSize(section_sp->GetByteSize() - last_sym.Offset);
+ }
+ };
+
+ // The address map is sorted by the address of a symbol.
+ for (auto pid : m_index->publics().getAddressMap()) {
PdbGlobalSymId global{pid, true};
CVSymbol sym = m_index->ReadSymbolRecord(global);
auto kind = sym.kind();
@@ -1138,8 +1201,11 @@ void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {
continue;
PublicSym32 pub =
llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym));
+ finish_last_symbol(&pub);
+
+ if (!section_sp || last_sym.Segment != pub.Segment)
+ section_sp = section_list->FindSectionByID(pub.Segment);
- auto section_sp = section_list->FindSectionByID(pub.Segment);
if (!section_sp)
continue;
@@ -1148,20 +1214,24 @@ void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {
(pub.Flags & PublicSymFlags::Code) != PublicSymFlags::None)
type = eSymbolTypeCode;
- symtab.AddSymbol(Symbol(/*symID=*/pid,
- /*name=*/pub.Name,
- /*type=*/type,
- /*external=*/true,
- /*is_debug=*/true,
- /*is_trampoline=*/false,
- /*is_artificial=*/false,
- /*section_sp=*/section_sp,
- /*value=*/pub.Offset,
- /*size=*/0,
- /*size_is_valid=*/false,
- /*contains_linker_annotations=*/false,
- /*flags=*/0));
- }
+ last_sym_idx =
+ symtab.AddSymbol(Symbol(/*symID=*/pid,
+ /*name=*/pub.Name,
+ /*type=*/type,
+ /*external=*/true,
+ /*is_debug=*/true,
+ /*is_trampoline=*/false,
+ /*is_artificial=*/false,
+ /*section_sp=*/section_sp,
+ /*value=*/pub.Offset,
+ /*size=*/0,
+ /*size_is_valid=*/false,
+ /*contains_linker_annotations=*/false,
+ /*flags=*/0));
+ last_sym = pub;
+ }
+
+ finish_last_symbol(nullptr);
}
size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) {
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 1c575e9..46cf9b8 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -442,6 +442,10 @@ void UdtRecordCompleter::Record::ConstructRecord() {
// The end offset to a vector of field/struct that ends at the offset.
std::map<uint64_t, std::vector<Member *>> end_offset_map;
+ auto is_last_end_offset = [&](auto it) {
+ return it != end_offset_map.end() && ++it == end_offset_map.end();
+ };
+
for (auto &pair : fields_map) {
uint64_t offset = pair.first;
auto &fields = pair.second;
@@ -462,8 +466,23 @@ void UdtRecordCompleter::Record::ConstructRecord() {
}
if (iter->second.empty())
continue;
- parent = iter->second.back();
- iter->second.pop_back();
+
+ // If the new fields come after the already added ones
+ // without overlap, go back to the root.
+ if (iter->first <= offset && is_last_end_offset(iter)) {
+ if (record.kind == Member::Struct) {
+ parent = &record;
+ } else {
+ assert(record.kind == Member::Union &&
+ "Current record must be a union");
+ assert(!record.fields.empty());
+ // For unions, append the field to the last struct
+ parent = record.fields.back().get();
+ }
+ } else {
+ parent = iter->second.back();
+ iter->second.pop_back();
+ }
}
// If it's a field, then the field is inside a union, so we can safely
// increase its size by converting it to a struct to hold multiple fields.
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index 3b936c0..97c995fc 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -83,8 +83,8 @@ constexpr OptionEnumValueElement g_pdb_reader_enums[] = {
{
ePDBReaderDefault,
"default",
- "Use DIA PDB reader unless LLDB_USE_NATIVE_PDB_READER environment "
- "variable is set",
+ "Use native PDB reader unless LLDB_USE_NATIVE_PDB_READER environment "
+ "is set to 0",
},
{
ePDBReaderDIA,
@@ -109,16 +109,10 @@ enum {
static const bool g_should_use_native_reader_by_default = [] {
llvm::StringRef env_value = ::getenv("LLDB_USE_NATIVE_PDB_READER");
-#if !LLVM_ENABLE_DIA_SDK || !defined(_WIN32)
- // if the environment value is unset, the native reader is requested
- if (env_value.empty())
- return true;
-#endif
-
- return env_value.equals_insensitive("on") ||
- env_value.equals_insensitive("yes") ||
- env_value.equals_insensitive("1") ||
- env_value.equals_insensitive("true");
+ return !env_value.equals_insensitive("off") &&
+ !env_value.equals_insensitive("no") &&
+ !env_value.equals_insensitive("0") &&
+ !env_value.equals_insensitive("false");
}();
class PluginProperties : public Properties {
@@ -293,8 +287,10 @@ uint32_t SymbolFilePDB::CalculateAbilities() {
}
void SymbolFilePDB::InitializeObject() {
- lldb::addr_t obj_load_address =
- m_objfile_sp->GetBaseAddress().GetFileAddress();
+ lldb::addr_t obj_load_address = m_objfile_sp->GetModule()
+ ->GetObjectFile()
+ ->GetBaseAddress()
+ .GetFileAddress();
lldbassert(obj_load_address && obj_load_address != LLDB_INVALID_ADDRESS);
m_session_up->setLoadAddress(obj_load_address);
if (!m_global_scope_up)
@@ -1485,7 +1481,8 @@ void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) {
if (!results)
return;
- auto section_list = m_objfile_sp->GetSectionList();
+ auto section_list =
+ m_objfile_sp->GetModule()->GetObjectFile()->GetSectionList();
if (!section_list)
return;
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/CMakeLists.txt b/lldb/source/Plugins/SyntheticFrameProvider/CMakeLists.txt
new file mode 100644
index 0000000..85b405e
--- /dev/null
+++ b/lldb/source/Plugins/SyntheticFrameProvider/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(ScriptedFrameProvider)
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/CMakeLists.txt b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/CMakeLists.txt
new file mode 100644
index 0000000..fe67d39
--- /dev/null
+++ b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_library(lldbPluginScriptedFrameProvider PLUGIN
+ ScriptedFrameProvider.cpp
+
+ LINK_COMPONENTS
+ Support
+
+ LINK_LIBS
+ lldbCore
+ lldbInterpreter
+ lldbTarget
+ lldbUtility
+ )
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp
new file mode 100644
index 0000000..739963e
--- /dev/null
+++ b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp
@@ -0,0 +1,221 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "ScriptedFrameProvider.h"
+#include "Plugins/Process/scripted/ScriptedFrame.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/BorrowedStackFrame.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ScriptedMetadata.h"
+#include "lldb/Utility/Status.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+
+using namespace lldb;
+using namespace lldb_private;
+
+void ScriptedFrameProvider::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ "Provides synthetic frames via scripting",
+ nullptr, ScriptedFrameProvider::CreateInstance);
+}
+
+void ScriptedFrameProvider::Terminate() {
+ PluginManager::UnregisterPlugin(ScriptedFrameProvider::CreateInstance);
+}
+
+llvm::Expected<lldb::SyntheticFrameProviderSP>
+ScriptedFrameProvider::CreateInstance(
+ lldb::StackFrameListSP input_frames,
+ const ScriptedFrameProviderDescriptor &descriptor) {
+ if (!input_frames)
+ return llvm::createStringError(
+ "failed to create scripted frame provider: invalid input frames");
+
+ Thread &thread = input_frames->GetThread();
+ ProcessSP process_sp = thread.GetProcess();
+ if (!process_sp)
+ return nullptr;
+
+ if (!descriptor.IsValid())
+ return llvm::createStringError(
+ "failed to create scripted frame provider: invalid scripted metadata");
+
+ if (!descriptor.AppliesToThread(thread))
+ return nullptr;
+
+ ScriptInterpreter *script_interp =
+ process_sp->GetTarget().GetDebugger().GetScriptInterpreter();
+ if (!script_interp)
+ return llvm::createStringError("cannot create scripted frame provider: No "
+ "script interpreter installed");
+
+ ScriptedFrameProviderInterfaceSP interface_sp =
+ script_interp->CreateScriptedFrameProviderInterface();
+ if (!interface_sp)
+ return llvm::createStringError(
+ "cannot create scripted frame provider: script interpreter couldn't "
+ "create Scripted Frame Provider Interface");
+
+ const ScriptedMetadataSP scripted_metadata = descriptor.scripted_metadata_sp;
+
+ // If we shouldn't attach a frame provider to this thread, just exit early.
+ if (!interface_sp->AppliesToThread(scripted_metadata->GetClassName(),
+ thread.shared_from_this()))
+ return nullptr;
+
+ auto obj_or_err = interface_sp->CreatePluginObject(
+ scripted_metadata->GetClassName(), input_frames,
+ scripted_metadata->GetArgsSP());
+ if (!obj_or_err)
+ return obj_or_err.takeError();
+
+ StructuredData::ObjectSP object_sp = *obj_or_err;
+ if (!object_sp || !object_sp->IsValid())
+ return llvm::createStringError(
+ "cannot create scripted frame provider: failed to create valid scripted"
+ "frame provider object");
+
+ return std::make_shared<ScriptedFrameProvider>(input_frames, interface_sp,
+ descriptor);
+}
+
+ScriptedFrameProvider::ScriptedFrameProvider(
+ StackFrameListSP input_frames,
+ lldb::ScriptedFrameProviderInterfaceSP interface_sp,
+ const ScriptedFrameProviderDescriptor &descriptor)
+ : SyntheticFrameProvider(input_frames), m_interface_sp(interface_sp),
+ m_descriptor(descriptor) {}
+
+ScriptedFrameProvider::~ScriptedFrameProvider() = default;
+
+std::string ScriptedFrameProvider::GetDescription() const {
+ if (!m_interface_sp)
+ return {};
+
+ return m_interface_sp->GetDescription(m_descriptor.GetName());
+}
+
+llvm::Expected<StackFrameSP>
+ScriptedFrameProvider::GetFrameAtIndex(uint32_t idx) {
+ if (!m_interface_sp)
+ return llvm::createStringError(
+ "cannot get stack frame: scripted frame provider not initialized");
+
+ auto create_frame_from_dict =
+ [this](StructuredData::Dictionary *dict,
+ uint32_t index) -> llvm::Expected<StackFrameSP> {
+ lldb::addr_t pc;
+ if (!dict->GetValueForKeyAsInteger("pc", pc))
+ return llvm::createStringError(
+ "missing 'pc' key from scripted frame dictionary");
+
+ Address symbol_addr;
+ symbol_addr.SetLoadAddress(pc, &GetThread().GetProcess()->GetTarget());
+
+ const lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
+ const bool cfa_is_valid = false;
+ const bool artificial = false;
+ const bool behaves_like_zeroth_frame = false;
+ SymbolContext sc;
+ symbol_addr.CalculateSymbolContext(&sc);
+
+ ThreadSP thread_sp = GetThread().shared_from_this();
+ return std::make_shared<StackFrame>(thread_sp, index, index, cfa,
+ cfa_is_valid, pc,
+ StackFrame::Kind::Synthetic, artificial,
+ behaves_like_zeroth_frame, &sc);
+ };
+
+ auto create_frame_from_script_object =
+ [this](
+ StructuredData::ObjectSP object_sp) -> llvm::Expected<StackFrameSP> {
+ Status error;
+ if (!object_sp || !object_sp->GetAsGeneric())
+ return llvm::createStringError("invalid script object");
+
+ ThreadSP thread_sp = GetThread().shared_from_this();
+ auto frame_or_error = ScriptedFrame::Create(thread_sp, nullptr, nullptr,
+ object_sp->GetAsGeneric());
+
+ if (!frame_or_error) {
+ ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
+ return error.ToError();
+ }
+
+ return *frame_or_error;
+ };
+
+ StructuredData::ObjectSP obj_sp = m_interface_sp->GetFrameAtIndex(idx);
+
+ // None/null means no more frames or error.
+ if (!obj_sp || !obj_sp->IsValid())
+ return llvm::createStringError("invalid script object returned for frame " +
+ llvm::Twine(idx));
+
+ StackFrameSP synth_frame_sp = nullptr;
+ if (StructuredData::UnsignedInteger *int_obj =
+ obj_sp->GetAsUnsignedInteger()) {
+ uint32_t real_frame_index = int_obj->GetValue();
+ if (real_frame_index < m_input_frames->GetNumFrames()) {
+ StackFrameSP real_frame_sp =
+ m_input_frames->GetFrameAtIndex(real_frame_index);
+ synth_frame_sp =
+ (real_frame_index == idx)
+ ? real_frame_sp
+ : std::make_shared<BorrowedStackFrame>(real_frame_sp, idx);
+ }
+ } else if (StructuredData::Dictionary *dict = obj_sp->GetAsDictionary()) {
+ // Check if it's a dictionary describing a frame.
+ auto frame_from_dict_or_err = create_frame_from_dict(dict, idx);
+ if (!frame_from_dict_or_err) {
+ return llvm::createStringError(llvm::Twine(
+ "couldn't create frame from dictionary at index " + llvm::Twine(idx) +
+ ": " + toString(frame_from_dict_or_err.takeError())));
+ }
+ synth_frame_sp = *frame_from_dict_or_err;
+ } else if (obj_sp->GetAsGeneric()) {
+ // It's a ScriptedFrame object.
+ auto frame_from_script_obj_or_err = create_frame_from_script_object(obj_sp);
+ if (!frame_from_script_obj_or_err) {
+ return llvm::createStringError(
+ llvm::Twine("couldn't create frame from script object at index " +
+ llvm::Twine(idx) + ": " +
+ toString(frame_from_script_obj_or_err.takeError())));
+ }
+ synth_frame_sp = *frame_from_script_obj_or_err;
+ } else {
+ return llvm::createStringError(
+ llvm::Twine("invalid return type from get_frame_at_index at index " +
+ llvm::Twine(idx)));
+ }
+
+ if (!synth_frame_sp)
+ return llvm::createStringError(
+ llvm::Twine("failed to create frame at index " + llvm::Twine(idx)));
+
+ synth_frame_sp->SetFrameIndex(idx);
+
+ return synth_frame_sp;
+}
+
+namespace lldb_private {
+void lldb_initialize_ScriptedFrameProvider() {
+ ScriptedFrameProvider::Initialize();
+}
+
+void lldb_terminate_ScriptedFrameProvider() {
+ ScriptedFrameProvider::Terminate();
+}
+} // namespace lldb_private
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.h b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.h
new file mode 100644
index 0000000..3434bf2
--- /dev/null
+++ b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.h
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SYNTHETICFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_H
+#define LLDB_PLUGINS_SYNTHETICFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_H
+
+#include "lldb/Target/SyntheticFrameProvider.h"
+#include "lldb/Utility/ScriptedMetadata.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/Support/Error.h"
+
+namespace lldb_private {
+
+class ScriptedFrameProvider : public SyntheticFrameProvider {
+public:
+ static llvm::StringRef GetPluginNameStatic() {
+ return "ScriptedFrameProvider";
+ }
+
+ static llvm::Expected<lldb::SyntheticFrameProviderSP>
+ CreateInstance(lldb::StackFrameListSP input_frames,
+ const ScriptedFrameProviderDescriptor &descriptor);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ ScriptedFrameProvider(lldb::StackFrameListSP input_frames,
+ lldb::ScriptedFrameProviderInterfaceSP interface_sp,
+ const ScriptedFrameProviderDescriptor &descriptor);
+ ~ScriptedFrameProvider() override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ std::string GetDescription() const override;
+
+ /// Get a single stack frame at the specified index.
+ llvm::Expected<lldb::StackFrameSP> GetFrameAtIndex(uint32_t idx) override;
+
+private:
+ lldb::ScriptedFrameProviderInterfaceSP m_interface_sp;
+ const ScriptedFrameProviderDescriptor &m_descriptor;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_PLUGINS_SYNTHETICFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_H
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 82dfe7e..625d0e5 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1000,6 +1000,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize(
case DW_ATE_signed:
if (!type_name.empty()) {
+ if (type_name.starts_with("_BitInt"))
+ return GetType(ast.getBitIntType(/*Unsigned=*/false, bit_size));
if (type_name == "wchar_t" &&
QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy) &&
(getTargetInfo() &&
@@ -1056,6 +1058,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize(
case DW_ATE_unsigned:
if (!type_name.empty()) {
+ if (type_name.starts_with("unsigned _BitInt"))
+ return GetType(ast.getBitIntType(/*Unsigned=*/true, bit_size));
if (type_name == "wchar_t") {
if (QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy)) {
if (!(getTargetInfo() &&
@@ -1693,6 +1697,11 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
class_template_specialization_decl->setInstantiationOf(class_template_decl);
class_template_specialization_decl->setTemplateArgs(
TemplateArgumentList::CreateCopy(ast, args));
+ void *insert_pos = nullptr;
+ if (class_template_decl->findSpecialization(args, insert_pos))
+ return nullptr;
+ class_template_decl->AddSpecialization(class_template_specialization_decl,
+ insert_pos);
class_template_specialization_decl->setDeclName(
class_template_decl->getDeclName());
@@ -2140,7 +2149,8 @@ PrintingPolicy TypeSystemClang::GetTypePrintingPolicy() {
printing_policy.SuppressTagKeyword = true;
// Inline namespaces are important for some type formatters (e.g., libc++
// and libstdc++ are differentiated by their inline namespaces).
- printing_policy.SuppressInlineNamespace = false;
+ printing_policy.SuppressInlineNamespace =
+ llvm::to_underlying(PrintingPolicy::SuppressInlineNamespaceMode::None);
printing_policy.SuppressUnwrittenScope = false;
// Default arguments are also always important for type formatters. Otherwise
// we would need to always specify two type names for the setups where we do
@@ -3483,7 +3493,7 @@ bool TypeSystemClang::IsReferenceType(lldb::opaque_compiler_type_t type,
}
bool TypeSystemClang::IsFloatingPointType(lldb::opaque_compiler_type_t type,
- uint32_t &count, bool &is_complex) {
+ bool &is_complex) {
if (type) {
clang::QualType qual_type(GetCanonicalQualType(type));
@@ -3492,30 +3502,26 @@ bool TypeSystemClang::IsFloatingPointType(lldb::opaque_compiler_type_t type,
clang::BuiltinType::Kind kind = BT->getKind();
if (kind >= clang::BuiltinType::Float &&
kind <= clang::BuiltinType::LongDouble) {
- count = 1;
is_complex = false;
return true;
}
} else if (const clang::ComplexType *CT =
llvm::dyn_cast<clang::ComplexType>(
qual_type->getCanonicalTypeInternal())) {
- if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count,
+ if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(),
is_complex)) {
- count = 2;
is_complex = true;
return true;
}
} else if (const clang::VectorType *VT = llvm::dyn_cast<clang::VectorType>(
qual_type->getCanonicalTypeInternal())) {
- if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count,
+ if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(),
is_complex)) {
- count = VT->getNumElements();
is_complex = false;
return true;
}
}
}
- count = 0;
is_complex = false;
return false;
}
@@ -3865,7 +3871,8 @@ TypeSystemClang::GetDisplayTypeName(lldb::opaque_compiler_type_t type) {
printing_policy.SuppressTagKeyword = true;
printing_policy.SuppressScope = false;
printing_policy.SuppressUnwrittenScope = true;
- printing_policy.SuppressInlineNamespace = true;
+ printing_policy.SuppressInlineNamespace =
+ llvm::to_underlying(PrintingPolicy::SuppressInlineNamespaceMode::All);
return ConstString(qual_type.getAsString(printing_policy));
}
@@ -3888,6 +3895,13 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type,
->getModifiedType()
.getAsOpaquePtr(),
pointee_or_element_clang_type);
+ case clang::Type::BitInt: {
+ uint32_t type_flags = eTypeIsScalar | eTypeIsInteger | eTypeHasValue;
+ if (qual_type->isSignedIntegerType())
+ type_flags |= eTypeIsSigned;
+
+ return type_flags;
+ }
case clang::Type::Builtin: {
const clang::BuiltinType *builtin_type =
llvm::cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal());
@@ -3960,9 +3974,9 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type,
if (complex_type) {
clang::QualType complex_element_type(complex_type->getElementType());
if (complex_element_type->isIntegerType())
- complex_type_flags |= eTypeIsFloat;
- else if (complex_element_type->isFloatingType())
complex_type_flags |= eTypeIsInteger;
+ else if (complex_element_type->isFloatingType())
+ complex_type_flags |= eTypeIsFloat;
}
return complex_type_flags;
} break;
@@ -4057,12 +4071,17 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type,
uint32_t vector_type_flags = eTypeHasChildren | eTypeIsVector;
const clang::VectorType *vector_type = llvm::dyn_cast<clang::VectorType>(
qual_type->getCanonicalTypeInternal());
- if (vector_type) {
- if (vector_type->isIntegerType())
- vector_type_flags |= eTypeIsFloat;
- else if (vector_type->isFloatingType())
- vector_type_flags |= eTypeIsInteger;
- }
+ if (!vector_type)
+ return 0;
+
+ QualType element_type = vector_type->getElementType();
+ if (element_type.isNull())
+ return 0;
+
+ if (element_type->isIntegerType())
+ vector_type_flags |= eTypeIsInteger;
+ else if (element_type->isFloatingType())
+ vector_type_flags |= eTypeIsFloat;
return vector_type_flags;
}
default:
@@ -4859,12 +4878,10 @@ TypeSystemClang::GetTypeBitAlign(lldb::opaque_compiler_type_t type,
return {};
}
-lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
- uint64_t &count) {
+lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type) {
if (!type)
return lldb::eEncodingInvalid;
- count = 1;
clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
switch (qual_type->getTypeClass()) {
@@ -4898,7 +4915,6 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
case clang::Type::DependentVector:
case clang::Type::ExtVector:
case clang::Type::Vector:
- // TODO: Set this to more than one???
break;
case clang::Type::BitInt:
@@ -5099,11 +5115,10 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
const clang::ComplexType *complex_type =
qual_type->getAsComplexIntegerType();
if (complex_type)
- encoding = GetType(complex_type->getElementType()).GetEncoding(count);
+ encoding = GetType(complex_type->getElementType()).GetEncoding();
else
encoding = lldb::eEncodingSint;
}
- count = 2;
return encoding;
}
@@ -5160,7 +5175,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
case clang::Type::SubstBuiltinTemplatePack:
break;
}
- count = 0;
+
return lldb::eEncodingInvalid;
}
@@ -7333,6 +7348,102 @@ CompilerType TypeSystemClang::GetTypeForFormatters(void *type) {
return CompilerType();
}
+bool TypeSystemClang::IsPromotableIntegerType(
+ lldb::opaque_compiler_type_t type) {
+ // Unscoped enums are always considered as promotable, even if their
+ // underlying type does not need to be promoted (e.g. "int").
+ bool is_signed = false;
+ bool isUnscopedEnumerationType =
+ IsEnumerationType(type, is_signed) && !IsScopedEnumerationType(type);
+ if (isUnscopedEnumerationType)
+ return true;
+
+ switch (GetBasicTypeEnumeration(type)) {
+ case lldb::eBasicTypeBool:
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ case lldb::eBasicTypeShort:
+ case lldb::eBasicTypeUnsignedShort:
+ case lldb::eBasicTypeWChar:
+ case lldb::eBasicTypeSignedWChar:
+ case lldb::eBasicTypeUnsignedWChar:
+ case lldb::eBasicTypeChar16:
+ case lldb::eBasicTypeChar32:
+ return true;
+
+ default:
+ return false;
+ }
+
+ llvm_unreachable("All cases handled above.");
+}
+
+llvm::Expected<CompilerType>
+TypeSystemClang::DoIntegralPromotion(CompilerType from,
+ ExecutionContextScope *exe_scope) {
+ if (!from.IsInteger() && !from.IsUnscopedEnumerationType())
+ return from;
+
+ if (!from.IsPromotableIntegerType())
+ return from;
+
+ if (from.IsUnscopedEnumerationType()) {
+ EnumDecl *enum_decl = GetAsEnumDecl(from);
+ CompilerType promotion_type = GetType(enum_decl->getPromotionType());
+ return DoIntegralPromotion(promotion_type, exe_scope);
+ }
+
+ lldb::BasicType builtin_type =
+ from.GetCanonicalType().GetBasicTypeEnumeration();
+ uint64_t from_size = 0;
+ if (builtin_type == lldb::eBasicTypeWChar ||
+ builtin_type == lldb::eBasicTypeSignedWChar ||
+ builtin_type == lldb::eBasicTypeUnsignedWChar ||
+ builtin_type == lldb::eBasicTypeChar16 ||
+ builtin_type == lldb::eBasicTypeChar32) {
+ // Find the type that can hold the entire range of values for our type.
+ bool is_signed = from.IsSigned();
+ llvm::Expected<uint64_t> from_size = from.GetByteSize(exe_scope);
+ if (!from_size)
+ return from_size.takeError();
+ CompilerType promote_types[] = {
+ GetBasicTypeFromAST(lldb::eBasicTypeInt),
+ GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt),
+ GetBasicTypeFromAST(lldb::eBasicTypeLong),
+ GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLong),
+ GetBasicTypeFromAST(lldb::eBasicTypeLongLong),
+ GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLongLong),
+ };
+ for (CompilerType &type : promote_types) {
+ llvm::Expected<uint64_t> byte_size = type.GetByteSize(exe_scope);
+ if (!byte_size)
+ return byte_size.takeError();
+ if (*from_size < *byte_size ||
+ (*from_size == *byte_size && is_signed == type.IsSigned())) {
+ return type;
+ }
+ }
+ llvm_unreachable("char type should fit into long long");
+ }
+
+ // Here we can promote only to "int" or "unsigned int".
+ CompilerType int_type = GetBasicTypeFromAST(lldb::eBasicTypeInt);
+ llvm::Expected<uint64_t> int_byte_size = int_type.GetByteSize(exe_scope);
+ if (!int_byte_size)
+ return int_byte_size.takeError();
+
+ // Signed integer types can be safely promoted to "int".
+ if (from.IsSigned()) {
+ return int_type;
+ }
+ // Unsigned integer types are promoted to "unsigned int" if "int" cannot hold
+ // their entire value range.
+ return (from_size == *int_byte_size)
+ ? GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt)
+ : int_type;
+}
+
clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) {
const clang::EnumType *enutype =
llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type));
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 9e0a542..67d206e 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -651,7 +651,7 @@ public:
bool IsDefined(lldb::opaque_compiler_type_t type) override;
- bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count,
+ bool IsFloatingPointType(lldb::opaque_compiler_type_t type,
bool &is_complex) override;
unsigned GetPtrAuthKey(lldb::opaque_compiler_type_t type) override;
@@ -837,8 +837,7 @@ public:
GetBitSize(lldb::opaque_compiler_type_t type,
ExecutionContextScope *exe_scope) override;
- lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type,
- uint64_t &count) override;
+ lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type) override;
lldb::Format GetFormat(lldb::opaque_compiler_type_t type) override;
@@ -939,6 +938,14 @@ public:
CompilerType GetTypeForFormatters(void *type) override;
+ // DIL
+
+ bool IsPromotableIntegerType(lldb::opaque_compiler_type_t type) override;
+
+ llvm::Expected<CompilerType>
+ DoIntegralPromotion(CompilerType from,
+ ExecutionContextScope *exe_scope) override;
+
#define LLDB_INVALID_DECL_LEVEL UINT32_MAX
// LLDB_INVALID_DECL_LEVEL is returned by CountDeclLevels if child_decl_ctx
// could not be found in decl_ctx.
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index 397c693..19ae1cf 100644
--- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -25,6 +25,8 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/SmallSet.h"
+#include <deque>
using namespace lldb;
using namespace lldb_private;
@@ -50,6 +52,33 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
range, function_text.data(), function_text.size(), unwind_plan);
}
+static void DumpUnwindRowsToLog(Log *log, AddressRange range,
+ const UnwindPlan &unwind_plan) {
+ if (!log || !log->GetVerbose())
+ return;
+ StreamString strm;
+ lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
+ strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
+ base_addr, base_addr + range.GetByteSize());
+ unwind_plan.Dump(strm, nullptr, base_addr);
+ log->PutString(strm.GetString());
+}
+
+static void DumpInstToLog(Log *log, Instruction &inst,
+ const InstructionList &inst_list) {
+ if (!log || !log->GetVerbose())
+ return;
+ const bool show_address = true;
+ const bool show_bytes = true;
+ const bool show_control_flow_kind = false;
+ StreamString strm;
+ lldb_private::FormatEntity::Entry format;
+ FormatEntity::Parse("${frame.pc}: ", format);
+ inst.Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address, show_bytes,
+ show_control_flow_kind, nullptr, nullptr, nullptr, &format, 0);
+ log->PutString(strm.GetString());
+}
+
bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
AddressRange &range, uint8_t *opcode_data, size_t opcode_size,
UnwindPlan &unwind_plan) {
@@ -82,11 +111,6 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
m_range_ptr = &range;
m_unwind_plan_ptr = &unwind_plan;
- const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
- const bool show_address = true;
- const bool show_bytes = true;
- const bool show_control_flow_kind = false;
-
m_state.cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(
unwind_plan.GetRegisterKind(), unwind_plan.GetInitialCFARegister());
m_state.fp_is_cfa = false;
@@ -94,134 +118,142 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
m_pushed_regs.clear();
- // Initialize the CFA with a known value. In the 32 bit case it will be
- // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the address
- // byte size to be safe for any future address sizes
- m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
RegisterValue cfa_reg_value;
- cfa_reg_value.SetUInt(m_initial_sp, m_state.cfa_reg_info.byte_size);
+ cfa_reg_value.SetUInt(m_initial_cfa, m_state.cfa_reg_info.byte_size);
SetRegisterValue(m_state.cfa_reg_info, cfa_reg_value);
- const InstructionList &inst_list = disasm_sp->GetInstructionList();
- const size_t num_instructions = inst_list.GetSize();
-
- if (num_instructions > 0) {
- Instruction *inst = inst_list.GetInstructionAtIndex(0).get();
- const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
-
- // Map for storing the unwind state at a given offset. When we see a forward
- // branch we add a new entry to this map with the actual unwind plan row and
- // register context for the target address of the branch as the current data
- // have to be valid for the target address of the branch too if we are in
- // the same function.
- std::map<lldb::addr_t, UnwindState> saved_unwind_states;
-
- // Make a copy of the current instruction Row and save it in m_state so
- // we can add updates as we process the instructions.
- m_state.row = *unwind_plan.GetLastRow();
-
- // Add the initial state to the save list with offset 0.
- auto condition_block_start_state =
- saved_unwind_states.emplace(0, m_state).first;
-
- // The architecture dependent condition code of the last processed
- // instruction.
- EmulateInstruction::InstructionCondition last_condition =
- EmulateInstruction::UnconditionalCondition;
-
- for (size_t idx = 0; idx < num_instructions; ++idx) {
- m_curr_row_modified = false;
- m_forward_branch_offset = 0;
-
- inst = inst_list.GetInstructionAtIndex(idx).get();
- if (!inst)
- continue;
-
- lldb::addr_t current_offset =
- inst->GetAddress().GetFileAddress() - base_addr;
- auto it = saved_unwind_states.upper_bound(current_offset);
- assert(it != saved_unwind_states.begin() &&
- "Unwind row for the function entry missing");
- --it; // Move it to the row corresponding to the current offset
-
- // If the offset of m_curr_row don't match with the offset we see in
- // saved_unwind_states then we have to update current unwind state to
- // the saved values. It is happening after we processed an epilogue and a
- // return to caller instruction.
- if (it->second.row.GetOffset() != m_state.row.GetOffset())
- m_state = it->second;
-
- m_inst_emulator_up->SetInstruction(inst->GetOpcode(), inst->GetAddress(),
- nullptr);
-
- if (last_condition != m_inst_emulator_up->GetInstructionCondition()) {
- // If the last instruction was conditional with a different condition
- // than the current condition then restore the state.
- if (last_condition != EmulateInstruction::UnconditionalCondition) {
- m_state = condition_block_start_state->second;
- m_state.row.SetOffset(current_offset);
- // The last instruction might already created a row for this offset
- // and we want to overwrite it.
- saved_unwind_states.insert_or_assign(current_offset, m_state);
- }
+ InstructionList inst_list = disasm_sp->GetInstructionList();
- // We are starting a new conditional block at the actual offset
- condition_block_start_state = it;
- }
+ if (inst_list.GetSize() == 0) {
+ DumpUnwindRowsToLog(log, range, unwind_plan);
+ return unwind_plan.GetRowCount() > 0;
+ }
- if (log && log->GetVerbose()) {
- StreamString strm;
- lldb_private::FormatEntity::Entry format;
- FormatEntity::Parse("${frame.pc}: ", format);
- inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
- show_bytes, show_control_flow_kind, nullptr, nullptr,
- nullptr, &format, 0);
- log->PutString(strm.GetString());
- }
+ Instruction &first_inst = *inst_list.GetInstructionAtIndex(0);
+ const lldb::addr_t base_addr = first_inst.GetAddress().GetFileAddress();
+
+ // Map for storing the unwind state at a given offset. When we see a forward
+ // branch we add a new entry to this map with the actual unwind plan row and
+ // register context for the target address of the branch as the current data
+ // have to be valid for the target address of the branch too if we are in
+ // the same function.
+ std::map<lldb::addr_t, UnwindState> saved_unwind_states;
- last_condition = m_inst_emulator_up->GetInstructionCondition();
+ // Make a copy of the current instruction Row and save it in m_state so
+ // we can add updates as we process the instructions.
+ m_state.row = *unwind_plan.GetLastRow();
- m_inst_emulator_up->EvaluateInstruction(
- eEmulateInstructionOptionIgnoreConditions);
+ // Add the initial state to the save list with offset 0.
+ auto condition_block_start_state =
+ saved_unwind_states.emplace(0, m_state).first;
- // If the current instruction is a branch forward then save the current
- // CFI information for the offset where we are branching.
- if (m_forward_branch_offset != 0 &&
- range.ContainsFileAddress(inst->GetAddress().GetFileAddress() +
- m_forward_branch_offset)) {
- if (auto [it, inserted] = saved_unwind_states.emplace(
- current_offset + m_forward_branch_offset, m_state);
- inserted)
- it->second.row.SetOffset(current_offset + m_forward_branch_offset);
+ // The architecture dependent condition code of the last processed
+ // instruction.
+ EmulateInstruction::InstructionCondition last_condition =
+ EmulateInstruction::UnconditionalCondition;
+
+ std::deque<std::size_t> to_visit = {0};
+ llvm::SmallSet<std::size_t, 0> enqueued = {0};
+
+ // Instructions reachable through jumps are inserted on the front.
+ // The next instruction is inserted on the back.
+ // Pop from the back to ensure non-branching instructions are visited
+ // sequentially.
+ while (!to_visit.empty()) {
+ const std::size_t current_index = to_visit.back();
+ Instruction &inst = *inst_list.GetInstructionAtIndex(current_index);
+ to_visit.pop_back();
+ DumpInstToLog(log, inst, inst_list);
+
+ m_curr_row_modified = false;
+ m_branch_offset = 0;
+
+ lldb::addr_t current_offset =
+ inst.GetAddress().GetFileAddress() - base_addr;
+ auto it = saved_unwind_states.upper_bound(current_offset);
+ assert(it != saved_unwind_states.begin() &&
+ "Unwind row for the function entry missing");
+ --it; // Move it to the row corresponding to the current offset
+
+ // When state is forwarded through a branch, the offset of m_state.row is
+ // different from the offset available in saved_unwind_states. Use the
+ // forwarded state in this case, as the previous instruction may have been
+ // an unconditional jump.
+ // FIXME: this assignment can always be done unconditionally.
+ if (it->second.row.GetOffset() != m_state.row.GetOffset())
+ m_state = it->second;
+
+ m_inst_emulator_up->SetInstruction(inst.GetOpcode(), inst.GetAddress(),
+ nullptr);
+ const EmulateInstruction::InstructionCondition new_condition =
+ m_inst_emulator_up->GetInstructionCondition();
+
+ if (last_condition != new_condition) {
+ // If the last instruction was conditional with a different condition
+ // than the current condition then restore the state.
+ if (last_condition != EmulateInstruction::UnconditionalCondition) {
+ m_state = condition_block_start_state->second;
+ m_state.row.SetOffset(current_offset);
+ // The last instruction might already created a row for this offset
+ // and we want to overwrite it.
+ saved_unwind_states.insert_or_assign(current_offset, m_state);
}
- // Were there any changes to the CFI while evaluating this instruction?
- if (m_curr_row_modified) {
- // Save the modified row if we don't already have a CFI row in the
- // current address
- if (saved_unwind_states.count(current_offset +
- inst->GetOpcode().GetByteSize()) == 0) {
- m_state.row.SetOffset(current_offset +
- inst->GetOpcode().GetByteSize());
- saved_unwind_states.emplace(
- current_offset + inst->GetOpcode().GetByteSize(), m_state);
+ // We are starting a new conditional block at the actual offset
+ condition_block_start_state = it;
+ }
+
+ last_condition = new_condition;
+
+ m_inst_emulator_up->EvaluateInstruction(
+ eEmulateInstructionOptionIgnoreConditions);
+
+ // If the current instruction is a branch forward then save the current
+ // CFI information for the offset where we are branching.
+ Address branch_address = inst.GetAddress();
+ branch_address.Slide(m_branch_offset);
+ if (m_branch_offset != 0 &&
+ range.ContainsFileAddress(branch_address.GetFileAddress())) {
+ if (auto [it, inserted] = saved_unwind_states.emplace(
+ current_offset + m_branch_offset, m_state);
+ inserted) {
+ it->second.row.SetOffset(current_offset + m_branch_offset);
+ if (std::size_t dest_instr_index =
+ inst_list.GetIndexOfInstructionAtAddress(branch_address);
+ dest_instr_index < inst_list.GetSize()) {
+ to_visit.push_front(dest_instr_index);
+ enqueued.insert(dest_instr_index);
}
}
}
- for (auto &[_, state] : saved_unwind_states) {
- unwind_plan.InsertRow(std::move(state.row),
- /*replace_existing=*/true);
+
+ // If inst is a barrier, do not propagate state to the next instruction.
+ if (inst.IsBarrier())
+ continue;
+
+ // Were there any changes to the CFI while evaluating this instruction?
+ if (m_curr_row_modified) {
+ // Save the modified row if we don't already have a CFI row in the
+ // current address
+ const lldb::addr_t next_inst_offset =
+ current_offset + inst.GetOpcode().GetByteSize();
+ if (saved_unwind_states.count(next_inst_offset) == 0) {
+ m_state.row.SetOffset(next_inst_offset);
+ saved_unwind_states.emplace(next_inst_offset, m_state);
+ }
}
- }
- if (log && log->GetVerbose()) {
- StreamString strm;
- lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
- strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
- base_addr, base_addr + range.GetByteSize());
- unwind_plan.Dump(strm, nullptr, base_addr);
- log->PutString(strm.GetString());
+ const size_t next_idx = current_index + 1;
+ const bool never_enqueued = enqueued.insert(next_idx).second;
+ if (never_enqueued && next_idx < inst_list.GetSize())
+ to_visit.push_back(next_idx);
}
+
+ for (auto &[_, state] : saved_unwind_states)
+ unwind_plan.InsertRow(std::move(state.row),
+ /*replace_existing=*/true);
+
+ DumpUnwindRowsToLog(log, range, unwind_plan);
return unwind_plan.GetRowCount() > 0;
}
@@ -382,7 +414,7 @@ size_t UnwindAssemblyInstEmulation::WriteMemory(
if (reg_num != LLDB_INVALID_REGNUM &&
generic_regnum != LLDB_REGNUM_GENERIC_SP) {
if (m_pushed_regs.try_emplace(reg_num, addr).second) {
- const int32_t offset = addr - m_initial_sp;
+ const int32_t offset = addr - m_initial_cfa;
m_state.row.SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,
/*can_replace=*/true);
m_curr_row_modified = true;
@@ -502,21 +534,20 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
case EmulateInstruction::eContextAbsoluteBranchRegister:
case EmulateInstruction::eContextRelativeBranchImmediate: {
if (context.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate &&
- context.info.ISAAndImmediate.unsigned_data32 > 0) {
- m_forward_branch_offset =
- context.info.ISAAndImmediateSigned.signed_data32;
+ context.info.ISAAndImmediate.unsigned_data32 != 0) {
+ m_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
} else if (context.GetInfoType() ==
EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
- context.info.ISAAndImmediateSigned.signed_data32 > 0) {
- m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
+ context.info.ISAAndImmediateSigned.signed_data32 != 0) {
+ m_branch_offset = context.info.ISAAndImmediateSigned.signed_data32;
} else if (context.GetInfoType() ==
EmulateInstruction::eInfoTypeImmediate &&
- context.info.unsigned_immediate > 0) {
- m_forward_branch_offset = context.info.unsigned_immediate;
+ context.info.unsigned_immediate != 0) {
+ m_branch_offset = context.info.unsigned_immediate;
} else if (context.GetInfoType() ==
EmulateInstruction::eInfoTypeImmediateSigned &&
- context.info.signed_immediate > 0) {
- m_forward_branch_offset = context.info.signed_immediate;
+ context.info.signed_immediate != 0) {
+ m_branch_offset = context.info.signed_immediate;
}
} break;
@@ -549,7 +580,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
sp_reg_info.kinds[m_unwind_plan_ptr->GetRegisterKind()];
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
- cfa_reg_num, m_initial_sp - sp_reg_val.GetAsUInt64());
+ cfa_reg_num, m_initial_cfa - sp_reg_val.GetAsUInt64());
}
}
}
@@ -580,7 +611,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
- cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
+ cfa_reg_num, m_initial_cfa - reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
@@ -593,7 +624,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
- cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
+ cfa_reg_num, m_initial_cfa - reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
@@ -604,7 +635,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
if (!m_state.fp_is_cfa) {
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
m_state.row.GetCFAValue().GetRegisterNumber(),
- m_initial_sp - reg_value.GetAsUInt64());
+ m_initial_cfa - reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
index 96a0881..43daf1c 100644
--- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
+++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -63,13 +63,17 @@ private:
UnwindAssemblyInstEmulation(const lldb_private::ArchSpec &arch,
lldb_private::EmulateInstruction *inst_emulator)
: UnwindAssembly(arch), m_inst_emulator_up(inst_emulator),
- m_range_ptr(nullptr), m_unwind_plan_ptr(nullptr), m_initial_sp(0),
- m_curr_row_modified(false), m_forward_branch_offset(0) {
+ m_range_ptr(nullptr), m_unwind_plan_ptr(nullptr),
+ m_curr_row_modified(false) {
if (m_inst_emulator_up) {
m_inst_emulator_up->SetBaton(this);
m_inst_emulator_up->SetCallbacks(ReadMemory, WriteMemory, ReadRegister,
WriteRegister);
}
+ // Initialize the CFA with a known value. In the 32 bit case it will be
+ // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the address
+ // byte size to be safe for any future address sizes
+ m_initial_cfa = (1ull << ((m_arch.GetAddressByteSize() * 8) - 1));
}
static size_t
@@ -134,8 +138,8 @@ private:
lldb_private::AddressRange *m_range_ptr;
lldb_private::UnwindPlan *m_unwind_plan_ptr;
UnwindState m_state;
+ uint64_t m_initial_cfa;
typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap;
- uint64_t m_initial_sp;
PushedRegisterToAddrMap m_pushed_regs;
// While processing the instruction stream, we need to communicate some state
@@ -148,7 +152,7 @@ private:
bool m_curr_row_modified;
// The instruction is branching forward with the given offset. 0 value means
// no branching.
- uint32_t m_forward_branch_offset;
+ int64_t m_branch_offset = 0;
};
#endif // LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_INSTEMULATION_UNWINDASSEMBLYINSTEMULATION_H