diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins')
259 files changed, 11945 insertions, 10129 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp index 8dee6b48453a..d36aeca21c69 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -39,6 +39,12 @@ ABIAArch64::GetEHAndDWARFNums(llvm::StringRef name) { return MCBasedABI::GetEHAndDWARFNums(name); } +std::string ABIAArch64::GetMCName(std::string reg) { + MapRegisterName(reg, "v", "q"); + MapRegisterName(reg, "x29", "fp"); + MapRegisterName(reg, "x30", "lr"); + return reg; +} uint32_t ABIAArch64::GetGenericNum(llvm::StringRef name) { return llvm::StringSwitch<uint32_t>(name) .Case("pc", LLDB_REGNUM_GENERIC_PC) diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h index 981145e2017e..bdff648f1b52 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h @@ -20,10 +20,7 @@ protected: std::pair<uint32_t, uint32_t> GetEHAndDWARFNums(llvm::StringRef name) override; - std::string GetMCName(std::string reg) override { - MapRegisterName(reg, "v", "q"); - return reg; - } + std::string GetMCName(std::string reg) override; uint32_t GetGenericNum(llvm::StringRef name) override; diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp index 983da26a2a6d..09b319a84a08 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp @@ -492,7 +492,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( uint32_t &NGRN, // NGRN (see ABI documentation) uint32_t &NSRN, // NSRN (see ABI documentation) DataExtractor &data) { - llvm::Optional<uint64_t> byte_size = value_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> byte_size = + value_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (!byte_size || *byte_size == 0) return false; @@ -509,7 +510,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { if (!base_type) return false; - llvm::Optional<uint64_t> base_byte_size = base_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> base_byte_size = + base_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (!base_byte_size) return false; uint32_t data_offset = 0; @@ -646,7 +648,7 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( return return_valobj_sp; llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index 831c8aa0d760..1214195dcfc0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -466,7 +466,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( uint32_t &NGRN, // NGRN (see ABI documentation) uint32_t &NSRN, // NSRN (see ABI documentation) DataExtractor &data) { - llvm::Optional<uint64_t> byte_size = value_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> byte_size = + value_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (byte_size || *byte_size == 0) return false; @@ -484,7 +485,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { if (!base_type) return false; - llvm::Optional<uint64_t> base_byte_size = base_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> base_byte_size = + base_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (!base_byte_size) return false; uint32_t data_offset = 0; @@ -614,7 +616,7 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( return return_valobj_sp; llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp index a212eef2ab8a..be8586722d8f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp @@ -272,7 +272,8 @@ bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t pc, reg_value[byte_index++] = 0; } - RegisterValue reg_val_obj(reg_value, reg_size, eByteOrderLittle); + RegisterValue reg_val_obj(llvm::makeArrayRef(reg_value, reg_size), + eByteOrderLittle); if (!reg_ctx->WriteRegister( reg_ctx->GetRegisterInfo(eRegisterKindGeneric, reg_index), reg_val_obj)) @@ -458,7 +459,7 @@ ABISysV_arc::GetReturnValueObjectSimple(Thread &thread, const uint32_t type_flags = compiler_type.GetTypeInfo(); // Integer return type. if (type_flags & eTypeIsInteger) { - const size_t byte_size = compiler_type.GetByteSize(nullptr).getValueOr(0); + const size_t byte_size = compiler_type.GetByteSize(&thread).getValueOr(0); auto raw_value = ReadRawValue(reg_ctx, byte_size); const bool is_signed = (type_flags & eTypeIsSigned) != 0; @@ -482,7 +483,7 @@ ABISysV_arc::GetReturnValueObjectSimple(Thread &thread, if (compiler_type.IsFloatingPointType(float_count, is_complex) && 1 == float_count && !is_complex) { - const size_t byte_size = compiler_type.GetByteSize(nullptr).getValueOr(0); + const size_t byte_size = compiler_type.GetByteSize(&thread).getValueOr(0); auto raw_value = ReadRawValue(reg_ctx, byte_size); if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size)) diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp index ef500cb198a8..06c4590b7740 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp @@ -34,7 +34,7 @@ using namespace lldb; using namespace lldb_private; -static RegisterInfo g_register_infos[] = { +static const RegisterInfo g_register_infos[] = { // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME // DWARF GENERIC PROCESS PLUGIN // LLDB NATIVE @@ -1292,24 +1292,9 @@ static RegisterInfo g_register_infos[] = { static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * ABIMacOSX_arm::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } count = k_num_register_infos; return g_register_infos; } diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp index 1a93bac564f7..26b3152bed16 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp @@ -36,7 +36,7 @@ using namespace lldb_private; LLDB_PLUGIN_DEFINE(ABISysV_arm) -static RegisterInfo g_register_infos[] = { +static const RegisterInfo g_register_infos[] = { // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME // DWARF GENERIC PROCESS PLUGIN // LLDB NATIVE VALUE REGS INVALIDATE REGS @@ -1295,24 +1295,9 @@ static RegisterInfo g_register_infos[] = { static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * ABISysV_arm::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } count = k_num_register_infos; return g_register_infos; } @@ -1718,7 +1703,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( if (homogeneous_count > 0 && homogeneous_count <= 4) { llvm::Optional<uint64_t> base_byte_size = - base_type.GetByteSize(nullptr); + base_type.GetByteSize(&thread); if (base_type.IsVectorType(nullptr, nullptr)) { if (base_byte_size && (*base_byte_size == 8 || *base_byte_size == 16)) { @@ -1747,7 +1732,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( if (base_type.IsFloatingPointType(float_count, is_complex)) { llvm::Optional<uint64_t> base_byte_size = - base_type.GetByteSize(nullptr); + base_type.GetByteSize(&thread); if (float_count == 2 && is_complex) { if (index != 0 && base_byte_size && vfp_byte_size != *base_byte_size) diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp index 32313d4cd815..47aaefd3b228 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp @@ -34,7 +34,7 @@ using namespace lldb_private; LLDB_PLUGIN_DEFINE_ADV(ABISysV_hexagon, ABIHexagon) -static RegisterInfo g_register_infos[] = { +static const RegisterInfo g_register_infos[] = { // hexagon-core.xml {"r00", "", @@ -974,24 +974,9 @@ static RegisterInfo g_register_infos[] = { static const uint32_t k_num_register_infos = sizeof(g_register_infos) / sizeof(RegisterInfo); -static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * ABISysV_hexagon::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } count = k_num_register_infos; return g_register_infos; } diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp index bb28a50e5f4a..751555722dac 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp @@ -753,7 +753,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( const ArchSpec target_arch = target->GetArchitecture(); ByteOrder target_byte_order = target_arch.GetByteOrder(); llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); @@ -962,7 +962,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); llvm::Optional<uint64_t> field_byte_width = - field_compiler_type.GetByteSize(nullptr); + field_compiler_type.GetByteSize(&thread); if (!field_byte_width) return return_valobj_sp; @@ -1034,7 +1034,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); llvm::Optional<uint64_t> field_byte_width = - field_compiler_type.GetByteSize(nullptr); + field_compiler_type.GetByteSize(&thread); // if we don't know the size of the field (e.g. invalid type), just // bail out diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp index 6f5eded7b031..91d2e59ed632 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp @@ -527,7 +527,7 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( // Extract the register context so we can read arguments from registers llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( @@ -574,7 +574,7 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( // Don't handle complex yet. } else { llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); RegisterValue f1_value; @@ -608,7 +608,7 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size > 0) { const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v2", 0); if (altivec_reg) { diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 251ac972fd76..c7cb7736df9f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -567,7 +567,7 @@ private: ReturnValueExtractor(Thread &thread, CompilerType &type, RegisterContext *reg_ctx, ProcessSP process_sp) : m_thread(thread), m_type(type), - m_byte_size(m_type.GetByteSize(nullptr).getValueOr(0)), + m_byte_size(m_type.GetByteSize(&thread).getValueOr(0)), m_data_up(new DataBufferHeap(m_byte_size, 0)), m_reg_ctx(reg_ctx), m_process_sp(process_sp), m_byte_order(process_sp->GetByteOrder()), m_addr_size( @@ -643,7 +643,7 @@ private: DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size); offset_t offset = 0; - llvm::Optional<uint64_t> byte_size = type.GetByteSize(nullptr); + llvm::Optional<uint64_t> byte_size = type.GetByteSize(m_process_sp.get()); if (!byte_size) return {}; switch (*byte_size) { @@ -777,7 +777,8 @@ private: CompilerType elem_type; if (m_type.IsHomogeneousAggregate(&elem_type)) { uint32_t type_flags = elem_type.GetTypeInfo(); - llvm::Optional<uint64_t> elem_size = elem_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> elem_size = + elem_type.GetByteSize(m_process_sp.get()); if (!elem_size) return {}; if (type_flags & eTypeIsComplex || !(type_flags & eTypeIsFloat)) { diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp index eced2adc7591..22a64170017b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp @@ -118,7 +118,7 @@ enum dwarf_regnums { nullptr, nullptr, nullptr, 0 \ } -static RegisterInfo g_register_infos[] = { +static const RegisterInfo g_register_infos[] = { DEFINE_REG(r0, 8, nullptr, LLDB_INVALID_REGNUM), DEFINE_REG(r1, 8, nullptr, LLDB_INVALID_REGNUM), DEFINE_REG(r2, 8, "arg1", LLDB_REGNUM_GENERIC_ARG1), @@ -173,24 +173,9 @@ static RegisterInfo g_register_infos[] = { static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * ABISysV_s390x::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } count = k_num_register_infos; return g_register_infos; } @@ -508,7 +493,7 @@ ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple( if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers. llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( @@ -555,7 +540,7 @@ ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple( // Don't handle complex yet. } else { llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); RegisterValue f0_value; diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp index 2ac87d1512e9..2f47d3f462d2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp @@ -387,7 +387,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( { value.SetValueType(Value::eValueTypeScalar); llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; bool success = false; @@ -512,7 +512,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( } else if (type_flags & eTypeIsVector) // 'Packed' { llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size > 0) { const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); if (vec_reg == nullptr) diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp index 7729e58f8580..2aa2c02b2e87 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp @@ -406,7 +406,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( // Extract the register context so we can read arguments from registers llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( @@ -453,7 +453,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( // Don't handle complex yet. } else { llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0); @@ -492,7 +492,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size > 0) { const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp index 63b670b07277..06e0ce40836d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp @@ -414,7 +414,7 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectSimple( if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( @@ -461,7 +461,7 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectSimple( // Don't handle complex yet. } else { llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0); @@ -499,7 +499,7 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectSimple( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size > 0) { const RegisterInfo *xmm_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); diff --git a/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp index 6427d8d176c8..8a2d3232a39a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -1056,7 +1056,7 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, thumb_arch_name.erase(0, 3); thumb_arch_name.insert(0, "thumb"); } else { - thumb_arch_name = "thumbv8.2a"; + thumb_arch_name = "thumbv8.7a"; } thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name)); } @@ -1068,7 +1068,7 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, // specified) if (triple.getArch() == llvm::Triple::arm && triple.getSubArch() == llvm::Triple::NoSubArch) - triple.setArchName("armv8.2a"); + triple.setArchName("armv8.7a"); std::string features_str = ""; const char *triple_str = triple.getTriple().c_str(); @@ -1137,16 +1137,13 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, features_str += "+dspr2,"; } - // If any AArch64 variant, enable the ARMv8.5 ISA with SVE extensions so we - // can disassemble newer instructions. - if (triple.getArch() == llvm::Triple::aarch64 || - triple.getArch() == llvm::Triple::aarch64_32) - features_str += "+v8.5a,+sve2"; + // If any AArch64 variant, enable latest ISA with any optional + // extensions like SVE. + if (triple.isAArch64()) { + features_str += "+v8.7a,+sve2,+mte"; - if ((triple.getArch() == llvm::Triple::aarch64 || - triple.getArch() == llvm::Triple::aarch64_32) - && triple.getVendor() == llvm::Triple::Apple) { - cpu = "apple-latest"; + if (triple.getVendor() == llvm::Triple::Apple) + cpu = "apple-latest"; } // We use m_disasm_up.get() to tell whether we are valid or not, so if this diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h index 2d39ce06a8d9..2570e003fd6a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h @@ -131,10 +131,6 @@ protected: private: const lldb_private::SectionList * GetSectionListFromModule(const lldb::ModuleSP module) const; - - DynamicLoaderHexagonDYLD(const DynamicLoaderHexagonDYLD &) = delete; - const DynamicLoaderHexagonDYLD & - operator=(const DynamicLoaderHexagonDYLD &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_DYNAMICLOADERHEXAGONDYLD_H diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp index af76056af684..5e2a866adb22 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp @@ -246,7 +246,7 @@ std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) { return std::string(); for (;;) { - size = m_process->DoReadMemory(addr, &c, 1, error); + size = m_process->ReadMemory(addr, &c, 1, error); if (size != 1 || error.Fail()) return std::string(); if (c == 0) diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index 15b3805003a5..866acbddbdc8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -94,12 +94,13 @@ DYLDRendezvous::DYLDRendezvous(Process *process) : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(), m_previous(), m_loaded_modules(), m_soentries(), m_added_soentries(), m_removed_soentries() { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - m_thread_info.valid = false; + UpdateExecutablePath(); +} - // Cache a copy of the executable path +void DYLDRendezvous::UpdateExecutablePath() { if (m_process) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); if (exe_mod) { m_exe_file_spec = exe_mod->GetPlatformFileSpec(); diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h index b028120eb0d4..3e88d88f407a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -60,6 +60,9 @@ public: DYLDRendezvous(lldb_private::Process *process); + /// Update the cached executable path. + void UpdateExecutablePath(); + /// Update the internal snapshot of runtime linker rendezvous and recompute /// the currently loaded modules. /// diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index ac60af5336ed..160faa74af23 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -76,7 +76,8 @@ DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process) m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS), m_auxv(), m_dyld_bid(LLDB_INVALID_BREAK_ID), m_vdso_base(LLDB_INVALID_ADDRESS), - m_interpreter_base(LLDB_INVALID_ADDRESS) {} + m_interpreter_base(LLDB_INVALID_ADDRESS), m_initial_modules_added(false) { +} DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() { if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { @@ -101,6 +102,7 @@ void DynamicLoaderPOSIXDYLD::DidAttach() { ModuleSP executable_sp = GetTargetExecutable(); ResolveExecutableModule(executable_sp); + m_rendezvous.UpdateExecutablePath(); // find the main process load offset addr_t load_offset = ComputeLoadOffset(); @@ -418,14 +420,38 @@ void DynamicLoaderPOSIXDYLD::RefreshModules() { ModuleList &loaded_modules = m_process->GetTarget().GetImages(); - if (m_rendezvous.ModulesDidLoad()) { + if (m_rendezvous.ModulesDidLoad() || !m_initial_modules_added) { ModuleList new_modules; - E = m_rendezvous.loaded_end(); - for (I = m_rendezvous.loaded_begin(); I != E; ++I) { + // If this is the first time rendezvous breakpoint fires, we need + // to take care of adding all the initial modules reported by + // the loader. This is necessary to list ld-linux.so on Linux, + // and all DT_NEEDED entries on *BSD. + if (m_initial_modules_added) { + I = m_rendezvous.loaded_begin(); + E = m_rendezvous.loaded_end(); + } else { + I = m_rendezvous.begin(); + E = m_rendezvous.end(); + m_initial_modules_added = true; + } + for (; I != E; ++I) { ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true); if (module_sp.get()) { + if (module_sp->GetObjectFile()->GetBaseAddress().GetLoadAddress( + &m_process->GetTarget()) == m_interpreter_base && + module_sp != m_interpreter_module.lock()) { + // If this is a duplicate instance of ld.so, unload it. We may end up + // with it if we load it via a different path than before (symlink + // vs real path). + // TODO: remove this once we either fix library matching or avoid + // loading the interpreter when setting the rendezvous breakpoint. + UnloadSections(module_sp); + loaded_modules.Remove(module_sp); + continue; + } + loaded_modules.AppendIfNeeded(module_sp); new_modules.Append(module_sp); } @@ -544,6 +570,7 @@ ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() { true /* notify */)) { UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_interpreter_base, false); + m_interpreter_module = module_sp; return module_sp; } return nullptr; diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index a7fcdfbadeaf..61567801fdd0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -81,6 +81,9 @@ protected: /// mapped to the address space lldb::addr_t m_interpreter_base; + /// Contains the pointer to the interpret module, if loaded. + std::weak_ptr<lldb_private::Module> m_interpreter_module; + /// Loaded module list. (link map for each module) std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>> m_loaded_modules; @@ -95,6 +98,9 @@ protected: void *baton, lldb_private::StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + /// Indicates whether the initial set of modules was reported added. + bool m_initial_modules_added; + /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set /// of loaded modules. void RefreshModules(); diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp index 48762fe6e0c3..c1fceeb1482c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp @@ -63,9 +63,6 @@ DynamicLoader *DynamicLoaderStatic::CreateInstance(Process *process, DynamicLoaderStatic::DynamicLoaderStatic(Process *process) : DynamicLoader(process) {} -// Destructor -DynamicLoaderStatic::~DynamicLoaderStatic() {} - /// Called after attaching a process. /// /// Allow DynamicLoader plug-ins to execute some code after @@ -86,11 +83,7 @@ void DynamicLoaderStatic::LoadAllImagesAtFileAddresses() { // Disable JIT for static dynamic loader targets m_process->SetCanJIT(false); - std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); - - const size_t num_modules = module_list.GetSize(); - for (uint32_t idx = 0; idx < num_modules; ++idx) { - ModuleSP module_sp(module_list.GetModuleAtIndexUnlocked(idx)); + for (ModuleSP module_sp : module_list.Modules()) { if (module_sp) { bool changed = false; ObjectFile *image_object_file = module_sp->GetObjectFile(); diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h index ce78804f9a92..1a36c7851c2a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h @@ -18,8 +18,6 @@ class DynamicLoaderStatic : public lldb_private::DynamicLoader { public: DynamicLoaderStatic(lldb_private::Process *process); - ~DynamicLoaderStatic() override; - // Static Functions static void Initialize(); @@ -52,9 +50,6 @@ public: private: void LoadAllImagesAtFileAddresses(); - - DynamicLoaderStatic(const DynamicLoaderStatic &) = delete; - const DynamicLoaderStatic &operator=(const DynamicLoaderStatic &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_STATIC_DYNAMICLOADERSTATIC_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 39ba5f4e9e4f..3edbc4ab98c0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -443,7 +443,9 @@ void ASTResultSynthesizer::CommitPersistentDecls() { return; auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); - TypeSystemClang *scratch_ctx = TypeSystemClang::GetScratch(m_target); + + TypeSystemClang *scratch_ctx = ScratchTypeSystemClang::GetForTarget( + m_target, m_ast_context->getLangOpts()); for (clang::NamedDecl *decl : m_decls) { StringRef name = decl->getName(); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h index 3787c572d45b..b70ec223df4d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h @@ -359,15 +359,12 @@ public: } void CompleteType(clang::TagDecl *Tag) override { - while (!Tag->isCompleteDefinition()) - for (size_t i = 0; i < Sources.size(); ++i) { - // FIXME: We are technically supposed to loop here too until - // Tag->isCompleteDefinition() is true, but if our low quality source - // is failing to complete the tag this code will deadlock. - Sources[i]->CompleteType(Tag); - if (Tag->isCompleteDefinition()) - break; - } + for (clang::ExternalSemaSource *S : Sources) { + S->CompleteType(Tag); + // Stop after the first source completed the type. + if (Tag->isCompleteDefinition()) + break; + } } void CompleteType(clang::ObjCInterfaceDecl *Class) override { @@ -404,13 +401,6 @@ public: return nullptr; } - bool DeclIsFromPCHWithObjectFile(const clang::Decl *D) override { - for (auto *S : Sources) - if (S->DeclIsFromPCHWithObjectFile(D)) - return true; - return false; - } - bool layoutRecordType( const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index ac16738933ac..e2601a059bb7 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -216,7 +216,12 @@ namespace { /// imported while completing the original Decls). class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { ClangASTImporter::ImporterDelegateSP m_delegate; - llvm::SmallVector<NamedDecl *, 32> m_decls_to_complete; + /// List of declarations in the target context that need to be completed. + /// Every declaration should only be completed once and therefore should only + /// be once in this list. + llvm::SetVector<NamedDecl *> m_decls_to_complete; + /// Set of declarations that already were successfully completed (not just + /// added to m_decls_to_complete). llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed; clang::ASTContext *m_dst_ctx; clang::ASTContext *m_src_ctx; @@ -244,10 +249,13 @@ public: NamedDecl *decl = m_decls_to_complete.pop_back_val(); m_decls_already_completed.insert(decl); + // The decl that should be completed has to be imported into the target + // context from some other context. + assert(to_context_md->hasOrigin(decl)); // We should only complete decls coming from the source context. - assert(to_context_md->m_origins[decl].ctx == m_src_ctx); + assert(to_context_md->getOrigin(decl).ctx == m_src_ctx); - Decl *original_decl = to_context_md->m_origins[decl].decl; + Decl *original_decl = to_context_md->getOrigin(decl).decl; // Complete the decl now. TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl); @@ -266,7 +274,7 @@ public: container_decl->setHasExternalVisibleStorage(false); } - to_context_md->m_origins.erase(decl); + to_context_md->removeOrigin(decl); } // Stop listening to imported decls. We do this after clearing the @@ -287,7 +295,8 @@ public: // Check if we already completed this type. if (m_decls_already_completed.count(to_named_decl) != 0) return; - m_decls_to_complete.push_back(to_named_decl); + // Queue this type to be completed. + m_decls_to_complete.insert(to_named_decl); } }; } // namespace @@ -581,10 +590,7 @@ bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - OriginMap &origins = context_md->m_origins; - - origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl); - + context_md->setOrigin(decl, DeclOrigin(origin_ast_ctx, origin_decl)); return true; } @@ -721,29 +727,14 @@ ClangASTImporter::DeclOrigin ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - OriginMap &origins = context_md->m_origins; - - OriginMap::iterator iter = origins.find(decl); - - if (iter != origins.end()) - return iter->second; - return DeclOrigin(); + return context_md->getOrigin(decl); } void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - OriginMap &origins = context_md->m_origins; - - OriginMap::iterator iter = origins.find(decl); - - if (iter != origins.end()) { - iter->second.decl = original_decl; - iter->second.ctx = &original_decl->getASTContext(); - return; - } - origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl); + context_md->setOrigin( + decl, DeclOrigin(&original_decl->getASTContext(), original_decl)); } void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl, @@ -817,14 +808,7 @@ void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast, return; md->m_delegates.erase(src_ast); - - for (OriginMap::iterator iter = md->m_origins.begin(); - iter != md->m_origins.end();) { - if (iter->second.ctx == src_ast) - md->m_origins.erase(iter++); - else - ++iter; - } + md->removeOriginsWithContext(src_ast); } ClangASTImporter::MapCompleter::~MapCompleter() { return; } @@ -895,13 +879,14 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { return dn_or_err.takeError(); DeclContext *dc = *dc_or_err; DeclContext::lookup_result lr = dc->lookup(*dn_or_err); - if (lr.size()) { - clang::Decl *lookup_found = lr.front(); - RegisterImportedDecl(From, lookup_found); - m_decls_to_ignore.insert(lookup_found); - return lookup_found; - } else - LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); + for (clang::Decl *candidate : lr) { + if (candidate->getKind() == From->getKind()) { + RegisterImportedDecl(From, candidate); + m_decls_to_ignore.insert(candidate); + return candidate; + } + } + LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); } return ASTImporter::ImportImpl(From); @@ -1100,37 +1085,31 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, m_master.MaybeGetContextMetadata(m_source_ctx); if (from_context_md) { - OriginMap &origins = from_context_md->m_origins; - - OriginMap::iterator origin_iter = origins.find(from); + DeclOrigin origin = from_context_md->getOrigin(from); - if (origin_iter != origins.end()) { - if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || - user_id != LLDB_INVALID_UID) { - if (origin_iter->second.ctx != &to->getASTContext()) - to_context_md->m_origins[to] = origin_iter->second; - } + if (origin.Valid()) { + if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) + if (origin.ctx != &to->getASTContext()) + to_context_md->setOrigin(to, origin); ImporterDelegateSP direct_completer = - m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx); + m_master.GetDelegate(&to->getASTContext(), origin.ctx); if (direct_completer.get() != this) - direct_completer->ASTImporter::Imported(origin_iter->second.decl, to); + direct_completer->ASTImporter::Imported(origin.decl, to); LLDB_LOG(log, " [ClangASTImporter] Propagated origin " "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to " "(ASTContext*){3}", - origin_iter->second.decl, origin_iter->second.ctx, - &from->getASTContext(), &to->getASTContext()); + origin.decl, origin.ctx, &from->getASTContext(), + &to->getASTContext()); } else { if (m_new_decl_listener) m_new_decl_listener->NewDeclImported(from, to); - if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || - user_id != LLDB_INVALID_UID) { - to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); - } + if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) + to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from)); LLDB_LOG(log, " [ClangASTImporter] Decl has no origin information in " @@ -1151,7 +1130,7 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, namespace_map_iter->second; } } else { - to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); + to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from)); LLDB_LOG(log, " [ClangASTImporter] Sourced origin " diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index 6ceec774914b..bf4ad174cf9c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -160,14 +160,12 @@ public: decl = rhs.decl; } - bool Valid() { return (ctx != nullptr || decl != nullptr); } + bool Valid() const { return (ctx != nullptr || decl != nullptr); } clang::ASTContext *ctx; clang::Decl *decl; }; - typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap; - /// Listener interface used by the ASTImporterDelegate to inform other code /// about decls that have been imported the first time. struct NewDeclListener { @@ -259,17 +257,61 @@ public: typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP> NamespaceMetaMap; - struct ASTContextMetadata { - ASTContextMetadata(clang::ASTContext *dst_ctx) - : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(), - m_map_completer(nullptr) {} + class ASTContextMetadata { + typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap; + + public: + ASTContextMetadata(clang::ASTContext *dst_ctx) : m_dst_ctx(dst_ctx) {} clang::ASTContext *m_dst_ctx; DelegateMap m_delegates; - OriginMap m_origins; NamespaceMetaMap m_namespace_maps; - MapCompleter *m_map_completer; + MapCompleter *m_map_completer = nullptr; + + /// Sets the DeclOrigin for the given Decl and overwrites any existing + /// DeclOrigin. + void setOrigin(const clang::Decl *decl, DeclOrigin origin) { + m_origins[decl] = origin; + } + + /// Removes any tracked DeclOrigin for the given decl. + void removeOrigin(const clang::Decl *decl) { m_origins.erase(decl); } + + /// Remove all DeclOrigin entries that point to the given ASTContext. + /// Useful when an ASTContext is about to be deleted and all the dangling + /// pointers to it need to be removed. + void removeOriginsWithContext(clang::ASTContext *ctx) { + for (OriginMap::iterator iter = m_origins.begin(); + iter != m_origins.end();) { + if (iter->second.ctx == ctx) + m_origins.erase(iter++); + else + ++iter; + } + } + + /// Returns the DeclOrigin for the given Decl or an invalid DeclOrigin + /// instance if there no known DeclOrigin for the given Decl. + DeclOrigin getOrigin(const clang::Decl *decl) const { + auto iter = m_origins.find(decl); + if (iter == m_origins.end()) + return DeclOrigin(); + return iter->second; + } + + /// Returns true there is a known DeclOrigin for the given Decl. + bool hasOrigin(const clang::Decl *decl) const { + return getOrigin(decl).Valid(); + } + + private: + /// Maps declarations to the ASTContext/Decl from which they were imported + /// from. If a declaration is from an ASTContext which has been deleted + /// since the declaration was imported or the declaration wasn't created by + /// the ASTImporter, then it doesn't have a DeclOrigin and will not be + /// tracked here. + OriginMap m_origins; }; typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 6fe85a1298fc..0f34c48c7e82 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -71,20 +71,22 @@ ClangASTSource::~ClangASTSource() { if (!m_target) return; - // We are in the process of destruction, don't create clang ast context on - // demand by passing false to - // Target::GetScratchTypeSystemClang(create_on_demand). - TypeSystemClang *scratch_clang_ast_context = - TypeSystemClang::GetScratch(*m_target, false); - if (!scratch_clang_ast_context) - return; + // Unregister the current ASTContext as a source for all scratch + // ASTContexts in the ClangASTImporter. Without this the scratch AST might + // query the deleted ASTContext for additional type information. + // We unregister from *all* scratch ASTContexts in case a type got exported + // to a scratch AST that isn't the best fitting scratch ASTContext. + TypeSystemClang *scratch_ast = ScratchTypeSystemClang::GetForTarget( + *m_target, ScratchTypeSystemClang::DefaultAST, false); - clang::ASTContext &scratch_ast_context = - scratch_clang_ast_context->getASTContext(); + if (!scratch_ast) + return; - if (m_ast_context != &scratch_ast_context && m_ast_importer_sp) - m_ast_importer_sp->ForgetSource(&scratch_ast_context, m_ast_context); + ScratchTypeSystemClang *default_scratch_ast = + llvm::cast<ScratchTypeSystemClang>(scratch_ast); + // Unregister from the default scratch AST (and all sub-ASTs). + default_scratch_ast->ForgetSource(m_ast_context, *m_ast_importer_sp); } void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) { @@ -482,6 +484,15 @@ void ClangASTSource::FindExternalLexicalDecls( if (!copied_decl) continue; + // FIXME: We should add the copied decl to the 'decls' list. This would + // add the copied Decl into the DeclContext and make sure that we + // correctly propagate that we added some Decls back to Clang. + // By leaving 'decls' empty we incorrectly return false from + // DeclContext::LoadLexicalDeclsFromExternalStorage which might cause + // lookup issues later on. + // We can't just add them for now as the ASTImporter already added the + // decl into the DeclContext and this would add it twice. + if (FieldDecl *copied_field = dyn_cast<FieldDecl>(copied_decl)) { QualType copied_field_type = copied_field->getType(); @@ -679,12 +690,7 @@ void ClangASTSource::FillNamespaceMap( return; } - const ModuleList &target_images = m_target->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); - - for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { - lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); - + for (lldb::ModuleSP image : m_target->GetImages().Modules()) { if (!image) continue; @@ -1656,14 +1662,8 @@ void ClangASTSource::CompleteNamespaceMap( module_sp->GetFileSpec().GetFilename()); } } else { - const ModuleList &target_images = m_target->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); - CompilerDeclContext null_namespace_decl; - - for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { - lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); - + for (lldb::ModuleSP image : m_target->GetImages().Modules()) { if (!image) continue; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 8c49898e1d6c..852ce3bbd3db 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" @@ -109,7 +110,7 @@ bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx, m_parser_vars->m_persistent_vars = llvm::cast<ClangPersistentVariables>( target->GetPersistentExpressionStateForLanguage(eLanguageTypeC)); - if (!TypeSystemClang::GetScratch(*target)) + if (!ScratchTypeSystemClang::GetForTarget(*target)) return false; } @@ -125,6 +126,12 @@ void ClangExpressionDeclMap::InstallCodeGenerator( m_parser_vars->m_code_gen = code_gen; } +void ClangExpressionDeclMap::InstallDiagnosticManager( + DiagnosticManager &diag_manager) { + assert(m_parser_vars); + m_parser_vars->m_diagnostics = &diag_manager; +} + void ClangExpressionDeclMap::DidParse() { if (m_parser_vars && m_parser_vars->m_persistent_vars) { for (size_t entity_index = 0, num_entities = m_found_entities.GetSize(); @@ -177,7 +184,7 @@ ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() { TypeFromUser ClangExpressionDeclMap::DeportType(TypeSystemClang &target, TypeSystemClang &source, TypeFromParser parser_type) { - assert(&target == TypeSystemClang::GetScratch(*m_target)); + assert(&target == GetScratchContext(*m_target)); assert((TypeSystem *)&source == parser_type.GetTypeSystem()); assert(&source.getASTContext() == m_ast_context); @@ -196,6 +203,17 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (ast == nullptr) return false; + // Check if we already declared a persistent variable with the same name. + if (lldb::ExpressionVariableSP conflicting_var = + m_parser_vars->m_persistent_vars->GetVariable(name)) { + std::string msg = llvm::formatv("redefinition of persistent variable '{0}'", + name).str(); + m_parser_vars->m_diagnostics->AddDiagnostic( + msg, DiagnosticSeverity::eDiagnosticSeverityError, + DiagnosticOrigin::eDiagnosticOriginLLDB); + return false; + } + if (m_parser_vars->m_materializer && is_result) { Status err; @@ -204,7 +222,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - auto *clang_ast_context = TypeSystemClang::GetScratch(*target); + auto *clang_ast_context = GetScratchContext(*target); if (!clang_ast_context) return false; @@ -242,7 +260,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - TypeSystemClang *context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *context = GetScratchContext(*target); if (!context) return false; @@ -703,7 +721,7 @@ clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) { if (!target) return nullptr; - TypeSystemClang::GetScratch(*target); + ScratchTypeSystemClang::GetForTarget(*target); if (!m_parser_vars->m_persistent_vars) return nullptr; @@ -1620,7 +1638,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, if (target == nullptr) return; - TypeSystemClang *scratch_ast_context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *scratch_ast_context = GetScratchContext(*target); if (!scratch_ast_context) return; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index 6974535a8993..a9cd5d166b9d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -102,6 +102,8 @@ public: void InstallCodeGenerator(clang::ASTConsumer *code_gen); + void InstallDiagnosticManager(DiagnosticManager &diag_manager); + /// Disable the state needed for parsing and IR transformation. void DidParse(); @@ -330,6 +332,8 @@ private: clang::ASTConsumer *m_code_gen = nullptr; ///< If non-NULL, a code generator ///that receives new top-level ///functions. + DiagnosticManager *m_diagnostics = nullptr; + private: ParserVars(const ParserVars &) = delete; const ParserVars &operator=(const ParserVars &) = delete; @@ -376,6 +380,11 @@ private: /// Deallocate struct variables void DisableStructVars() { m_struct_vars.reset(); } + TypeSystemClang *GetScratchContext(Target &target) { + return ScratchTypeSystemClang::GetForTarget(target, + m_ast_context->getLangOpts()); + } + /// Get this parser's ID for use in extracting parser- and JIT-specific data /// from persistent variables. uint64_t GetParserID() { return (uint64_t) this; } diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 6ff028cf6980..7644a5e1423e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -85,7 +85,7 @@ #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" @@ -302,6 +302,55 @@ static void SetupModuleHeaderPaths(CompilerInstance *compiler, search_opts.ImplicitModuleMaps = true; } +/// Iff the given identifier is a C++ keyword, remove it from the +/// identifier table (i.e., make the token a normal identifier). +static void RemoveCppKeyword(IdentifierTable &idents, llvm::StringRef token) { + // FIXME: 'using' is used by LLDB for local variables, so we can't remove + // this keyword without breaking this functionality. + if (token == "using") + return; + // GCC's '__null' is used by LLDB to define NULL/Nil/nil. + if (token == "__null") + return; + + LangOptions cpp_lang_opts; + cpp_lang_opts.CPlusPlus = true; + cpp_lang_opts.CPlusPlus11 = true; + cpp_lang_opts.CPlusPlus20 = true; + + clang::IdentifierInfo &ii = idents.get(token); + // The identifier has to be a C++-exclusive keyword. if not, then there is + // nothing to do. + if (!ii.isCPlusPlusKeyword(cpp_lang_opts)) + return; + // If the token is already an identifier, then there is nothing to do. + if (ii.getTokenID() == clang::tok::identifier) + return; + // Otherwise the token is a C++ keyword, so turn it back into a normal + // identifier. + ii.revertTokenIDToIdentifier(); +} + +/// Remove all C++ keywords from the given identifier table. +static void RemoveAllCppKeywords(IdentifierTable &idents) { +#define KEYWORD(NAME, FLAGS) RemoveCppKeyword(idents, llvm::StringRef(#NAME)); +#include "clang/Basic/TokenKinds.def" +} + +/// Configures Clang diagnostics for the expression parser. +static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) { + // List of Clang warning groups that are not useful when parsing expressions. + const std::vector<const char *> groupsToIgnore = { + "unused-value", + "odr", + }; + for (const char *group : groupsToIgnore) { + compiler.getDiagnostics().setSeverityForGroup( + clang::diag::Flavor::WarningOrError, group, + clang::diag::Severity::Ignored, SourceLocation()); + } +} + //===----------------------------------------------------------------------===// // Implementation of ClangExpressionParser //===----------------------------------------------------------------------===// @@ -454,6 +503,10 @@ ClangExpressionParser::ClangExpressionParser( // 4. Create and install the target on the compiler. m_compiler->createDiagnostics(); + // Limit the number of error diagnostics we emit. + // A value of 0 means no limit for both LLDB and Clang. + m_compiler->getDiagnostics().setErrorLimit(target_sp->GetExprErrorLimit()); + auto target_info = TargetInfo::CreateTargetInfo( m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts); if (log) { @@ -598,12 +651,7 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo); // Disable some warnings. - m_compiler->getDiagnostics().setSeverityForGroup( - clang::diag::Flavor::WarningOrError, "unused-value", - clang::diag::Severity::Ignored, SourceLocation()); - m_compiler->getDiagnostics().setSeverityForGroup( - clang::diag::Flavor::WarningOrError, "odr", - clang::diag::Severity::Ignored, SourceLocation()); + SetupDefaultClangDiagnostics(*m_compiler); // Inform the target of the language options // @@ -623,6 +671,21 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->createSourceManager(m_compiler->getFileManager()); m_compiler->createPreprocessor(TU_Complete); + switch (language) { + case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC89: + case lldb::eLanguageTypeC99: + case lldb::eLanguageTypeC11: + case lldb::eLanguageTypeObjC: + // This is not a C++ expression but we enabled C++ as explained above. + // Remove all C++ keywords from the PP so that the user can still use + // variables that have C++ keywords as names (e.g. 'int template;'). + RemoveAllCppKeywords(m_compiler->getPreprocessor().getIdentifierTable()); + break; + default: + break; + } + if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor()) { if (auto *clang_persistent_vars = llvm::cast<ClangPersistentVariables>( @@ -1010,8 +1073,8 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, if (file.Write(expr_text, bytes_written).Success()) { if (bytes_written == expr_text_len) { file.Close(); - if (auto fileEntry = - m_compiler->getFileManager().getFile(result_path)) { + if (auto fileEntry = m_compiler->getFileManager().getOptionalFileRef( + result_path)) { source_mgr.setMainFileID(source_mgr.createFileID( *fileEntry, SourceLocation(), SrcMgr::C_User)); @@ -1074,6 +1137,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); if (decl_map) { decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer()); + decl_map->InstallDiagnosticManager(diagnostic_manager); clang::ExternalASTSource *ast_source = decl_map->CreateProxy(); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index a429963277d1..180e08b03c93 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -221,7 +221,7 @@ TokenVerifier::TokenVerifier(std::string body) { clang::SourceManager SM(diags, file_mgr); auto buf = llvm::MemoryBuffer::getMemBuffer(body); - FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get()); + FileID FID = SM.createFileID(buf->getMemBufferRef()); // Let's just enable the latest ObjC and C++ which should get most tokens // right. @@ -231,7 +231,7 @@ TokenVerifier::TokenVerifier(std::string body) { Opts.CPlusPlus17 = true; Opts.LineComment = true; - Lexer lex(FID, buf.get(), SM, Opts); + Lexer lex(FID, buf->getMemBufferRef(), SM, Opts); Token token; bool exit = false; @@ -297,6 +297,7 @@ bool ClangExpressionSourceCode::GetText( bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const { const char *target_specific_defines = "typedef signed char BOOL;\n"; std::string module_macros; + llvm::raw_string_ostream module_macros_stream(module_macros); Target *target = exe_ctx.GetTargetPtr(); if (target) { @@ -344,9 +345,13 @@ bool ClangExpressionSourceCode::GetText( decl_vendor->ForEachMacro( modules_for_macros, - [&module_macros](const std::string &expansion) -> bool { - module_macros.append(expansion); - module_macros.append("\n"); + [&module_macros_stream](llvm::StringRef token, + llvm::StringRef expansion) -> bool { + // Check if the macro hasn't already been defined in the + // g_expression_prefix (which defines a few builtin macros). + module_macros_stream << "#ifndef " << token << "\n"; + module_macros_stream << expansion << "\n"; + module_macros_stream << "#endif\n"; return false; }); } @@ -387,8 +392,8 @@ bool ClangExpressionSourceCode::GetText( StreamString wrap_stream; - wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), - debug_macros_stream.GetData(), g_expression_prefix, + wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", g_expression_prefix, + module_macros.c_str(), debug_macros_stream.GetData(), target_specific_defines, m_prefix.c_str()); // First construct a tagged form of the user expression so we can find it diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 8abb7e420575..b76fa6fbf690 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -137,14 +137,12 @@ bool lldb_private::ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, FileSystem::Instance().Resolve(file_spec); return true; } - raw_path = lldb_shlib_spec.GetPath(); } - raw_path.resize(rev_it - r_end); - } else { - raw_path.resize(rev_it - r_end); } // Fall back to the Clang resource directory inside the framework. + raw_path = lldb_shlib_spec.GetPath(); + raw_path.resize(rev_it - r_end); raw_path.append("LLDB.framework/Resources/Clang"); file_spec.GetDirectory().SetString(raw_path.c_str()); FileSystem::Instance().Resolve(file_spec); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 95acb883774d..c014ad504d37 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -33,7 +33,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/StreamString.h" #include <memory> @@ -95,8 +95,10 @@ public: uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector<CompilerDecl> &decls) override; - void ForEachMacro(const ModuleVector &modules, - std::function<bool(const std::string &)> handler) override; + void ForEachMacro( + const ModuleVector &modules, + std::function<bool(llvm::StringRef, llvm::StringRef)> handler) override; + private: void ReportModuleExportsHelper(std::set<ClangModulesDeclVendor::ModuleID> &exports, @@ -420,7 +422,7 @@ ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, void ClangModulesDeclVendorImpl::ForEachMacro( const ClangModulesDeclVendor::ModuleVector &modules, - std::function<bool(const std::string &)> handler) { + std::function<bool(llvm::StringRef, llvm::StringRef)> handler) { if (!m_enabled) { return; } @@ -490,7 +492,8 @@ void ClangModulesDeclVendorImpl::ForEachMacro( if (macro_info) { std::string macro_expansion = "#define "; - macro_expansion.append(mi->first->getName().str()); + llvm::StringRef macro_identifier = mi->first->getName(); + macro_expansion.append(macro_identifier.str()); { if (macro_info->isFunctionLike()) { @@ -575,7 +578,7 @@ void ClangModulesDeclVendorImpl::ForEachMacro( } } - if (handler(macro_expansion)) { + if (handler(macro_identifier, macro_expansion)) { return; } } diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h index f04d1b07f03d..d820552a2912 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h @@ -90,13 +90,13 @@ public: /// if module A #defines a macro and module B #undefs it. /// /// \param[in] handler - /// A function to call with the text of each #define (including the - /// #define directive). #undef directives are not included; we simply - /// elide any corresponding #define. If this function returns true, - /// we stop the iteration immediately. - virtual void - ForEachMacro(const ModuleVector &modules, - std::function<bool(const std::string &)> handler) = 0; + /// A function to call with the identifier of this macro and the text of + /// each #define (including the #define directive). #undef directives are + /// not included; we simply elide any corresponding #define. If this + /// function returns true, we stop the iteration immediately. + virtual void ForEachMacro( + const ModuleVector &modules, + std::function<bool(llvm::StringRef, llvm::StringRef)> handler) = 0; /// Query whether Clang supports modules for a particular language. /// LLDB uses this to decide whether to try to find the modules loaded diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index a28b4a7fb42c..9be294750fa0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -417,7 +417,6 @@ void ClangUserExpression::CreateSourceCode( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, std::vector<std::string> modules_to_import, bool for_completion) { - m_filename = m_clang_state->GetNextExprFileName(); std::string prefix = m_expr_prefix; if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { @@ -477,9 +476,6 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language, if (!target) return LogConfigError("No target"); - if (!target->GetEnableImportStdModule()) - return LogConfigError("Importing std module not enabled in settings"); - StackFrame *frame = exe_ctx.GetFramePtr(); if (!frame) return LogConfigError("No frame"); @@ -529,8 +525,6 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language, bool ClangUserExpression::PrepareForParsing( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, bool for_completion) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - InstallContext(exe_ctx); if (!SetupPersistentState(diagnostic_manager, exe_ctx)) @@ -551,50 +545,20 @@ bool ClangUserExpression::PrepareForParsing( SetupDeclVendor(exe_ctx, m_target, diagnostic_manager); - CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); - llvm::ArrayRef<std::string> imported_modules = - module_config.GetImportedModules(); - m_imported_cpp_modules = !imported_modules.empty(); - m_include_directories = module_config.GetIncludeDirs(); + m_filename = m_clang_state->GetNextExprFileName(); - LLDB_LOG(log, "List of imported modules in expression: {0}", - llvm::make_range(imported_modules.begin(), imported_modules.end())); - LLDB_LOG(log, "List of include directories gathered for modules: {0}", - llvm::make_range(m_include_directories.begin(), - m_include_directories.end())); + if (m_target->GetImportStdModule() == eImportStdModuleTrue) + SetupCppModuleImports(exe_ctx); - CreateSourceCode(diagnostic_manager, exe_ctx, imported_modules, + CreateSourceCode(diagnostic_manager, exe_ctx, m_imported_cpp_modules, for_completion); return true; } -bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, - bool generate_debug_info) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false)) - return false; - - LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str()); - - //////////////////////////////////// - // Set up the target and compiler - // - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target"); - return false; - } - - ////////////////////////// - // Parse the expression - // - +bool ClangUserExpression::TryParse( + DiagnosticManager &diagnostic_manager, ExecutionContextScope *exe_scope, + ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info) { m_materializer_up = std::make_unique<Materializer>(); ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory); @@ -612,26 +576,16 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, DeclMap()->SetLookupsEnabled(true); } - Process *process = exe_ctx.GetProcessPtr(); - ExecutionContextScope *exe_scope = process; - - if (!exe_scope) - exe_scope = exe_ctx.GetTargetPtr(); - - // We use a shared pointer here so we can use the original parser - if it - // succeeds or the rewrite parser we might make if it fails. But the - // parser_sp will never be empty. - - ClangExpressionParser parser(exe_scope, *this, generate_debug_info, - m_include_directories, m_filename); + m_parser = std::make_unique<ClangExpressionParser>( + exe_scope, *this, generate_debug_info, m_include_directories, m_filename); - unsigned num_errors = parser.Parse(diagnostic_manager); + unsigned num_errors = m_parser->Parse(diagnostic_manager); // Check here for FixItHints. If there are any try to apply the fixits and // set the fixed text in m_fixed_text before returning an error. if (num_errors) { if (diagnostic_manager.HasFixIts()) { - if (parser.RewriteExpression(diagnostic_manager)) { + if (m_parser->RewriteExpression(diagnostic_manager)) { size_t fixed_start; size_t fixed_end; m_fixed_text = diagnostic_manager.GetFixedExpression(); @@ -652,7 +606,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // { - Status jit_error = parser.PrepareForExecution( + Status jit_error = m_parser->PrepareForExecution( m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx, m_can_interpret, execution_policy); @@ -666,10 +620,91 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, return false; } } + return true; +} + +void ClangUserExpression::SetupCppModuleImports(ExecutionContext &exe_ctx) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); + m_imported_cpp_modules = module_config.GetImportedModules(); + m_include_directories = module_config.GetIncludeDirs(); + + LLDB_LOG(log, "List of imported modules in expression: {0}", + llvm::make_range(m_imported_cpp_modules.begin(), + m_imported_cpp_modules.end())); + LLDB_LOG(log, "List of include directories gathered for modules: {0}", + llvm::make_range(m_include_directories.begin(), + m_include_directories.end())); +} + +static bool shouldRetryWithCppModule(Target &target, ExecutionPolicy exe_policy) { + // Top-level expression don't yet support importing C++ modules. + if (exe_policy == ExecutionPolicy::eExecutionPolicyTopLevel) + return false; + return target.GetImportStdModule() == eImportStdModuleFallback; +} + +bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, + bool generate_debug_info) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false)) + return false; + + LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str()); + + //////////////////////////////////// + // Set up the target and compiler + // + + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) { + diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target"); + return false; + } + + ////////////////////////// + // Parse the expression + // + + Process *process = exe_ctx.GetProcessPtr(); + ExecutionContextScope *exe_scope = process; + + if (!exe_scope) + exe_scope = exe_ctx.GetTargetPtr(); + + bool parse_success = TryParse(diagnostic_manager, exe_scope, exe_ctx, + execution_policy, keep_result_in_memory, + generate_debug_info); + // If the expression failed to parse, check if retrying parsing with a loaded + // C++ module is possible. + if (!parse_success && shouldRetryWithCppModule(*target, execution_policy)) { + // Load the loaded C++ modules. + SetupCppModuleImports(exe_ctx); + // If we did load any modules, then retry parsing. + if (!m_imported_cpp_modules.empty()) { + // The module imports are injected into the source code wrapper, + // so recreate those. + CreateSourceCode(diagnostic_manager, exe_ctx, m_imported_cpp_modules, + /*for_completion*/ false); + // Clear the error diagnostics from the previous parse attempt. + diagnostic_manager.Clear(); + parse_success = TryParse(diagnostic_manager, exe_scope, exe_ctx, + execution_policy, keep_result_in_memory, + generate_debug_info); + } + } + if (!parse_success) + return false; if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) { Status static_init_error = - parser.RunStaticInitializers(m_execution_unit_sp, exe_ctx); + m_parser->RunStaticInitializers(m_execution_unit_sp, exe_ctx); if (!static_init_error.Success()) { const char *error_cstr = static_init_error.AsCString(); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index f734069655ef..b628f6debf66 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -168,12 +168,23 @@ public: lldb::ExpressionVariableSP GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override; - bool DidImportCxxModules() const { return m_imported_cpp_modules; } + /// Returns true iff this expression is using any imported C++ modules. + bool DidImportCxxModules() const { return !m_imported_cpp_modules.empty(); } private: /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the /// environment. + /// Contains the actual parsing implementation. + /// The parameter have the same meaning as in ClangUserExpression::Parse. + /// \see ClangUserExpression::Parse + bool TryParse(DiagnosticManager &diagnostic_manager, + ExecutionContextScope *exe_scope, ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, + bool generate_debug_info); + + void SetupCppModuleImports(ExecutionContext &exe_ctx); + void ScanContext(ExecutionContext &exe_ctx, lldb_private::Status &err) override; @@ -219,6 +230,8 @@ private: ResultDelegate m_result_delegate; ClangPersistentVariables *m_clang_state; std::unique_ptr<ClangExpressionSourceCode> m_source_code; + /// The parser instance we used to parse the expression. + std::unique_ptr<ClangExpressionParser> m_parser; /// File name used for the expression. std::string m_filename; @@ -226,8 +239,9 @@ private: /// See the comment to `UserExpression::Evaluate` for details. ValueObject *m_ctx_obj; - /// True iff this expression explicitly imported C++ modules. - bool m_imported_cpp_modules = false; + /// A list of module names that should be imported when parsing. + /// \see CppModuleConfiguration::GetImportedModules + std::vector<std::string> m_imported_cpp_modules; /// True if the expression parser should enforce the presence of a valid class /// pointer in order to generate the expression as a method. diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 25ec982220a0..9788a4e1c183 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -42,12 +42,11 @@ char ClangUtilityFunction::ID; /// \param[in] name /// The name of the function, as used in the text. ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope, - const char *text, const char *name) - : UtilityFunction(exe_scope, text, name) { - m_function_text.assign(ClangExpressionSourceCode::g_expression_prefix); - if (text && text[0]) - m_function_text.append(text); -} + std::string text, std::string name) + : UtilityFunction( + exe_scope, + std::string(ClangExpressionSourceCode::g_expression_prefix) + text, + std::move(name)) {} ClangUtilityFunction::~ClangUtilityFunction() {} diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index 1f2dd5fdbecc..7914e1406cd0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -41,6 +41,34 @@ public: } static bool classof(const Expression *obj) { return obj->isA(&ID); } + /// Constructor + /// + /// \param[in] text + /// The text of the function. Must be a full translation unit. + /// + /// \param[in] name + /// The name of the function, as used in the text. + ClangUtilityFunction(ExecutionContextScope &exe_scope, std::string text, + std::string name); + + ~ClangUtilityFunction() override; + + ExpressionTypeSystemHelper *GetTypeSystemHelper() override { + return &m_type_system_helper; + } + + ClangExpressionDeclMap *DeclMap() { return m_type_system_helper.DeclMap(); } + + void ResetDeclMap() { m_type_system_helper.ResetDeclMap(); } + + void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) { + m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); + } + + bool Install(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx) override; + +private: class ClangUtilityFunctionHelper : public ClangExpressionHelper { public: ClangUtilityFunctionHelper() {} @@ -58,7 +86,7 @@ public: void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory); /// Return the object that the parser should allow to access ASTs. May be - /// NULL if the ASTs do not need to be transformed. + /// nullptr if the ASTs do not need to be transformed. /// /// \param[in] passthrough /// The ASTConsumer that the returned transformer should send @@ -71,37 +99,9 @@ public: private: std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up; }; - /// Constructor - /// - /// \param[in] text - /// The text of the function. Must be a full translation unit. - /// - /// \param[in] name - /// The name of the function, as used in the text. - ClangUtilityFunction(ExecutionContextScope &exe_scope, const char *text, - const char *name); - - ~ClangUtilityFunction() override; - - ExpressionTypeSystemHelper *GetTypeSystemHelper() override { - return &m_type_system_helper; - } - ClangExpressionDeclMap *DeclMap() { return m_type_system_helper.DeclMap(); } - - void ResetDeclMap() { m_type_system_helper.ResetDeclMap(); } - - void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) { - m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); - } - - bool Install(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx) override; - -private: - ClangUtilityFunctionHelper m_type_system_helper; ///< The map to use when - ///parsing and materializing - ///the expression. + /// The map to use when parsing and materializing the expression. + ClangUtilityFunctionHelper m_type_system_helper; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp index f1272c67d20f..ffab16b1682b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp @@ -38,9 +38,11 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f) { // Check for /c++/vX/ that is used by libc++. static llvm::Regex libcpp_regex(R"regex(/c[+][+]/v[0-9]/)regex"); - if (libcpp_regex.match(f.GetPath())) { - // Strip away libc++'s /experimental directory if there is one. - posix_dir.consume_back("/experimental"); + // If the path is in the libc++ include directory use it as the found libc++ + // path. Ignore subdirectories such as /c++/v1/experimental as those don't + // need to be specified in the header search. + if (libcpp_regex.match(f.GetPath()) && + parent_path(posix_dir, Style::posix).endswith("c++")) { return m_std_inc.TrySet(posix_dir); } @@ -55,9 +57,38 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f) { return true; } +/// Utility function for just appending two paths. +static std::string MakePath(llvm::StringRef lhs, llvm::StringRef rhs) { + llvm::SmallString<256> result(lhs); + llvm::sys::path::append(result, rhs); + return std::string(result); +} + bool CppModuleConfiguration::hasValidConfig() { - // We all these include directories to have a valid usable configuration. - return m_c_inc.Valid() && m_std_inc.Valid(); + // We need to have a C and C++ include dir for a valid configuration. + if (!m_c_inc.Valid() || !m_std_inc.Valid()) + return false; + + // Do some basic sanity checks on the directories that we don't activate + // the module when it's clear that it's not usable. + const std::vector<std::string> files_to_check = { + // * Check that the C library contains at least one random C standard + // library header. + MakePath(m_c_inc.Get(), "stdio.h"), + // * Without a libc++ modulemap file we can't have a 'std' module that + // could be imported. + MakePath(m_std_inc.Get(), "module.modulemap"), + // * Check for a random libc++ header (vector in this case) that has to + // exist in a working libc++ setup. + MakePath(m_std_inc.Get(), "vector"), + }; + + for (llvm::StringRef file_to_check : files_to_check) { + if (!FileSystem::Instance().Exists(file_to_check)) + return false; + } + + return true; } CppModuleConfiguration::CppModuleConfiguration( @@ -76,7 +107,8 @@ CppModuleConfiguration::CppModuleConfiguration( m_resource_inc = std::string(resource_dir.str()); // This order matches the way Clang orders these directories. - m_include_dirs = {m_std_inc.Get(), m_resource_inc, m_c_inc.Get()}; + m_include_dirs = {m_std_inc.Get().str(), m_resource_inc, + m_c_inc.Get().str()}; m_imported_modules = {"std"}; } } diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h index 235ac2bd090c..b984db43fa6d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h @@ -32,7 +32,7 @@ class CppModuleConfiguration { /// the path was already set. LLVM_NODISCARD bool TrySet(llvm::StringRef path); /// Return the path if there is one. - std::string Get() const { + llvm::StringRef Get() const { assert(m_valid && "Called Get() on an invalid SetOncePath?"); return m_path; } @@ -57,9 +57,6 @@ class CppModuleConfiguration { public: /// Creates a configuration by analyzing the given list of used source files. - /// - /// Currently only looks at the used paths and doesn't actually access the - /// files on the disk. explicit CppModuleConfiguration(const FileSpecList &support_files); /// Creates an empty and invalid configuration. CppModuleConfiguration() {} diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp index 2f8cf1846ee7..f953e860969c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp @@ -22,6 +22,7 @@ CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) std::initializer_list<const char *> supported_names = { // containers + "array", "deque", "forward_list", "list", @@ -34,6 +35,7 @@ CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) "weak_ptr", // utility "allocator", + "pair", }; m_supported_templates.insert(supported_names.begin(), supported_names.end()); } @@ -180,21 +182,21 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { // If we don't have a template to instiantiate, then there is nothing to do. auto td = dyn_cast<ClassTemplateSpecializationDecl>(d); if (!td) - return {}; + return llvm::None; // We only care about templates in the std namespace. if (!td->getDeclContext()->isStdNamespace()) - return {}; + return llvm::None; // We have a list of supported template names. - if (m_supported_templates.find(td->getName()) == m_supported_templates.end()) - return {}; + if (!m_supported_templates.contains(td->getName())) + return llvm::None; // Early check if we even support instantiating this template. We do this // before we import anything into the target AST. auto &foreign_args = td->getTemplateInstantiationArgs(); if (!templateArgsAreSupported(foreign_args.asArray())) - return {}; + return llvm::None; // Find the local DeclContext that corresponds to the DeclContext of our // decl we want to import. @@ -205,7 +207,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { "Got error while searching equal local DeclContext for decl " "'{1}':\n{0}", td->getName()); - return {}; + return llvm::None; } // Look up the template in our local context. @@ -218,7 +220,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { break; } if (!new_class_template) - return {}; + return llvm::None; // Import the foreign template arguments. llvm::SmallVector<TemplateArgument, 4> imported_args; @@ -230,7 +232,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { llvm::Expected<QualType> type = m_importer->Import(arg.getAsType()); if (!type) { LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); - return {}; + return llvm::None; } imported_args.push_back(TemplateArgument(*type)); break; @@ -241,7 +243,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { m_importer->Import(arg.getIntegralType()); if (!type) { LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); - return {}; + return llvm::None; } imported_args.push_back( TemplateArgument(d->getASTContext(), integral, *type)); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp index b92f00ec2b63..a6e36d81b950 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp @@ -48,29 +48,27 @@ ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default; bool ClangDynamicCheckerFunctions::Install( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { - Status error; - m_valid_pointer_check.reset( - exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - g_valid_pointer_check_text, lldb::eLanguageTypeC, - VALID_POINTER_CHECK_NAME, error)); - if (error.Fail()) + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + g_valid_pointer_check_text, VALID_POINTER_CHECK_NAME, + lldb::eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + llvm::consumeError(utility_fn_or_error.takeError()); return false; + } + m_valid_pointer_check = std::move(*utility_fn_or_error); - if (!m_valid_pointer_check->Install(diagnostic_manager, exe_ctx)) - return false; - - Process *process = exe_ctx.GetProcessPtr(); - - if (process) { + if (Process *process = exe_ctx.GetProcessPtr()) { ObjCLanguageRuntime *objc_language_runtime = ObjCLanguageRuntime::Get(*process); if (objc_language_runtime) { - m_objc_object_check.reset(objc_language_runtime->CreateObjectChecker( - VALID_OBJC_OBJECT_CHECK_NAME)); - - if (!m_objc_object_check->Install(diagnostic_manager, exe_ctx)) + auto utility_fn_or_error = objc_language_runtime->CreateObjectChecker( + VALID_OBJC_OBJECT_CHECK_NAME, exe_ctx); + if (!utility_fn_or_error) { + llvm::consumeError(utility_fn_or_error.takeError()); return false; + } + m_objc_object_check = std::move(*utility_fn_or_error); } } diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 8511e554509a..b35bf07034bd 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -305,9 +305,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { } lldb::TargetSP target_sp(m_execution_unit.GetTarget()); - lldb_private::ExecutionContext exe_ctx(target_sp, true); - llvm::Optional<uint64_t> bit_size = - m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()); + llvm::Optional<uint64_t> bit_size = m_result_type.GetBitSize(target_sp.get()); if (!bit_size) { lldb_private::StreamString type_desc_stream; m_result_type.DumpTypeDescription(&type_desc_stream); @@ -330,7 +328,8 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { m_result_name = lldb_private::ConstString("$RESULT_NAME"); LLDB_LOG(log, "Creating a new result global: \"{0}\" with size {1}", - m_result_name, m_result_type.GetByteSize(nullptr).getValueOr(0)); + m_result_name, + m_result_type.GetByteSize(target_sp.get()).getValueOr(0)); // Construct a new result global and set up its metadata @@ -1242,10 +1241,12 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { value_type = global_variable->getType(); } - llvm::Optional<uint64_t> value_size = compiler_type.GetByteSize(nullptr); + auto *target = m_execution_unit.GetTarget().get(); + llvm::Optional<uint64_t> value_size = compiler_type.GetByteSize(target); if (!value_size) return false; - llvm::Optional<size_t> opt_alignment = compiler_type.GetTypeBitAlign(nullptr); + llvm::Optional<size_t> opt_alignment = + compiler_type.GetTypeBitAlign(target); if (!opt_alignment) return false; lldb::offset_t value_alignment = (*opt_alignment + 7ull) / 8ull; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h index b7b6640c4810..4fe727460fdb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h @@ -18,7 +18,7 @@ class ModuleDependencyCollectorAdaptor : public clang::ModuleDependencyCollector { public: ModuleDependencyCollectorAdaptor( - std::shared_ptr<llvm::FileCollector> file_collector) + std::shared_ptr<llvm::FileCollectorBase> file_collector) : clang::ModuleDependencyCollector(""), m_file_collector(file_collector) { } @@ -33,7 +33,7 @@ public: void writeFileMap() override {} private: - std::shared_ptr<llvm::FileCollector> m_file_collector; + std::shared_ptr<llvm::FileCollectorBase> m_file_collector; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp index c1f88889f1dc..829afa5ffcec 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -78,7 +78,8 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, clang::FunctionDecl *func_decl = FunctionDecl::Create( ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, - isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + isConstexprSpecified ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); // We have to do more than just synthesize the FunctionDecl. We have to // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp index 72d28c347457..99784bd3dbd1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp @@ -114,7 +114,7 @@ InstrumentationRuntimeMainThreadChecker::RetrieveReportData( std::string className = ""; std::string selector = ""; if (apiName.substr(0, 2) == "-[") { - size_t spacePos = apiName.find(" "); + size_t spacePos = apiName.find(' '); if (spacePos != std::string::npos) { className = apiName.substr(2, spacePos - 2); selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2); diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index 50f0faefa0f4..a2954f556b10 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -809,7 +809,9 @@ bool InstrumentationRuntimeTSan::NotifyBreakpointHit( StructuredData::ObjectSP report = instance->RetrieveReportData(context->exe_ctx_ref); - std::string stop_reason_description; + std::string stop_reason_description = + "unknown thread sanitizer fault (unable to extract thread sanitizer " + "report)"; if (report) { std::string issue_description = instance->FormatDescription(report); report->GetAsDictionary()->AddStringItem("description", issue_description); diff --git a/contrib/llvm-project/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/contrib/llvm-project/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 74d65b3caaf0..33dfc7b3281e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -293,8 +293,8 @@ bool JITLoaderGDB::ReadJITDescriptorImpl(bool all_entries) { jit_descriptor<ptr_t> jit_desc; const size_t jit_desc_size = sizeof(jit_desc); Status error; - size_t bytes_read = m_process->DoReadMemory(m_jit_descriptor_addr, &jit_desc, - jit_desc_size, error); + size_t bytes_read = m_process->ReadMemory(m_jit_descriptor_addr, &jit_desc, + jit_desc_size, error); if (bytes_read != jit_desc_size || !error.Success()) { LLDB_LOGF(log, "JITLoaderGDB::%s failed to read JIT descriptor", __FUNCTION__); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index 42f6bd9ffb7b..35788a6445c2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -50,11 +50,7 @@ public: } TypeSystemClang *clang_ast_context = - llvm::dyn_cast<TypeSystemClang>(&type_system_or_err.get()); - - if (!clang_ast_context) { - return; - } + llvm::cast<TypeSystemClang>(block_pointer_type.GetTypeSystem()); std::shared_ptr<ClangASTImporter> clang_ast_importer; auto *state = target_sp->GetPersistentExpressionStateForLanguage( diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 08e43ae6b3e8..d844498fd8a3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -601,8 +601,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { ConstString("^std::__[[:alnum:]]+::atomic<.+>$"), stl_synth_flags, true); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression( - llvm::StringRef("^(std::__[[:alnum:]]+::)deque<.+>(( )?&)?$")), + RegularExpression("^(std::__[[:alnum:]]+::)deque<.+>(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.libcxx.stddeque_SynthProvider"))); @@ -823,32 +822,32 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { false); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$")), + RegularExpression("^std::vector<.+>(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider"))); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$")), + RegularExpression("^std::map<.+> >(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider"))); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression(llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$")), + RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider"))); stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(true); cpp_category_sp->GetRegexTypeSummariesContainer()->Add( - RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$")), + RegularExpression("^std::vector<.+>(( )?&)?$"), TypeSummaryImplSP( new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); cpp_category_sp->GetRegexTypeSummariesContainer()->Add( - RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$")), + RegularExpression("^std::map<.+> >(( )?&)?$"), TypeSummaryImplSP( new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); cpp_category_sp->GetRegexTypeSummariesContainer()->Add( - RegularExpression(llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$")), + RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"), TypeSummaryImplSP( new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); @@ -1135,6 +1134,15 @@ CPlusPlusLanguage::GetHardcodedSynthetics() { return g_formatters; } +bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) { + if (!Language::LanguageIsCPlusPlus(valobj.GetObjectRuntimeLanguage()) || + !valobj.IsPointerType()) + return false; + bool canReadValue = true; + bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0; + return canReadValue && isZero; +} + bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const { const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c", ".h", ".hh", ".hpp", ".hxx", ".h++"}; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index 89dea08a2c53..e2b5d2918753 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -88,6 +88,10 @@ public: HardcodedFormatters::HardcodedSyntheticFinder GetHardcodedSynthetics() override; + bool IsNilReference(ValueObject &valobj) override; + + llvm::StringRef GetNilReferenceSummaryString() override { return "nullptr"; } + bool IsSourceFile(llvm::StringRef file_path) const override; const Highlighter *GetHighlighter() const override { return &m_highlighter; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 84dd09a47d8a..2b16ebe79daf 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -692,7 +692,7 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( // std::wstring::size() is measured in 'characters', not bytes TypeSystemClang *ast_context = - TypeSystemClang::GetScratch(*valobj.GetTargetSP()); + ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP()); if (!ast_context) return false; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp index aaf578c6f728..fe6eeea54e4d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp @@ -168,7 +168,7 @@ void ClangHighlighter::Highlight(const HighlightStyle &options, clang::SourceManager SM(diags, file_mgr); auto buf = llvm::MemoryBuffer::getMemBuffer(full_source); - FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get()); + FileID FID = SM.createFileID(buf->getMemBufferRef()); // Let's just enable the latest ObjC and C++ which should get most tokens // right. @@ -178,7 +178,7 @@ void ClangHighlighter::Highlight(const HighlightStyle &options, Opts.CPlusPlus17 = true; Opts.LineComment = true; - Lexer lex(FID, buf.get(), SM, Opts); + Lexer lex(FID, buf->getMemBufferRef(), SM, Opts); // The lexer should keep whitespace around. lex.SetKeepWhitespaceMode(true); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 648fc4adf24f..d871d3470e70 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -72,6 +72,9 @@ bool lldb_private::formatters::NSBundleSummaryProvider( valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true)); + if (!text) + return false; + StreamString summary_stream; bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); @@ -117,6 +120,10 @@ bool lldb_private::formatters::NSTimeZoneSummaryProvider( uint64_t offset = ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset( offset, valobj.GetCompilerType(), true)); + + if (!text) + return false; + StreamString summary_stream; bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); @@ -162,6 +169,10 @@ bool lldb_private::formatters::NSNotificationSummaryProvider( uint64_t offset = ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset( offset, valobj.GetCompilerType(), true)); + + if (!text) + return false; + StreamString summary_stream; bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); @@ -1024,7 +1035,7 @@ bool lldb_private::formatters::ObjCBOOLSummaryProvider( if (!real_guy_sp) return false; } - uint8_t value = (real_guy_sp->GetValueAsUnsigned(0) & 0xFF); + int8_t value = (real_guy_sp->GetValueAsSigned(0) & 0xFF); switch (value) { case 0: stream.Printf("NO"); @@ -1033,7 +1044,7 @@ bool lldb_private::formatters::ObjCBOOLSummaryProvider( stream.Printf("YES"); break; default: - stream.Printf("%u", value); + stream.Printf("%d", value); break; } return true; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp index ac2f45b8354f..efc80cc75557 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp @@ -25,21 +25,12 @@ bool lldb_private::formatters::CMTimeSummaryProvider( if (!type.IsValid()) return false; - auto type_system_or_err = - valobj.GetExecutionContextRef() - .GetTargetSP() - ->GetScratchTypeSystemForLanguage(lldb::eLanguageTypeC); - if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR( - lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS), - std::move(err), "Failed to get scratch type system"); - return false; - } + TypeSystem *type_system = type.GetTypeSystem(); // fetch children by offset to compensate for potential lack of debug info - auto int64_ty = type_system_or_err->GetBuiltinTypeForEncodingAndBitSize( - eEncodingSint, 64); - auto int32_ty = type_system_or_err->GetBuiltinTypeForEncodingAndBitSize( - eEncodingSint, 32); + auto int64_ty = + type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 64); + auto int32_ty = + type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 32); auto value_sp(valobj.GetSyntheticChildAtOffset(0, int64_ty, true)); auto timescale_sp(valobj.GetSyntheticChildAtOffset(8, int32_ty, true)); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp index 8d648d8a0861..b0398dd19c02 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -96,7 +96,7 @@ private: D32 *m_data_32; D64 *m_data_64; }; - + namespace Foundation1010 { namespace { struct DataDescriptor_32 { @@ -107,7 +107,7 @@ namespace Foundation1010 { uint32_t _priv2; uint32_t _data; }; - + struct DataDescriptor_64 { uint64_t _used; uint64_t _offset; @@ -117,11 +117,11 @@ namespace Foundation1010 { uint64_t _data; }; } - + using NSArrayMSyntheticFrontEnd = GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; } - + namespace Foundation1428 { namespace { struct DataDescriptor_32 { @@ -130,7 +130,7 @@ namespace Foundation1428 { uint32_t _size; uint32_t _data; }; - + struct DataDescriptor_64 { uint64_t _used; uint64_t _offset; @@ -138,11 +138,11 @@ namespace Foundation1428 { uint64_t _data; }; } - + using NSArrayMSyntheticFrontEnd = GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; } - + namespace Foundation1437 { template <typename PtrType> struct DataDescriptor { @@ -154,11 +154,11 @@ namespace Foundation1437 { uint32_t _muts; uint32_t _used; }; - + using NSArrayMSyntheticFrontEnd = GenericNSArrayMSyntheticFrontEnd< DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>; - + template <typename DD> uint64_t __NSArrayMSize_Impl(lldb_private::Process &process, @@ -173,7 +173,7 @@ namespace Foundation1437 { } return descriptor._used; } - + uint64_t __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, Status &error) { @@ -227,23 +227,23 @@ public: private: ExecutionContextRef m_exe_ctx_ref; uint8_t m_ptr_size; - + D32 *m_data_32; D64 *m_data_64; CompilerType m_id_type; }; - + namespace Foundation1300 { struct IDD32 { uint32_t used; uint32_t list; }; - + struct IDD64 { uint64_t used; uint64_t list; }; - + using NSArrayISyntheticFrontEnd = GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>; } @@ -258,18 +258,18 @@ namespace Foundation1436 { uint32_t used; uint32_t list; // in Inline cases, this is the first element }; - + struct IDD64 { uint64_t used; uint64_t list; // in Inline cases, this is the first element }; - + using NSArrayI_TransferSyntheticFrontEnd = GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>; using NSArrayISyntheticFrontEnd = GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>; - + using NSFrozenArrayMSyntheticFrontEnd = Foundation1437::NSArrayMSyntheticFrontEnd; @@ -441,7 +441,7 @@ lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontE : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), m_id_type() { if (valobj_sp) { - auto *clang_ast_context = TypeSystemClang::GetScratch( + auto *clang_ast_context = ScratchTypeSystemClang::GetForTarget( *valobj_sp->GetExecutionContextRef().GetTargetSP()); if (clang_ast_context) m_id_type = CompilerType( @@ -589,7 +589,7 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: if (valobj_sp) { CompilerType type = valobj_sp->GetCompilerType(); if (type) { - auto *clang_ast_context = TypeSystemClang::GetScratch( + auto *clang_ast_context = ScratchTypeSystemClang::GetForTarget( *valobj_sp->GetExecutionContextRef().GetTargetSP()); if (clang_ast_context) m_id_type = clang_ast_context->GetType( @@ -758,7 +758,7 @@ lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex( if (idx == 0) { auto *clang_ast_context = - TypeSystemClang::GetScratch(*m_backend.GetTargetSP()); + ScratchTypeSystemClang::GetForTarget(*m_backend.GetTargetSP()); if (clang_ast_context) { CompilerType id_type( clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID)); @@ -820,11 +820,9 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator( return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp)); if (runtime->GetFoundationVersion() >= 1430) return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp)); - else - return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp)); + return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp)); } else if (class_name == g_NSArrayI_Transfer) { return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp)); - } else if (class_name == g_NSArray0) { } else if (class_name == g_NSFrozenArrayM) { return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp)); } else if (class_name == g_NSArray0) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 3dc07678f92f..afb9c6951f55 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -66,7 +66,8 @@ NSDictionary_Additionals::GetAdditionalSynthetics() { static CompilerType GetLLDBNSPairType(TargetSP target_sp) { CompilerType compiler_type; - TypeSystemClang *target_ast_context = TypeSystemClang::GetScratch(*target_sp); + TypeSystemClang *target_ast_context = + ScratchTypeSystemClang::GetForTarget(*target_sp); if (target_ast_context) { ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair"); @@ -388,7 +389,7 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( return false; ObjCLanguageRuntime::ClassDescriptorSP descriptor( - runtime->GetClassDescriptor(valobj)); + runtime->GetNonKVOClassDescriptor(valobj)); if (!descriptor || !descriptor->IsValid()) return false; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp index aa1103cb342c..4ffa072f9f53 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp @@ -87,7 +87,7 @@ bool lldb_private::formatters::NSError_SummaryProvider( ValueObjectSP domain_str_sp = ValueObject::CreateValueObjectFromData( "domain_str", isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), - TypeSystemClang::GetScratch(process_sp->GetTarget()) + ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()) ->GetBasicType(lldb::eBasicTypeVoid) .GetPointerType()); @@ -156,7 +156,7 @@ public: m_child_sp = CreateValueObjectFromData( "_userInfo", isw.GetAsData(process_sp->GetByteOrder()), m_backend.GetExecutionContextRef(), - TypeSystemClang::GetScratch(process_sp->GetTarget()) + ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()) ->GetBasicType(lldb::eBasicTypeObjCID)); return false; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp index c6bae5e1c008..7360abb8fdd2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp @@ -69,7 +69,8 @@ static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp, InferiorSizedWord userinfo_isw(userinfo, *process_sp); InferiorSizedWord reserved_isw(reserved, *process_sp); - auto *clang_ast_context = TypeSystemClang::GetScratch(process_sp->GetTarget()); + auto *clang_ast_context = + ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()); if (!clang_ast_context) return false; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp index d962f39611b6..a15b0f64954a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp @@ -53,7 +53,7 @@ public: if (!type_system) return false; - TypeSystemClang *ast = TypeSystemClang::GetScratch( + TypeSystemClang *ast = ScratchTypeSystemClang::GetForTarget( *m_backend.GetExecutionContextRef().GetTargetSP()); if (!ast) return false; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.cpp index b9d0d73cbc2e..85922992eb2b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -34,7 +34,7 @@ NSString_Additionals::GetAdditionalSummaries() { static CompilerType GetNSPathStore2Type(Target &target) { static ConstString g_type_name("__lldb_autogen_nspathstore2"); - TypeSystemClang *ast_ctx = TypeSystemClang::GetScratch(target); + TypeSystemClang *ast_ctx = ScratchTypeSystemClang::GetForTarget(target); if (!ast_ctx) return CompilerType(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h index bed62a5c447a..02c15e86046b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h @@ -119,6 +119,8 @@ public: bool IsNilReference(ValueObject &valobj) override; + llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; } + bool IsSourceFile(llvm::StringRef file_path) const override; const Highlighter *GetHighlighter() const override { return &m_highlighter; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h index 4b3d23653347..233fd5c00a7a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h @@ -27,6 +27,8 @@ public: return lldb::eLanguageTypeObjC_plus_plus; } + llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; } + bool IsSourceFile(llvm::StringRef file_path) const override; const Highlighter *GetHighlighter() const override { return &m_highlighter; } diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 8aa803a8553e..24ab9cc5f238 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -37,9 +37,6 @@ static ConstString g_this = ConstString("this"); char CPPLanguageRuntime::ID = 0; -// Destructor -CPPLanguageRuntime::~CPPLanguageRuntime() {} - CPPLanguageRuntime::CPPLanguageRuntime(Process *process) : LanguageRuntime(process) {} @@ -102,9 +99,7 @@ line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol, CPPLanguageRuntime::LibCppStdFunctionCallableInfo CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( lldb::ValueObjectSP &valobj_sp) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo"); + LLDB_SCOPED_TIMER(); LibCppStdFunctionCallableInfo optional_info; @@ -154,6 +149,9 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( member__f_ = sub_member__f_; } + if (!member__f_) + return optional_info; + lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0); optional_info.member__f_pointer_value = member__f_pointer_value; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h index 5b00590e6301..3f5b99351872 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h @@ -40,8 +40,6 @@ public: LibCppStdFunctionCallableInfo FindLibCppStdFunctionCallableInfo(lldb::ValueObjectSP &valobj_sp); - ~CPPLanguageRuntime() override; - static char ID; bool isA(const void *ClassID) const override { @@ -89,9 +87,6 @@ private: llvm::StringMap<CPPLanguageRuntime::LibCppStdFunctionCallableInfo>; OperatorStringToCallableInfoMap CallableLookupCache; - - CPPLanguageRuntime(const CPPLanguageRuntime &) = delete; - const CPPLanguageRuntime &operator=(const CPPLanguageRuntime &) = delete; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 3ab32641d9c1..6ea9751f563a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -536,7 +536,7 @@ ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( return {}; TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(m_process->GetTarget()); + ScratchTypeSystemClang::GetForTarget(m_process->GetTarget()); if (!clang_ast_context) return {}; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 22ea83a57beb..973a5570c06e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -122,7 +122,8 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, } } else { // If it is not a pointer, see if we can make it into a pointer. - TypeSystemClang *ast_context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *ast_context = + ScratchTypeSystemClang::GetForTarget(*target); if (!ast_context) return false; @@ -137,7 +138,7 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, arg_value_list.PushValue(value); // This is the return value: - TypeSystemClang *ast_context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *ast_context = ScratchTypeSystemClang::GetForTarget(*target); if (!ast_context) return false; @@ -376,12 +377,7 @@ AppleObjCRuntime::GetObjCVersion(Process *process, ModuleSP &objc_module_sp) { llvm::Triple::VendorType::Apple) return ObjCRuntimeVersions::eObjC_VersionUnknown; - const ModuleList &target_modules = target.GetImages(); - std::lock_guard<std::recursive_mutex> gaurd(target_modules.GetMutex()); - - size_t num_images = target_modules.GetSize(); - for (size_t i = 0; i < num_images; i++) { - ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); + for (ModuleSP module_sp : target.GetImages().Modules()) { // One tricky bit here is that we might get called as part of the initial // module loading, but before all the pre-run libraries get winnowed from // the module list. So there might actually be an old and incorrect ObjC @@ -525,7 +521,7 @@ ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( return FailExceptionParsing("Failed to get synthetic value."); TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(*exception_sp->GetTargetSP()); + ScratchTypeSystemClang::GetForTarget(*exception_sp->GetTargetSP()); if (!clang_ast_context) return FailExceptionParsing("Failed to get scratch AST."); CompilerType objc_id = diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 8202686597ae..b37e5a9a7bf9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -122,58 +122,60 @@ struct BufStruct { char contents[2048]; }; -UtilityFunction *AppleObjCRuntimeV1::CreateObjectChecker(const char *name) { +llvm::Expected<std::unique_ptr<UtilityFunction>> +AppleObjCRuntimeV1::CreateObjectChecker(std::string name, + ExecutionContext &exe_ctx) { std::unique_ptr<BufStruct> buf(new BufStruct); - int strformatsize = snprintf(&buf->contents[0], sizeof(buf->contents), - "struct __objc_class " - " \n" - "{ " - " \n" - " struct __objc_class *isa; " - " \n" - " struct __objc_class *super_class; " - " \n" - " const char *name; " - " \n" - " // rest of struct elided because unused " - " \n" - "}; " - " \n" - " " - " \n" - "struct __objc_object " - " \n" - "{ " - " \n" - " struct __objc_class *isa; " - " \n" - "}; " - " \n" - " " - " \n" - "extern \"C\" void " - " \n" - "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) " - " \n" - "{ " - " \n" - " struct __objc_object *obj = (struct " - "__objc_object*)$__lldb_arg_obj; \n" - " if ($__lldb_arg_obj == (void *)0) " - " \n" - " return; // nil is ok " - " (int)strlen(obj->isa->name); " - " \n" - "} " - " \n", - name); + int strformatsize = + snprintf(&buf->contents[0], sizeof(buf->contents), + "struct __objc_class " + " \n" + "{ " + " \n" + " struct __objc_class *isa; " + " \n" + " struct __objc_class *super_class; " + " \n" + " const char *name; " + " \n" + " // rest of struct elided because unused " + " \n" + "}; " + " \n" + " " + " \n" + "struct __objc_object " + " \n" + "{ " + " \n" + " struct __objc_class *isa; " + " \n" + "}; " + " \n" + " " + " \n" + "extern \"C\" void " + " \n" + "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) " + " \n" + "{ " + " \n" + " struct __objc_object *obj = (struct " + "__objc_object*)$__lldb_arg_obj; \n" + " if ($__lldb_arg_obj == (void *)0) " + " \n" + " return; // nil is ok " + " (int)strlen(obj->isa->name); " + " \n" + "} " + " \n", + name.c_str()); assert(strformatsize < (int)sizeof(buf->contents)); (void)strformatsize; - Status error; - return GetTargetRef().GetUtilityFunctionForLanguage( - buf->contents, eLanguageTypeObjC, name, error); + return GetTargetRef().CreateUtilityFunction(buf->contents, std::move(name), + eLanguageTypeC, exe_ctx); } AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1( diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index d8725d0f57ce..4eb7d979394b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -97,7 +97,8 @@ public: Address &address, Value::ValueType &value_type) override; - UtilityFunction *CreateObjectChecker(const char *) override; + llvm::Expected<std::unique_ptr<UtilityFunction>> + CreateObjectChecker(std::string, ExecutionContext &exe_ctx) override; // PluginInterface protocol ConstString GetPluginName() override; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index ac9a09394021..ee84ccd869fc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -407,7 +407,7 @@ ExtractRuntimeGlobalSymbol(Process *process, ConstString name, } } -static void RegisterObjCExceptionRecognizer(); +static void RegisterObjCExceptionRecognizer(Process *process); AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, const ModuleSP &objc_module_sp) @@ -429,7 +429,7 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType( g_gdb_object_getClass, eSymbolTypeCode) != nullptr); - RegisterObjCExceptionRecognizer(); + RegisterObjCExceptionRecognizer(process); } bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( @@ -840,7 +840,9 @@ AppleObjCRuntimeV2::CreateExceptionResolver(const BreakpointSP &bkpt, return resolver_sp; } -UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { +llvm::Expected<std::unique_ptr<UtilityFunction>> +AppleObjCRuntimeV2::CreateObjectChecker(std::string name, + ExecutionContext &exe_ctx) { char check_function_code[2048]; int len = 0; @@ -861,7 +863,8 @@ UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { if ($responds == (signed char) 0) *((volatile int *)0) = 'ocgc'; } - })", name); + })", + name.c_str()); } else { len = ::snprintf(check_function_code, sizeof(check_function_code), R"( extern "C" void *gdb_class_getClass(void *); @@ -881,15 +884,15 @@ UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { if ($responds == (signed char) 0) *((volatile int *)0) = 'ocgc'; } - })", name); + })", + name.c_str()); } assert(len < (int)sizeof(check_function_code)); UNUSED_IF_ASSERT_DISABLED(len); - Status error; - return GetTargetRef().GetUtilityFunctionForLanguage( - check_function_code, eLanguageTypeObjC, name, error); + return GetTargetRef().CreateUtilityFunction(check_function_code, name, + eLanguageTypeC, exe_ctx); } size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type, @@ -1175,28 +1178,6 @@ AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) { return class_descriptor_sp; } -static std::pair<bool, ConstString> ObjCGetClassNameRaw( - AppleObjCRuntime::ObjCISA isa, - Process *process) { - StreamString expr_string; - std::string input = std::to_string(isa); - expr_string.Printf("(const char *)objc_debug_class_getNameRaw(%s)", - input.c_str()); - - ValueObjectSP result_sp; - EvaluateExpressionOptions eval_options; - eval_options.SetLanguage(lldb::eLanguageTypeObjC); - eval_options.SetResultIsInternal(true); - eval_options.SetGenerateDebugInfo(true); - eval_options.SetTimeout(process->GetUtilityExpressionTimeout()); - auto eval_result = process->GetTarget().EvaluateExpression( - expr_string.GetData(), - process->GetThreadList().GetSelectedThread()->GetSelectedFrame().get(), - result_sp, eval_options); - ConstString type_name(result_sp->GetSummaryAsCString()); - return std::make_pair(eval_result == eExpressionCompleted, type_name); -} - ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { ClassDescriptorSP objc_class_sp; @@ -1232,10 +1213,7 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { return objc_class_sp; objc_class_sp = GetClassDescriptorFromISA(isa); - - if (objc_class_sp) - return objc_class_sp; - else { + if (isa && !objc_class_sp) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); LLDB_LOGF(log, @@ -1244,13 +1222,6 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { "not in class descriptor cache 0x%" PRIx64, isa_pointer, isa); } - - ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, nullptr)); - auto resolved = ObjCGetClassNameRaw(isa, process); - if (resolved.first == true) { - AddClass(isa, descriptor_sp, resolved.second.AsCString()); - objc_class_sp = descriptor_sp; - } return objc_class_sp; } @@ -1333,15 +1304,14 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( return DescriptorMapUpdateResult::Fail(); thread_sp->CalculateExecutionContext(exe_ctx); - TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!ast) return DescriptorMapUpdateResult::Fail(); Address function_address; - DiagnosticManager diagnostics; - const uint32_t addr_size = process->GetAddressByteSize(); Status err; @@ -1363,28 +1333,16 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( FunctionCaller *get_class_info_function = nullptr; if (!m_get_class_info_code) { - Status error; - m_get_class_info_code.reset(GetTargetRef().GetUtilityFunctionForLanguage( - g_get_dynamic_class_info_body, eLanguageTypeObjC, - g_get_dynamic_class_info_name, error)); - if (error.Fail()) { - LLDB_LOGF(log, - "Failed to get Utility Function for implementation lookup: %s", - error.AsCString()); - m_get_class_info_code.reset(); - } else { - diagnostics.Clear(); - - if (!m_get_class_info_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install implementation lookup"); - diagnostics.Dump(log); - } - m_get_class_info_code.reset(); - } - } - if (!m_get_class_info_code) + auto utility_fn_or_error = GetTargetRef().CreateUtilityFunction( + g_get_dynamic_class_info_body, g_get_dynamic_class_info_name, + eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR( + log, utility_fn_or_error.takeError(), + "Failed to get utility function for implementation lookup: {0}"); return DescriptorMapUpdateResult::Fail(); + } + m_get_class_info_code = std::move(*utility_fn_or_error); // Next make the runner function for our implementation utility function. Value value; @@ -1398,6 +1356,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( arguments.PushValue(value); arguments.PushValue(value); + Status error; get_class_info_function = m_get_class_info_code->MakeFunctionCaller( clang_uint32_t_type, arguments, thread_sp, error); @@ -1410,17 +1369,13 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( } else { get_class_info_function = m_get_class_info_code->GetFunctionCaller(); if (!get_class_info_function) { - if (log) { - LLDB_LOGF(log, "Failed to get implementation lookup function caller."); - diagnostics.Dump(log); - } - + LLDB_LOGF(log, "Failed to get implementation lookup function caller."); return DescriptorMapUpdateResult::Fail(); } arguments = get_class_info_function->GetArgumentValues(); } - diagnostics.Clear(); + DiagnosticManager diagnostics; const uint32_t class_info_byte_size = addr_size + 4; const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; @@ -1593,15 +1548,14 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { return DescriptorMapUpdateResult::Fail(); thread_sp->CalculateExecutionContext(exe_ctx); - TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!ast) return DescriptorMapUpdateResult::Fail(); Address function_address; - DiagnosticManager diagnostics; - const uint32_t addr_size = process->GetAddressByteSize(); Status err; @@ -1636,10 +1590,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process); if (objc_runtime) { - const ModuleList &images = process->GetTarget().GetImages(); - std::lock_guard<std::recursive_mutex> guard(images.GetMutex()); - for (size_t i = 0; i < images.GetSize(); ++i) { - lldb::ModuleSP mod_sp = images.GetModuleAtIndexUnlocked(i); + for (lldb::ModuleSP mod_sp : process->GetTarget().GetImages().Modules()) { if (objc_runtime->IsModuleObjCLibrary(mod_sp)) { const Symbol *symbol = mod_sp->FindFirstSymbolWithNameAndType(g_class_getNameRaw_symbol_name, @@ -1663,29 +1614,17 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { shared_class_expression += g_get_shared_cache_class_info_body; - m_get_shared_cache_class_info_code.reset( - GetTargetRef().GetUtilityFunctionForLanguage( - shared_class_expression.c_str(), eLanguageTypeObjC, - g_get_shared_cache_class_info_name, error)); - if (error.Fail()) { - LLDB_LOGF(log, - "Failed to get Utility function for implementation lookup: %s.", - error.AsCString()); - m_get_shared_cache_class_info_code.reset(); - } else { - diagnostics.Clear(); - - if (!m_get_shared_cache_class_info_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install implementation lookup."); - diagnostics.Dump(log); - } - m_get_shared_cache_class_info_code.reset(); - } + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + std::move(shared_class_expression), g_get_shared_cache_class_info_name, + eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR( + log, utility_fn_or_error.takeError(), + "Failed to get utility function for implementation lookup: {0}"); + return DescriptorMapUpdateResult::Fail(); } - if (!m_get_shared_cache_class_info_code) - return DescriptorMapUpdateResult::Fail(); + m_get_shared_cache_class_info_code = std::move(*utility_fn_or_error); // Next make the function caller for our implementation utility function. Value value; @@ -1714,7 +1653,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { arguments = get_shared_cache_class_info_function->GetArgumentValues(); } - diagnostics.Clear(); + DiagnosticManager diagnostics; const uint32_t class_info_byte_size = addr_size + 4; const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; @@ -1889,10 +1828,9 @@ lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() { } void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + LLDB_SCOPED_TIMER(); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); // Else we need to check with our process to see when the map was updated. Process *process = GetProcess(); @@ -2669,7 +2607,7 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { if (!abi) return; TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(process_sp->GetTarget()); + ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()); if (!clang_ast_context) return; CompilerType voidstar = @@ -2709,18 +2647,19 @@ class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer { return lldb::RecognizedStackFrameSP( new ObjCExceptionRecognizedStackFrame(frame)); }; + std::string GetName() override { + return "ObjC Exception Throw StackFrame Recognizer"; + } }; -static void RegisterObjCExceptionRecognizer() { - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { - FileSpec module; - ConstString function; - std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); - std::vector<ConstString> symbols = {function}; - StackFrameRecognizerManager::AddRecognizer( - StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), - module.GetFilename(), symbols, - /*first_instruction_only*/ true); - }); +static void RegisterObjCExceptionRecognizer(Process *process) { + FileSpec module; + ConstString function; + std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); + std::vector<ConstString> symbols = {function}; + + process->GetTarget().GetFrameRecognizerManager().AddRecognizer( + StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), + module.GetFilename(), symbols, + /*first_instruction_only*/ true); } diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 99264d556da5..c6fb6ea26b98 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -53,7 +53,8 @@ public: Address &address, Value::ValueType &value_type) override; - UtilityFunction *CreateObjectChecker(const char *) override; + llvm::Expected<std::unique_ptr<UtilityFunction>> + CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override; // PluginInterface protocol ConstString GetPluginName() override; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index c96768c9f585..bcc1f6fd339f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -452,15 +452,11 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::InitializeVTableSymbols() { if (process_sp) { Target &target = process_sp->GetTarget(); - const ModuleList &target_modules = target.GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); - size_t num_modules = target_modules.GetSize(); if (!m_objc_module_sp) { - for (size_t i = 0; i < num_modules; i++) { + for (ModuleSP module_sp : target.GetImages().Modules()) { if (ObjCLanguageRuntime::Get(*process_sp) - ->IsModuleObjCLibrary( - target_modules.GetModuleAtIndexUnlocked(i))) { - m_objc_module_sp = target_modules.GetModuleAtIndexUnlocked(i); + ->IsModuleObjCLibrary(module_sp)) { + m_objc_module_sp = module_sp; break; } } @@ -521,7 +517,7 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines( const ABI *abi = process->GetABI().get(); TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(process->GetTarget()); + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!clang_ast_context) return false; @@ -798,7 +794,6 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, ValueList &dispatch_values) { ThreadSP thread_sp(thread.shared_from_this()); ExecutionContext exe_ctx(thread_sp); - DiagnosticManager diagnostics; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; @@ -812,35 +807,24 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, if (!m_impl_code) { if (m_lookup_implementation_function_code != nullptr) { - Status error; - m_impl_code.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - m_lookup_implementation_function_code, eLanguageTypeObjC, - g_lookup_implementation_function_name, error)); - if (error.Fail()) { - LLDB_LOGF( - log, - "Failed to get Utility Function for implementation lookup: %s.", - error.AsCString()); - m_impl_code.reset(); - return args_addr; - } - - if (!m_impl_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install implementation lookup."); - diagnostics.Dump(log); - } - m_impl_code.reset(); + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + m_lookup_implementation_function_code, + g_lookup_implementation_function_name, eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR( + log, utility_fn_or_error.takeError(), + "Failed to get Utility Function for implementation lookup: {0}."); return args_addr; } + m_impl_code = std::move(*utility_fn_or_error); } else { LLDB_LOGF(log, "No method lookup implementation code."); return LLDB_INVALID_ADDRESS; } // Next make the runner function for our implementation utility function. - TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(thread.GetProcess()->GetTarget()); + TypeSystemClang *clang_ast_context = ScratchTypeSystemClang::GetForTarget( + thread.GetProcess()->GetTarget()); if (!clang_ast_context) return LLDB_INVALID_ADDRESS; @@ -861,14 +845,13 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, } } - diagnostics.Clear(); - // Now write down the argument values for this particular call. // This looks like it might be a race condition if other threads // were calling into here, but actually it isn't because we allocate // a new args structure for this call by passing args_addr = // LLDB_INVALID_ADDRESS... + DiagnosticManager diagnostics; if (!impl_function_caller->WriteFunctionArguments( exe_ctx, args_addr, dispatch_values, diagnostics)) { if (log) { @@ -944,7 +927,8 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, TargetSP target_sp(thread.CalculateTarget()); - TypeSystemClang *clang_ast_context = TypeSystemClang::GetScratch(*target_sp); + TypeSystemClang *clang_ast_context = + ScratchTypeSystemClang::GetForTarget(*target_sp); if (!clang_ast_context) return ret_plan_sp; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h index c43acf54bbcd..683eff777728 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h @@ -251,7 +251,8 @@ public: llvm::Optional<CompilerType> GetRuntimeType(CompilerType base_type) override; - virtual UtilityFunction *CreateObjectChecker(const char *) = 0; + virtual llvm::Expected<std::unique_ptr<UtilityFunction>> + CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) = 0; virtual ObjCRuntimeVersions GetRuntimeVersion() const { return ObjCRuntimeVersions::eObjC_VersionUnknown; diff --git a/contrib/llvm-project/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/contrib/llvm-project/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index 333113a0b17a..7d9976285192 100644 --- a/contrib/llvm-project/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -36,13 +36,8 @@ MemoryHistorySP MemoryHistoryASan::CreateInstance(const ProcessSP &process_sp) { Target &target = process_sp->GetTarget(); - const ModuleList &target_modules = target.GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); - const size_t num_modules = target_modules.GetSize(); - for (size_t i = 0; i < num_modules; ++i) { - Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i); - - const Symbol *symbol = module_pointer->FindFirstSymbolWithNameAndType( + for (ModuleSP module_sp : target.GetImages().Modules()) { + const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( ConstString("__asan_get_alloc_stack"), lldb::eSymbolTypeAny); if (symbol != nullptr) diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 83cf9f8bd269..211eb9ce0d3a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -300,9 +300,7 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( DataExtractor data; data.SetData(data_sp, data_offset, length); if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data)) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, + LLDB_SCOPED_TIMERF( "ObjectContainerBSDArchive::CreateInstance (module = %s, file = " "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", module_sp->GetFileSpec().GetPath().c_str(), diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index bca575b7f884..cad9ce218b10 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -296,9 +296,23 @@ static uint32_t mipsVariantFromElfFlags (const elf::ELFHeader &header) { return arch_variant; } +static uint32_t riscvVariantFromElfFlags(const elf::ELFHeader &header) { + uint32_t fileclass = header.e_ident[EI_CLASS]; + switch (fileclass) { + case llvm::ELF::ELFCLASS32: + return ArchSpec::eRISCVSubType_riscv32; + case llvm::ELF::ELFCLASS64: + return ArchSpec::eRISCVSubType_riscv64; + default: + return ArchSpec::eRISCVSubType_unknown; + } +} + static uint32_t subTypeFromElfHeader(const elf::ELFHeader &header) { if (header.e_machine == llvm::ELF::EM_MIPS) return mipsVariantFromElfFlags(header); + else if (header.e_machine == llvm::ELF::EM_RISCV) + return riscvVariantFromElfFlags(header); return LLDB_INVALID_CPUTYPE; } @@ -576,9 +590,7 @@ size_t ObjectFileELF::GetModuleSpecifications( uint32_t core_notes_crc = 0; if (!gnu_debuglink_crc) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - lldb_private::Timer scoped_timer( - func_cat, + LLDB_SCOPED_TIMERF( "Calculating module crc32 %s with size %" PRIu64 " KiB", file.GetLastPathComponent().AsCString(), (length - file_offset) / 1024); diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp new file mode 100644 index 000000000000..35a823e9a28f --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -0,0 +1,197 @@ +//===-- ObjectFilePDB.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 "ObjectFilePDB.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Utility/StreamString.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/Support/BinaryByteStream.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm::pdb; +using namespace llvm::codeview; + +LLDB_PLUGIN_DEFINE(ObjectFilePDB) + +static UUID GetPDBUUID(InfoStream &IS) { + UUID::CvRecordPdb70 debug_info; + memcpy(&debug_info.Uuid, IS.getGuid().Guid, sizeof(debug_info.Uuid)); + debug_info.Age = IS.getAge(); + return UUID::fromCvRecord(debug_info); +} + +char ObjectFilePDB::ID; + +void ObjectFilePDB::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFilePDB::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString ObjectFilePDB::GetPluginNameStatic() { + static ConstString g_name("pdb"); + return g_name; +} + +ArchSpec ObjectFilePDB::GetArchitecture() { + auto dbi_stream = m_file_up->getPDBDbiStream(); + if (!dbi_stream) { + llvm::consumeError(dbi_stream.takeError()); + return ArchSpec(); + } + + PDB_Machine machine = dbi_stream->getMachineType(); + switch (machine) { + default: + break; + case PDB_Machine::Amd64: + case PDB_Machine::x86: + case PDB_Machine::PowerPC: + case PDB_Machine::PowerPCFP: + case PDB_Machine::Arm: + case PDB_Machine::ArmNT: + case PDB_Machine::Thumb: + case PDB_Machine::Arm64: + ArchSpec arch; + arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine), + LLDB_INVALID_CPUTYPE); + return arch; + } + return ArchSpec(); +} + +bool ObjectFilePDB::initPDBFile() { + m_file_up = loadPDBFile(m_file.GetPath(), m_allocator); + if (!m_file_up) + return false; + auto info_stream = m_file_up->getPDBInfoStream(); + if (!info_stream) { + llvm::consumeError(info_stream.takeError()); + return false; + } + m_uuid = GetPDBUUID(*info_stream); + return true; +} + +ObjectFile * +ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t file_offset, offset_t length) { + auto objfile_up = std::make_unique<ObjectFilePDB>( + module_sp, data_sp, data_offset, file, file_offset, length); + if (!objfile_up->initPDBFile()) + return nullptr; + return objfile_up.release(); +} + +ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp, + DataBufferSP &data_sp, + const ProcessSP &process_sp, + addr_t header_addr) { + return nullptr; +} + +size_t ObjectFilePDB::GetModuleSpecifications( + const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, + offset_t file_offset, offset_t length, ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + ModuleSpec module_spec(file); + llvm::BumpPtrAllocator allocator; + std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator); + if (!pdb_file) + return initial_count; + + auto info_stream = pdb_file->getPDBInfoStream(); + if (!info_stream) { + llvm::consumeError(info_stream.takeError()); + return initial_count; + } + auto dbi_stream = pdb_file->getPDBDbiStream(); + if (!dbi_stream) { + llvm::consumeError(dbi_stream.takeError()); + return initial_count; + } + + lldb_private::UUID &uuid = module_spec.GetUUID(); + uuid = GetPDBUUID(*info_stream); + + ArchSpec &module_arch = module_spec.GetArchitecture(); + switch (dbi_stream->getMachineType()) { + case PDB_Machine::Amd64: + module_arch.SetTriple("x86_64-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::x86: + module_arch.SetTriple("i386-pc-windows"); + specs.Append(module_spec); + module_arch.SetTriple("i686-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::ArmNT: + module_arch.SetTriple("armv7-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::Arm64: + module_arch.SetTriple("aarch64-pc-windows"); + specs.Append(module_spec); + break; + default: + break; + } + + return specs.GetSize() - initial_count; +} + +ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t offset, offset_t length) + : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {} + +std::unique_ptr<PDBFile> +ObjectFilePDB::loadPDBFile(std::string PdbPath, + llvm::BumpPtrAllocator &Allocator) { + llvm::file_magic magic; + auto ec = llvm::identify_magic(PdbPath, magic); + if (ec || magic != llvm::file_magic::pdb) + return nullptr; + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer = + llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + if (!ErrorOrBuffer) + return nullptr; + std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); + + llvm::StringRef Path = Buffer->getBufferIdentifier(); + auto Stream = std::make_unique<llvm::MemoryBufferByteStream>( + std::move(Buffer), llvm::support::little); + + auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator); + if (auto EC = File->parseFileHeaders()) { + llvm::consumeError(std::move(EC)); + return nullptr; + } + if (auto EC = File->parseStreamData()) { + llvm::consumeError(std::move(EC)); + return nullptr; + } + + return File; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h new file mode 100644 index 000000000000..19dd46b31406 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h @@ -0,0 +1,107 @@ +//===-- ObjectFilePDB.h --------------------------------------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +namespace lldb_private { + +class ObjectFilePDB : public ObjectFile { +public: + // Static Functions + static void Initialize(); + static void Terminate(); + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic() { + return "PDB object file reader."; + } + + static std::unique_ptr<llvm::pdb::PDBFile> + loadPDBFile(std::string PdbPath, llvm::BumpPtrAllocator &Allocator); + + static ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + ModuleSpecList &specs); + + // PluginInterface protocol + ConstString GetPluginName() override { return GetPluginNameStatic(); } + + uint32_t GetPluginVersion() override { return 1; } + + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + + // ObjectFile Protocol. + uint32_t GetAddressByteSize() const override { return 8; } + + lldb::ByteOrder GetByteOrder() const override { + return lldb::eByteOrderLittle; + } + + bool ParseHeader() override { return true; } + + bool IsExecutable() const override { return false; } + + Symtab *GetSymtab() override { return nullptr; } + + bool IsStripped() override { return false; } + + // No section in PDB file. + void CreateSections(SectionList &unified_section_list) override {} + + void Dump(Stream *s) override {} + + ArchSpec GetArchitecture() override; + + UUID GetUUID() override { return m_uuid; } + + uint32_t GetDependentModules(FileSpecList &files) override { return 0; } + + Type CalculateType() override { return eTypeDebugInfo; } + + Strata CalculateStrata() override { return eStrataUser; } + + llvm::pdb::PDBFile &GetPDBFile() { return *m_file_up; } + + ObjectFilePDB(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + +private: + UUID m_uuid; + llvm::BumpPtrAllocator m_allocator; + std::unique_ptr<llvm::pdb::PDBFile> m_file_up; + + bool initPDBFile(); +}; + +} // namespace lldb_private +#endif // LLDB_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp index 91150fa02ebc..6c29c2326212 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -253,6 +253,43 @@ bool ObjectFileWasm::ParseHeader() { Symtab *ObjectFileWasm::GetSymtab() { return nullptr; } +static SectionType GetSectionTypeFromName(llvm::StringRef Name) { + if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) { + return llvm::StringSwitch<SectionType>(Name) + .Case("abbrev", eSectionTypeDWARFDebugAbbrev) + .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo) + .Case("addr", eSectionTypeDWARFDebugAddr) + .Case("aranges", eSectionTypeDWARFDebugAranges) + .Case("cu_index", eSectionTypeDWARFDebugCuIndex) + .Case("frame", eSectionTypeDWARFDebugFrame) + .Case("info", eSectionTypeDWARFDebugInfo) + .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo) + .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine) + .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr) + .Case("loc", eSectionTypeDWARFDebugLoc) + .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo) + .Case("loclists", eSectionTypeDWARFDebugLocLists) + .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo) + .Case("macinfo", eSectionTypeDWARFDebugMacInfo) + .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro) + .Case("names", eSectionTypeDWARFDebugNames) + .Case("pubnames", eSectionTypeDWARFDebugPubNames) + .Case("pubtypes", eSectionTypeDWARFDebugPubTypes) + .Case("ranges", eSectionTypeDWARFDebugRanges) + .Case("rnglists", eSectionTypeDWARFDebugRngLists) + .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo) + .Case("str", eSectionTypeDWARFDebugStr) + .Case("str.dwo", eSectionTypeDWARFDebugStrDwo) + .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets) + .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) + .Case("tu_index", eSectionTypeDWARFDebugTuIndex) + .Case("types", eSectionTypeDWARFDebugTypes) + .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo) + .Default(eSectionTypeOther); + } + return eSectionTypeOther; +} + void ObjectFileWasm::CreateSections(SectionList &unified_section_list) { if (m_sections_up) return; @@ -280,29 +317,7 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) { // Code section. vm_addr = 0; } else { - section_type = - llvm::StringSwitch<SectionType>(sect_info.name.GetStringRef()) - .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) - .Case(".debug_addr", eSectionTypeDWARFDebugAddr) - .Case(".debug_aranges", eSectionTypeDWARFDebugAranges) - .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex) - .Case(".debug_frame", eSectionTypeDWARFDebugFrame) - .Case(".debug_info", eSectionTypeDWARFDebugInfo) - .Case(".debug_line", eSectionTypeDWARFDebugLine) - .Case(".debug_line_str", eSectionTypeDWARFDebugLineStr) - .Case(".debug_loc", eSectionTypeDWARFDebugLoc) - .Case(".debug_loclists", eSectionTypeDWARFDebugLocLists) - .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo) - .Case(".debug_macro", eSectionTypeDWARFDebugMacro) - .Case(".debug_names", eSectionTypeDWARFDebugNames) - .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames) - .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes) - .Case(".debug_ranges", eSectionTypeDWARFDebugRanges) - .Case(".debug_rnglists", eSectionTypeDWARFDebugRngLists) - .Case(".debug_str", eSectionTypeDWARFDebugStr) - .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets) - .Case(".debug_types", eSectionTypeDWARFDebugTypes) - .Default(eSectionTypeOther); + section_type = GetSectionTypeFromName(sect_info.name.GetStringRef()); if (section_type == eSectionTypeOther) continue; section_name = sect_info.name; diff --git a/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index 417aa2e21436..4350010f0296 100644 --- a/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -133,8 +133,8 @@ DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() { if (!dictionary) return nullptr; - m_register_info_up.reset(new DynamicRegisterInfo( - *dictionary, m_process->GetTarget().GetArchitecture())); + m_register_info_up = std::make_unique<DynamicRegisterInfo>( + *dictionary, m_process->GetTarget().GetArchitecture()); assert(m_register_info_up->GetNumRegisters() > 0); assert(m_register_info_up->GetNumRegisterSets() > 0); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index 97c2f22b505f..6b39a83fd668 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -27,6 +27,9 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Host.h" + // Define these constants from FreeBSD mman.h for use when targeting remote // FreeBSD systems even when host has different values. #define MAP_PRIVATE 0x0002 @@ -125,8 +128,6 @@ PlatformFreeBSD::PlatformFreeBSD(bool is_host) : PlatformPOSIX(is_host) // This is the local host platform {} -PlatformFreeBSD::~PlatformFreeBSD() = default; - bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) { if (IsHost()) { @@ -213,92 +214,13 @@ void PlatformFreeBSD::GetStatus(Stream &strm) { #endif } -size_t -PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode(Target &target, - BreakpointSite *bp_site) { - switch (target.GetArchitecture().GetMachine()) { - case llvm::Triple::arm: { - lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); - AddressClass addr_class = AddressClass::eUnknown; - - if (bp_loc_sp) { - addr_class = bp_loc_sp->GetAddress().GetAddressClass(); - if (addr_class == AddressClass::eUnknown && - (bp_loc_sp->GetAddress().GetFileAddress() & 1)) - addr_class = AddressClass::eCodeAlternateISA; - } - - if (addr_class == AddressClass::eCodeAlternateISA) { - // TODO: Enable when FreeBSD supports thumb breakpoints. - // FreeBSD kernel as of 10.x, does not support thumb breakpoints - return 0; - } - - static const uint8_t g_arm_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7}; - size_t trap_opcode_size = sizeof(g_arm_breakpoint_opcode); - assert(bp_site); - if (bp_site->SetTrapOpcode(g_arm_breakpoint_opcode, trap_opcode_size)) - return trap_opcode_size; - } - LLVM_FALLTHROUGH; - default: - return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site); - } -} - -Status PlatformFreeBSD::LaunchProcess(ProcessLaunchInfo &launch_info) { - Status error; - if (IsHost()) { - error = Platform::LaunchProcess(launch_info); - } else { - if (m_remote_platform_sp) - error = m_remote_platform_sp->LaunchProcess(launch_info); - else - error.SetErrorString("the platform is not currently connected"); - } - return error; -} - -lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info, - Debugger &debugger, Target *target, - Status &error) { - lldb::ProcessSP process_sp; +bool PlatformFreeBSD::CanDebugProcess() { if (IsHost()) { - if (target == nullptr) { - TargetSP new_target_sp; - ArchSpec emptyArchSpec; - - error = debugger.GetTargetList().CreateTarget( - debugger, "", emptyArchSpec, eLoadDependentsNo, m_remote_platform_sp, - new_target_sp); - target = new_target_sp.get(); - } else - error.Clear(); - - if (target && error.Success()) { - debugger.GetTargetList().SetSelectedTarget(target); - // The freebsd always currently uses the GDB remote debugger plug-in so - // even when debugging locally we are debugging remotely! Just like the - // darwin plugin. - process_sp = target->CreateProcess( - attach_info.GetListenerForProcess(debugger), "gdb-remote", nullptr); - - if (process_sp) - error = process_sp->Attach(attach_info); - } + return true; } else { - if (m_remote_platform_sp) - process_sp = - m_remote_platform_sp->Attach(attach_info, debugger, target, error); - else - error.SetErrorString("the platform is not currently connected"); + // If we're connected, we can debug. + return IsConnected(); } - return process_sp; -} - -// FreeBSD processes cannot yet be launched by spawning and attaching. -bool PlatformFreeBSD::CanDebugProcess() { - return false; } void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() { diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h index 56f2f2771d12..4fd10fb1be73 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h @@ -18,8 +18,6 @@ class PlatformFreeBSD : public PlatformPOSIX { public: PlatformFreeBSD(bool is_host); - ~PlatformFreeBSD() override; - static void Initialize(); static void Terminate(); @@ -46,24 +44,12 @@ public: bool CanDebugProcess() override; - size_t GetSoftwareBreakpointTrapOpcode(Target &target, - BreakpointSite *bp_site) override; - - Status LaunchProcess(ProcessLaunchInfo &launch_info) override; - - lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger, - Target *target, Status &error) override; - void CalculateTrapHandlerSymbolNames() override; MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, lldb::addr_t length, unsigned prot, unsigned flags, lldb::addr_t fd, lldb::addr_t offset) override; - -private: - PlatformFreeBSD(const PlatformFreeBSD &) = delete; - const PlatformFreeBSD &operator=(const PlatformFreeBSD &) = delete; }; } // namespace platform_freebsd diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp index caebd79c853e..a5d73c942830 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -117,8 +117,6 @@ PlatformNetBSD::PlatformNetBSD(bool is_host) : PlatformPOSIX(is_host) // This is the local host platform {} -PlatformNetBSD::~PlatformNetBSD() = default; - bool PlatformNetBSD::GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) { if (IsHost()) { @@ -187,9 +185,9 @@ void PlatformNetBSD::GetStatus(Stream &strm) { #endif } -int32_t +uint32_t PlatformNetBSD::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { - int32_t resume_count = 0; + uint32_t resume_count = 0; // Always resume past the initial stop when we use eLaunchFlagDebug if (launch_info.GetFlags().Test(eLaunchFlagDebug)) { @@ -231,121 +229,6 @@ bool PlatformNetBSD::CanDebugProcess() { } } -// For local debugging, NetBSD will override the debug logic to use llgs-launch -// rather than lldb-launch, llgs-attach. This differs from current lldb- -// launch, debugserver-attach approach on MacOSX. -lldb::ProcessSP -PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, - Target *target, // Can be NULL, if NULL create a new - // target, else use existing one - Status &error) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); - LLDB_LOG(log, "target {0}", target); - - // If we're a remote host, use standard behavior from parent class. - if (!IsHost()) - return PlatformPOSIX::DebugProcess(launch_info, debugger, target, error); - - // - // For local debugging, we'll insist on having ProcessGDBRemote create the - // process. - // - - ProcessSP process_sp; - - // Make sure we stop at the entry point - launch_info.GetFlags().Set(eLaunchFlagDebug); - - // We always launch the process we are going to debug in a separate process - // group, since then we can handle ^C interrupts ourselves w/o having to - // worry about the target getting them as well. - launch_info.SetLaunchInSeparateProcessGroup(true); - - // Ensure we have a target. - if (target == nullptr) { - LLDB_LOG(log, "creating new target"); - TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget( - debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); - if (error.Fail()) { - LLDB_LOG(log, "failed to create new target: {0}", error); - return process_sp; - } - - target = new_target_sp.get(); - if (!target) { - error.SetErrorString("CreateTarget() returned nullptr"); - LLDB_LOG(log, "error: {0}", error); - return process_sp; - } - } - - // Mark target as currently selected target. - debugger.GetTargetList().SetSelectedTarget(target); - - // Now create the gdb-remote process. - LLDB_LOG(log, "having target create process with gdb-remote plugin"); - process_sp = - target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr); - - if (!process_sp) { - error.SetErrorString("CreateProcess() failed for gdb-remote process"); - LLDB_LOG(log, "error: {0}", error); - return process_sp; - } - - LLDB_LOG(log, "successfully created process"); - // Adjust launch for a hijacker. - ListenerSP listener_sp; - if (!launch_info.GetHijackListener()) { - LLDB_LOG(log, "setting up hijacker"); - listener_sp = - Listener::MakeListener("lldb.PlatformNetBSD.DebugProcess.hijack"); - launch_info.SetHijackListener(listener_sp); - process_sp->HijackProcessEvents(listener_sp); - } - - // Log file actions. - if (log) { - LLDB_LOG(log, "launching process with the following file actions:"); - StreamString stream; - size_t i = 0; - const FileAction *file_action; - while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) { - file_action->Dump(stream); - LLDB_LOG(log, "{0}", stream.GetData()); - stream.Clear(); - } - } - - // Do the launch. - error = process_sp->Launch(launch_info); - if (error.Success()) { - // Handle the hijacking of process events. - if (listener_sp) { - const StateType state = process_sp->WaitForProcessToStop( - llvm::None, nullptr, false, listener_sp); - - LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state); - } - - // Hook up process PTY if we have one (which we should for local debugging - // with llgs). - int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); - if (pty_fd != PseudoTerminal::invalid_fd) { - process_sp->SetSTDIOFileDescriptor(pty_fd); - LLDB_LOG(log, "hooked up STDIO pty to process"); - } else - LLDB_LOG(log, "not using process STDIO pty"); - } else { - LLDB_LOG(log, "{0}", error); - // FIXME figure out appropriate cleanup here. Do we delete the target? Do - // we delete the process? Does our caller do that? - } - - return process_sp; -} - void PlatformNetBSD::CalculateTrapHandlerSymbolNames() { m_trap_handlers.push_back(ConstString("_sigtramp")); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h b/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h index d53e58418884..e664f5181123 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h @@ -18,8 +18,6 @@ class PlatformNetBSD : public PlatformPOSIX { public: PlatformNetBSD(bool is_host); - ~PlatformNetBSD() override; - static void Initialize(); static void Terminate(); @@ -44,24 +42,16 @@ public: bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override; - int32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; + uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; bool CanDebugProcess() override; - lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info, - Debugger &debugger, Target *target, - Status &error) override; - void CalculateTrapHandlerSymbolNames() override; MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, lldb::addr_t length, unsigned prot, unsigned flags, lldb::addr_t fd, lldb::addr_t offset) override; - -private: - PlatformNetBSD(const PlatformNetBSD &) = delete; - const PlatformNetBSD &operator=(const PlatformNetBSD &) = delete; }; } // namespace platform_netbsd diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp index a743970990a6..2cd024f56ec9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp @@ -123,8 +123,6 @@ PlatformOpenBSD::PlatformOpenBSD(bool is_host) : PlatformPOSIX(is_host) // This is the local host platform {} -PlatformOpenBSD::~PlatformOpenBSD() = default; - bool PlatformOpenBSD::GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) { if (IsHost()) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h b/contrib/llvm-project/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h index 9cfe32c3720c..e1402ae0ae9f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h @@ -18,8 +18,6 @@ class PlatformOpenBSD : public PlatformPOSIX { public: PlatformOpenBSD(bool is_host); - ~PlatformOpenBSD() override; - static void Initialize(); static void Terminate(); @@ -52,10 +50,6 @@ public: lldb::addr_t length, unsigned prot, unsigned flags, lldb::addr_t fd, lldb::addr_t offset) override; - -private: - PlatformOpenBSD(const PlatformOpenBSD &) = delete; - const PlatformOpenBSD &operator=(const PlatformOpenBSD &) = delete; }; } // namespace platform_openbsd diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 180ea1d2cfd1..3628b0a2ce5e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -377,7 +377,6 @@ lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, } if (target && error.Success()) { - debugger.GetTargetList().SetSelectedTarget(target); if (log) { ModuleSP exe_module_sp = target->GetExecutableModule(); LLDB_LOGF(log, "PlatformPOSIX::%s set selected target to %p %s", @@ -388,7 +387,7 @@ lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), - attach_info.GetProcessPluginName(), nullptr); + "gdb-remote", nullptr, true); if (process_sp) { ListenerSP listener_sp = attach_info.GetHijackListener(); @@ -416,24 +415,113 @@ PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new // target, else use existing one Status &error) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + LLDB_LOG(log, "target {0}", target); + ProcessSP process_sp; - if (IsHost()) { - // We are going to hand this process off to debugserver which will be in - // charge of setting the exit status. However, we still need to reap it - // from lldb. So, make sure we use a exit callback which does not set exit - // status. - const bool monitor_signals = false; - launch_info.SetMonitorProcessCallback( - &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals); - process_sp = Platform::DebugProcess(launch_info, debugger, target, error); - } else { + if (!IsHost()) { if (m_remote_platform_sp) process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, target, error); else error.SetErrorString("the platform is not currently connected"); + return process_sp; + } + + // + // For local debugging, we'll insist on having ProcessGDBRemote create the + // process. + // + + // Make sure we stop at the entry point + launch_info.GetFlags().Set(eLaunchFlagDebug); + + // We always launch the process we are going to debug in a separate process + // group, since then we can handle ^C interrupts ourselves w/o having to + // worry about the target getting them as well. + launch_info.SetLaunchInSeparateProcessGroup(true); + + // Ensure we have a target. + if (target == nullptr) { + LLDB_LOG(log, "creating new target"); + TargetSP new_target_sp; + error = debugger.GetTargetList().CreateTarget( + debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); + if (error.Fail()) { + LLDB_LOG(log, "failed to create new target: {0}", error); + return process_sp; + } + + target = new_target_sp.get(); + if (!target) { + error.SetErrorString("CreateTarget() returned nullptr"); + LLDB_LOG(log, "error: {0}", error); + return process_sp; + } } + + // Now create the gdb-remote process. + LLDB_LOG(log, "having target create process with gdb-remote plugin"); + process_sp = + target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr, + true); + + if (!process_sp) { + error.SetErrorString("CreateProcess() failed for gdb-remote process"); + LLDB_LOG(log, "error: {0}", error); + return process_sp; + } + + LLDB_LOG(log, "successfully created process"); + // Adjust launch for a hijacker. + ListenerSP listener_sp; + if (!launch_info.GetHijackListener()) { + LLDB_LOG(log, "setting up hijacker"); + listener_sp = + Listener::MakeListener("lldb.PlatformLinux.DebugProcess.hijack"); + launch_info.SetHijackListener(listener_sp); + process_sp->HijackProcessEvents(listener_sp); + } + + // Log file actions. + if (log) { + LLDB_LOG(log, "launching process with the following file actions:"); + StreamString stream; + size_t i = 0; + const FileAction *file_action; + while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) { + file_action->Dump(stream); + LLDB_LOG(log, "{0}", stream.GetData()); + stream.Clear(); + } + } + + // Do the launch. + error = process_sp->Launch(launch_info); + if (error.Success()) { + // Handle the hijacking of process events. + if (listener_sp) { + const StateType state = process_sp->WaitForProcessToStop( + llvm::None, nullptr, false, listener_sp); + + LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state); + } + + // Hook up process PTY if we have one (which we should for local debugging + // with llgs). + int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); + if (pty_fd != PseudoTerminal::invalid_fd) { + process_sp->SetSTDIOFileDescriptor(pty_fd); + LLDB_LOG(log, "hooked up STDIO pty to process"); + } else + LLDB_LOG(log, "not using process STDIO pty"); + } else { + LLDB_LOG(log, "{0}", error); + // FIXME figure out appropriate cleanup here. Do we delete the target? Do + // we delete the process? Does our caller do that? + } + return process_sp; } @@ -540,30 +628,26 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, expr.append(dlopen_wrapper_code); Status utility_error; DiagnosticManager diagnostics; - - std::unique_ptr<UtilityFunction> dlopen_utility_func_up(process - ->GetTarget().GetUtilityFunctionForLanguage(expr.c_str(), - eLanguageTypeObjC, - dlopen_wrapper_name, - utility_error)); - if (utility_error.Fail()) { - error.SetErrorStringWithFormat("dlopen error: could not make utility" - "function: %s", utility_error.AsCString()); - return nullptr; - } - if (!dlopen_utility_func_up->Install(diagnostics, exe_ctx)) { - error.SetErrorStringWithFormat("dlopen error: could not install utility" - "function: %s", - diagnostics.GetString().c_str()); + + auto utility_fn_or_error = process->GetTarget().CreateUtilityFunction( + std::move(expr), dlopen_wrapper_name, eLanguageTypeObjC, exe_ctx); + if (!utility_fn_or_error) { + std::string error_str = llvm::toString(utility_fn_or_error.takeError()); + error.SetErrorStringWithFormat("dlopen error: could not create utility" + "function: %s", + error_str.c_str()); return nullptr; } + std::unique_ptr<UtilityFunction> dlopen_utility_func_up = + std::move(*utility_fn_or_error); Value value; ValueList arguments; FunctionCaller *do_dlopen_function = nullptr; // Fetch the clang types we will need: - TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!ast) return nullptr; @@ -807,7 +891,8 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, Value return_value; // Fetch the clang types we will need: - TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!ast) { error.SetErrorString("dlopen error: Unable to get TypeSystemClang"); return LLDB_INVALID_IMAGE_TOKEN; diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 21bf7f4ac46d..6a4275d249f6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -495,12 +495,10 @@ lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess( error.Clear(); if (target && error.Success()) { - debugger.GetTargetList().SetSelectedTarget(target); - // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! process_sp = target->CreateProcess(launch_info.GetListener(), - "gdb-remote", nullptr); + "gdb-remote", nullptr, true); if (process_sp) { error = process_sp->ConnectRemote(connect_url.c_str()); @@ -581,13 +579,11 @@ lldb::ProcessSP PlatformRemoteGDBServer::Attach( error.Clear(); if (target && error.Success()) { - debugger.GetTargetList().SetSelectedTarget(target); - // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), - "gdb-remote", nullptr); + "gdb-remote", nullptr, true); if (process_sp) { error = process_sp->ConnectRemote(connect_url.c_str()); if (error.Success()) { @@ -661,6 +657,11 @@ PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) { return m_gdb_client.GetFileSize(file_spec); } +void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory( + CompletionRequest &request, bool only_dir) { + m_gdb_client.AutoCompleteDiskFileOrDirectory(request, only_dir); +} + uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Status &error) { @@ -706,7 +707,7 @@ bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) { } Status PlatformRemoteGDBServer::RunShellCommand( - const char *command, // Shouldn't be NULL + llvm::StringRef shell, llvm::StringRef command, const FileSpec & working_dir, // Pass empty FileSpec to use the current working directory int *status_ptr, // Pass NULL if you don't want the process exit status @@ -824,7 +825,7 @@ std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme, const char *hostname, uint16_t port, const char *path) { StreamString result; - result.Printf("%s://%s", scheme, hostname); + result.Printf("%s://[%s]", scheme, hostname); if (port != 0) result.Printf(":%u", port); if (path) @@ -832,18 +833,6 @@ std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme, return std::string(result.GetString()); } -lldb::ProcessSP PlatformRemoteGDBServer::ConnectProcess( - llvm::StringRef connect_url, llvm::StringRef plugin_name, - lldb_private::Debugger &debugger, lldb_private::Target *target, - lldb_private::Status &error) { - if (!IsRemote() || !IsConnected()) { - error.SetErrorString("Not connected to remote gdb server"); - return nullptr; - } - return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, - error); -} - size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger, Status &error) { std::vector<std::string> connection_urls; diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 0602be1fa377..e43cd0e55c6d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -127,6 +127,9 @@ public: lldb::user_id_t GetFileSize(const FileSpec &file_spec) override; + void AutoCompleteDiskFileOrDirectory(CompletionRequest &request, + bool only_dir) override; + Status PutFile(const FileSpec &source, const FileSpec &destination, uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) override; @@ -137,7 +140,7 @@ public: Status Unlink(const FileSpec &path) override; Status RunShellCommand( - const char *command, // Shouldn't be NULL + llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir, // Pass empty FileSpec to use the current // working directory int *status_ptr, // Pass NULL if you don't want the process exit status @@ -151,12 +154,6 @@ public: const lldb::UnixSignalsSP &GetRemoteUnixSignals() override; - lldb::ProcessSP ConnectProcess(llvm::StringRef connect_url, - llvm::StringRef plugin_name, - lldb_private::Debugger &debugger, - lldb_private::Target *target, - lldb_private::Status &error) override; - size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger, lldb_private::Status &error) override; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp deleted file mode 100644 index 896f68eadfe1..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp +++ /dev/null @@ -1,616 +0,0 @@ -//===-- FreeBSDThread.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 <errno.h> -#include <pthread.h> -#include <pthread_np.h> -#include <stdlib.h> -#include <sys/sysctl.h> -#include <sys/types.h> -#include <sys/user.h> - -#include "FreeBSDThread.h" -#include "POSIXStopInfo.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" -#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" -#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" -#include "ProcessFreeBSD.h" -#include "ProcessMonitor.h" -#include "RegisterContextPOSIXProcessMonitor_arm.h" -#include "RegisterContextPOSIXProcessMonitor_arm64.h" -#include "RegisterContextPOSIXProcessMonitor_mips64.h" -#include "RegisterContextPOSIXProcessMonitor_powerpc.h" -#include "RegisterContextPOSIXProcessMonitor_x86.h" -#include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Host/HostNativeThread.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/ThreadSpec.h" -#include "lldb/Target/UnixSignals.h" -#include "lldb/Target/Unwind.h" -#include "lldb/Utility/State.h" -#include "llvm/ADT/SmallString.h" - -using namespace lldb; -using namespace lldb_private; - -FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid) - : Thread(process, tid), m_frame_up(), m_breakpoint(), - m_thread_name_valid(false), m_thread_name(), m_posix_thread(nullptr) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - LLDB_LOGV(log, "tid = {0}", tid); - - // Set the current watchpoints for this thread. - Target &target = GetProcess()->GetTarget(); - const WatchpointList &wp_list = target.GetWatchpointList(); - size_t wp_size = wp_list.GetSize(); - - for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++) { - lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx); - if (wp.get() && wp->IsEnabled()) { - // This watchpoint as been enabled; obviously this "new" thread has been - // created since that watchpoint was enabled. Since the - // POSIXBreakpointProtocol has yet to be initialized, its - // m_watchpoints_initialized member will be FALSE. Attempting to read - // the debug status register to determine if a watchpoint has been hit - // would result in the zeroing of that register. Since the active debug - // registers would have been cloned when this thread was created, simply - // force the m_watchpoints_initized member to TRUE and avoid resetting - // dr6 and dr7. - GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized(); - } - } -} - -FreeBSDThread::~FreeBSDThread() { DestroyThread(); } - -ProcessMonitor &FreeBSDThread::GetMonitor() { - ProcessSP base = GetProcess(); - ProcessFreeBSD &process = static_cast<ProcessFreeBSD &>(*base); - return process.GetMonitor(); -} - -void FreeBSDThread::RefreshStateAfterStop() { - // Invalidate all registers in our register context. We don't set "force" to - // true because the stop reply packet might have had some register values - // that were expedited and these will already be copied into the register - // context by the time this function gets called. The KDPRegisterContext - // class has been made smart enough to detect when it needs to invalidate - // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do the - // right thing. if (StateIsStoppedState(GetState()) - { - const bool force = false; - GetRegisterContext()->InvalidateIfNeeded(force); - } -} - -const char *FreeBSDThread::GetInfo() { return nullptr; } - -void FreeBSDThread::SetName(const char *name) { - m_thread_name_valid = (name && name[0]); - if (m_thread_name_valid) - m_thread_name.assign(name); - else - m_thread_name.clear(); -} - -const char *FreeBSDThread::GetName() { - if (!m_thread_name_valid) { - m_thread_name.clear(); - int pid = GetProcess()->GetID(); - - struct kinfo_proc *kp = nullptr, *nkp; - size_t len = 0; - int error; - int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, - pid}; - - while (1) { - error = sysctl(ctl, 4, kp, &len, nullptr, 0); - if (kp == nullptr || (error != 0 && errno == ENOMEM)) { - // Add extra space in case threads are added before next call. - len += sizeof(*kp) + len / 10; - nkp = (struct kinfo_proc *)realloc(kp, len); - if (nkp == nullptr) { - free(kp); - return nullptr; - } - kp = nkp; - continue; - } - if (error != 0) - len = 0; - break; - } - - for (size_t i = 0; i < len / sizeof(*kp); i++) { - if (kp[i].ki_tid == (lwpid_t)GetID()) { - m_thread_name.append(kp[i].ki_tdname, - kp[i].ki_tdname + strlen(kp[i].ki_tdname)); - break; - } - } - free(kp); - m_thread_name_valid = true; - } - - if (m_thread_name.empty()) - return nullptr; - return m_thread_name.c_str(); -} - -lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() { - if (!m_reg_context_sp) { - m_posix_thread = nullptr; - - RegisterInfoInterface *reg_interface = nullptr; - const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); - - switch (target_arch.GetMachine()) { - case llvm::Triple::aarch64: - break; - case llvm::Triple::arm: - reg_interface = new RegisterInfoPOSIX_arm(target_arch); - break; - case llvm::Triple::ppc: -#ifndef __powerpc64__ - reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); - break; -#endif - case llvm::Triple::ppc64: - reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch); - break; - case llvm::Triple::mips64: - reg_interface = new RegisterContextFreeBSD_mips64(target_arch); - break; - case llvm::Triple::x86: - reg_interface = new RegisterContextFreeBSD_i386(target_arch); - break; - case llvm::Triple::x86_64: - reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); - break; - default: - llvm_unreachable("CPU not supported"); - } - - switch (target_arch.GetMachine()) { - case llvm::Triple::aarch64: { - RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = - new RegisterContextPOSIXProcessMonitor_arm64( - *this, std::make_unique<RegisterInfoPOSIX_arm64>(target_arch)); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::arm: { - RegisterContextPOSIXProcessMonitor_arm *reg_ctx = - new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::mips64: { - RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = - new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, - reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::ppc: - case llvm::Triple::ppc64: { - RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = - new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, - reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::x86: - case llvm::Triple::x86_64: { - RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = - new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, - reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - default: - break; - } - } - return m_reg_context_sp; -} - -lldb::RegisterContextSP -FreeBSDThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) { - lldb::RegisterContextSP reg_ctx_sp; - uint32_t concrete_frame_idx = 0; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - LLDB_LOGV(log, "called"); - - if (frame) - concrete_frame_idx = frame->GetConcreteFrameIndex(); - - if (concrete_frame_idx == 0) - reg_ctx_sp = GetRegisterContext(); - else { - reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); - } - - return reg_ctx_sp; -} - -lldb::addr_t FreeBSDThread::GetThreadPointer() { - ProcessMonitor &monitor = GetMonitor(); - addr_t addr; - if (monitor.ReadThreadPointer(GetID(), addr)) - return addr; - else - return LLDB_INVALID_ADDRESS; -} - -bool FreeBSDThread::CalculateStopInfo() { - SetStopInfo(m_stop_info_sp); - return true; -} - -void FreeBSDThread::DidStop() { - // Don't set the thread state to stopped unless we really stopped. -} - -void FreeBSDThread::WillResume(lldb::StateType resume_state) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - LLDB_LOGF(log, "tid %" PRIu64 " resume_state = %s", GetID(), - lldb_private::StateAsCString(resume_state)); - ProcessSP process_sp(GetProcess()); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get()); - int signo = GetResumeSignal(); - bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo); - - switch (resume_state) { - case eStateSuspended: - case eStateStopped: - process->m_suspend_tids.push_back(GetID()); - break; - case eStateRunning: - process->m_run_tids.push_back(GetID()); - if (signo_valid) - process->m_resume_signo = signo; - break; - case eStateStepping: - process->m_step_tids.push_back(GetID()); - if (signo_valid) - process->m_resume_signo = signo; - break; - default: - break; - } -} - -bool FreeBSDThread::Resume() { - lldb::StateType resume_state = GetResumeState(); - ProcessMonitor &monitor = GetMonitor(); - bool status; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - LLDB_LOGF(log, "FreeBSDThread::%s (), resume_state = %s", __FUNCTION__, - StateAsCString(resume_state)); - - switch (resume_state) { - default: - assert(false && "Unexpected state for resume!"); - status = false; - break; - - case lldb::eStateRunning: - SetState(resume_state); - status = monitor.Resume(GetID(), GetResumeSignal()); - break; - - case lldb::eStateStepping: - SetState(resume_state); - status = monitor.SingleStep(GetID(), GetResumeSignal()); - break; - case lldb::eStateStopped: - case lldb::eStateSuspended: - status = true; - break; - } - - return status; -} - -void FreeBSDThread::Notify(const ProcessMessage &message) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - LLDB_LOGF(log, "FreeBSDThread::%s () message kind = '%s' for tid %" PRIu64, - __FUNCTION__, message.PrintKind(), GetID()); - - switch (message.GetKind()) { - default: - assert(false && "Unexpected message kind!"); - break; - - case ProcessMessage::eExitMessage: - // Nothing to be done. - break; - - case ProcessMessage::eLimboMessage: - LimboNotify(message); - break; - - case ProcessMessage::eCrashMessage: - case ProcessMessage::eSignalMessage: - SignalNotify(message); - break; - - case ProcessMessage::eSignalDeliveredMessage: - SignalDeliveredNotify(message); - break; - - case ProcessMessage::eTraceMessage: - TraceNotify(message); - break; - - case ProcessMessage::eBreakpointMessage: - BreakNotify(message); - break; - - case ProcessMessage::eWatchpointMessage: - WatchNotify(message); - break; - - case ProcessMessage::eExecMessage: - ExecNotify(message); - break; - } -} - -bool FreeBSDThread::EnableHardwareWatchpoint(Watchpoint *wp) { - bool wp_set = false; - if (wp) { - addr_t wp_addr = wp->GetLoadAddress(); - size_t wp_size = wp->GetByteSize(); - bool wp_read = wp->WatchpointRead(); - bool wp_write = wp->WatchpointWrite(); - uint32_t wp_hw_index = wp->GetHardwareIndex(); - POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - wp_set = reg_ctx->SetHardwareWatchpointWithIndex( - wp_addr, wp_size, wp_read, wp_write, wp_hw_index); - } - return wp_set; -} - -bool FreeBSDThread::DisableHardwareWatchpoint(Watchpoint *wp) { - bool result = false; - if (wp) { - lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); - if (reg_ctx_sp.get()) - result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex()); - } - return result; -} - -uint32_t FreeBSDThread::NumSupportedHardwareWatchpoints() { - lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); - if (reg_ctx_sp.get()) - return reg_ctx_sp->NumSupportedHardwareWatchpoints(); - return 0; -} - -uint32_t FreeBSDThread::FindVacantWatchpointIndex() { - uint32_t hw_index = LLDB_INVALID_INDEX32; - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) { - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { - if (reg_ctx->IsWatchpointVacant(wp_idx)) { - hw_index = wp_idx; - break; - } - } - } - return hw_index; -} - -void FreeBSDThread::BreakNotify(const ProcessMessage &message) { - bool status; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - - assert(GetRegisterContext()); - status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint(); - assert(status && "Breakpoint update failed!"); - - // With our register state restored, resolve the breakpoint object - // corresponding to our current PC. - assert(GetRegisterContext()); - lldb::addr_t pc = GetRegisterContext()->GetPC(); - LLDB_LOGF(log, "FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); - lldb::BreakpointSiteSP bp_site( - GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); - - // If the breakpoint is for this thread, then we'll report the hit, but if it - // is for another thread, we create a stop reason with should_stop=false. If - // there is no breakpoint location, then report an invalid stop reason. We - // don't need to worry about stepping over the breakpoint here, that will be - // taken care of when the thread resumes and notices that there's a - // breakpoint under the pc. - if (bp_site) { - lldb::break_id_t bp_id = bp_site->GetID(); - // If we have an operating system plug-in, we might have set a thread - // specific breakpoint using the operating system thread ID, so we can't - // make any assumptions about the thread ID so we must always report the - // breakpoint regardless of the thread. - if (bp_site->ValidForThisThread(this) || - GetProcess()->GetOperatingSystem() != nullptr) - SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); - else { - const bool should_stop = false; - SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, - should_stop)); - } - } else - SetStopInfo(StopInfoSP()); -} - -void FreeBSDThread::WatchNotify(const ProcessMessage &message) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - - lldb::addr_t halt_addr = message.GetHWAddress(); - LLDB_LOGF(log, - "FreeBSDThread::%s () Hardware Watchpoint Address = 0x%8.8" PRIx64, - __FUNCTION__, halt_addr); - - POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) { - uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { - if (reg_ctx->IsWatchpointHit(wp_idx)) { - // Clear the watchpoint hit here - reg_ctx->ClearWatchpointHits(); - break; - } - } - - if (wp_idx == num_hw_wps) - return; - - Target &target = GetProcess()->GetTarget(); - lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx); - const WatchpointList &wp_list = target.GetWatchpointList(); - lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr); - - assert(wp_sp.get() && "No watchpoint found"); - SetStopInfo( - StopInfo::CreateStopReasonWithWatchpointID(*this, wp_sp->GetID())); - } -} - -void FreeBSDThread::TraceNotify(const ProcessMessage &message) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - - // Try to resolve the breakpoint object corresponding to the current PC. - assert(GetRegisterContext()); - lldb::addr_t pc = GetRegisterContext()->GetPC(); - LLDB_LOGF(log, "FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); - lldb::BreakpointSiteSP bp_site( - GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); - - // If the current pc is a breakpoint site then set the StopInfo to - // Breakpoint. Otherwise, set the StopInfo to Watchpoint or Trace. If we have - // an operating system plug-in, we might have set a thread specific - // breakpoint using the operating system thread ID, so we can't make any - // assumptions about the thread ID so we must always report the breakpoint - // regardless of the thread. - if (bp_site && (bp_site->ValidForThisThread(this) || - GetProcess()->GetOperatingSystem() != nullptr)) - SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID( - *this, bp_site->GetID())); - else { - POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) { - uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { - if (reg_ctx->IsWatchpointHit(wp_idx)) { - WatchNotify(message); - return; - } - } - } - SetStopInfo(StopInfo::CreateStopReasonToTrace(*this)); - } -} - -void FreeBSDThread::LimboNotify(const ProcessMessage &message) { - SetStopInfo(lldb::StopInfoSP(new POSIXLimboStopInfo(*this))); -} - -void FreeBSDThread::SignalNotify(const ProcessMessage &message) { - int signo = message.GetSignal(); - if (message.GetKind() == ProcessMessage::eCrashMessage) { - std::string stop_description = GetCrashReasonString( - message.GetCrashReason(), message.GetFaultAddress()); - SetStopInfo(StopInfo::CreateStopReasonWithSignal( - *this, signo, stop_description.c_str())); - } else { - SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo)); - } -} - -void FreeBSDThread::SignalDeliveredNotify(const ProcessMessage &message) { - int signo = message.GetSignal(); - SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo)); -} - -unsigned FreeBSDThread::GetRegisterIndexFromOffset(unsigned offset) { - unsigned reg = LLDB_INVALID_REGNUM; - ArchSpec arch = HostInfo::GetArchitecture(); - - switch (arch.GetMachine()) { - default: - llvm_unreachable("CPU type not supported!"); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::mips64: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::x86: - case llvm::Triple::x86_64: { - POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); - reg = reg_ctx->GetRegisterIndexFromOffset(offset); - } break; - } - return reg; -} - -void FreeBSDThread::ExecNotify(const ProcessMessage &message) { - SetStopInfo(StopInfo::CreateStopReasonWithExec(*this)); -} - -const char *FreeBSDThread::GetRegisterName(unsigned reg) { - const char *name = nullptr; - ArchSpec arch = HostInfo::GetArchitecture(); - - switch (arch.GetMachine()) { - default: - assert(false && "CPU type not supported!"); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::mips64: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - name = GetRegisterContext()->GetRegisterName(reg); - break; - } - return name; -} - -const char *FreeBSDThread::GetRegisterNameFromOffset(unsigned offset) { - return GetRegisterName(GetRegisterIndexFromOffset(offset)); -} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h deleted file mode 100644 index 774ffb511bc6..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h +++ /dev/null @@ -1,111 +0,0 @@ -//===-- FreeBSDThread.h -----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_FreeBSDThread_H_ -#define liblldb_FreeBSDThread_H_ - -#include <memory> -#include <string> - -#include "RegisterContextPOSIX.h" -#include "lldb/Target/Thread.h" - -class ProcessMessage; -class ProcessMonitor; -class POSIXBreakpointProtocol; - -// @class FreeBSDThread -// Abstraction of a FreeBSD thread. -class FreeBSDThread : public lldb_private::Thread { -public: - // Constructors and destructors - FreeBSDThread(lldb_private::Process &process, lldb::tid_t tid); - - virtual ~FreeBSDThread(); - - // POSIXThread - void RefreshStateAfterStop() override; - - // This notifies the thread when a private stop occurs. - void DidStop() override; - - const char *GetInfo() override; - - void SetName(const char *name) override; - - const char *GetName() override; - - lldb::RegisterContextSP GetRegisterContext() override; - - lldb::RegisterContextSP - CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; - - lldb::addr_t GetThreadPointer() override; - - // These functions provide a mapping from the register offset - // back to the register index or name for use in debugging or log - // output. - - unsigned GetRegisterIndexFromOffset(unsigned offset); - - const char *GetRegisterName(unsigned reg); - - const char *GetRegisterNameFromOffset(unsigned offset); - - // These methods form a specialized interface to POSIX threads. - // - bool Resume(); - - void Notify(const ProcessMessage &message); - - // These methods provide an interface to watchpoints - // - bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp); - - bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp); - - uint32_t NumSupportedHardwareWatchpoints(); - - uint32_t FindVacantWatchpointIndex(); - -protected: - POSIXBreakpointProtocol *GetPOSIXBreakpointProtocol() { - if (!m_reg_context_sp) - m_reg_context_sp = GetRegisterContext(); - return m_posix_thread; - } - - std::unique_ptr<lldb_private::StackFrame> m_frame_up; - - lldb::BreakpointSiteSP m_breakpoint; - - bool m_thread_name_valid; - std::string m_thread_name; - POSIXBreakpointProtocol *m_posix_thread; - - ProcessMonitor &GetMonitor(); - - bool CalculateStopInfo() override; - - void BreakNotify(const ProcessMessage &message); - void WatchNotify(const ProcessMessage &message); - virtual void TraceNotify(const ProcessMessage &message); - void LimboNotify(const ProcessMessage &message); - void SignalNotify(const ProcessMessage &message); - void SignalDeliveredNotify(const ProcessMessage &message); - void CrashNotify(const ProcessMessage &message); - void ExitNotify(const ProcessMessage &message); - void ExecNotify(const ProcessMessage &message); - - // FreeBSDThread internal API. - - // POSIXThread override - virtual void WillResume(lldb::StateType resume_state) override; -}; - -#endif // #ifndef liblldb_FreeBSDThread_H_ diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp new file mode 100644 index 000000000000..5961ff4439db --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp @@ -0,0 +1,921 @@ +//===-- NativeProcessFreeBSD.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 "NativeProcessFreeBSD.h" + +// clang-format off +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/sysctl.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <machine/elf.h> +// clang-format on + +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/State.h" +#include "llvm/Support/Errno.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; +using namespace llvm; + +// Simple helper function to ensure flags are enabled on the given file +// descriptor. +static Status EnsureFDFlags(int fd, int flags) { + Status error; + + int status = fcntl(fd, F_GETFL); + if (status == -1) { + error.SetErrorToErrno(); + return error; + } + + if (fcntl(fd, F_SETFL, status | flags) == -1) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +// Public Static Methods + +llvm::Expected<std::unique_ptr<NativeProcessProtocol>> +NativeProcessFreeBSD::Factory::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate, + MainLoop &mainloop) const { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); + } + + // Wait for the child process to trap on its call to execve. + int wstatus; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + (void)wpid; + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error<StringError>("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); + } + LLDB_LOG(log, "inferior started, now in stopped state"); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error<StringError>("Cannot get process architecture", + llvm::inconvertibleErrorCode()); + } + + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, + Info.GetArchitecture().GetArchitectureName()); + + std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD( + pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, + Info.GetArchitecture(), mainloop)); + + status = process_up->SetupTrace(); + if (status.Fail()) + return status.ToError(); + + for (const auto &thread : process_up->m_threads) + static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP); + process_up->SetState(StateType::eStateStopped, false); + + return std::move(process_up); +} + +llvm::Expected<std::unique_ptr<NativeProcessProtocol>> +NativeProcessFreeBSD::Factory::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, + MainLoop &mainloop) const { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "pid = {0:x}", pid); + + // Retrieve the architecture for the running process. + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error<StringError>("Cannot get process architecture", + llvm::inconvertibleErrorCode()); + } + + std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD( + pid, -1, native_delegate, Info.GetArchitecture(), mainloop)); + + Status status = process_up->Attach(); + if (!status.Success()) + return status.ToError(); + + return std::move(process_up); +} + +// Public Instance Methods + +NativeProcessFreeBSD::NativeProcessFreeBSD(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, + MainLoop &mainloop) + : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) { + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + + Status status; + m_sigchld_handle = mainloop.RegisterSignal( + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); +} + +// Handles all waitpid events from the inferior process. +void NativeProcessFreeBSD::MonitorCallback(lldb::pid_t pid, int signal) { + switch (signal) { + case SIGTRAP: + return MonitorSIGTRAP(pid); + case SIGSTOP: + return MonitorSIGSTOP(pid); + default: + return MonitorSignal(pid, signal); + } +} + +void NativeProcessFreeBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + + LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid); + + /* Stop Tracking All Threads attached to Process */ + m_threads.clear(); + + SetExitStatus(status, true); + + // Notify delegate that our process has exited. + SetState(StateType::eStateExited, true); +} + +void NativeProcessFreeBSD::MonitorSIGSTOP(lldb::pid_t pid) { + /* Stop all Threads attached to Process */ + for (const auto &thread : m_threads) { + static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP, + nullptr); + } + SetState(StateType::eStateStopped, true); +} + +void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + struct ptrace_lwpinfo info; + + const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return; + } + assert(info.pl_event == PL_EVENT_SIGNAL); + + LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, flags = {2:x}", pid, + info.pl_lwpid, info.pl_flags); + NativeThreadFreeBSD *thread = nullptr; + + if (info.pl_flags & (PL_FLAG_BORN | PL_FLAG_EXITED)) { + if (info.pl_flags & PL_FLAG_BORN) { + LLDB_LOG(log, "monitoring new thread, tid = {0}", info.pl_lwpid); + NativeThreadFreeBSD &t = AddThread(info.pl_lwpid); + + // Technically, the FreeBSD kernel copies the debug registers to new + // threads. However, there is a non-negligible delay between acquiring + // the DR values and reporting the new thread during which the user may + // establish a new watchpoint. In order to ensure that watchpoints + // established during this period are propagated to new threads, + // explicitly copy the DR value at the time the new thread is reported. + // + // See also: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=250954 + + llvm::Error error = t.CopyWatchpointsFrom( + static_cast<NativeThreadFreeBSD &>(*GetCurrentThread())); + if (error) { + LLDB_LOG_ERROR(log, std::move(error), + "failed to copy watchpoints to new thread {1}: {0}", + info.pl_lwpid); + SetState(StateType::eStateInvalid); + return; + } + } else /*if (info.pl_flags & PL_FLAG_EXITED)*/ { + LLDB_LOG(log, "thread exited, tid = {0}", info.pl_lwpid); + RemoveThread(info.pl_lwpid); + } + + Status error = + PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0); + if (error.Fail()) + SetState(StateType::eStateInvalid); + return; + } + + if (info.pl_flags & PL_FLAG_EXEC) { + Status error = ReinitializeThreads(); + if (error.Fail()) { + SetState(StateType::eStateInvalid); + return; + } + + // Let our delegate know we have just exec'd. + NotifyDidExec(); + + for (const auto &thread : m_threads) + static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedByExec(); + SetState(StateType::eStateStopped, true); + return; + } + + if (info.pl_lwpid > 0) { + for (const auto &t : m_threads) { + if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid)) + thread = static_cast<NativeThreadFreeBSD *>(t.get()); + static_cast<NativeThreadFreeBSD *>(t.get())->SetStoppedWithNoReason(); + } + if (!thread) + LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid, + info.pl_lwpid); + } + + if (info.pl_flags & PL_FLAG_SI) { + assert(info.pl_siginfo.si_signo == SIGTRAP); + LLDB_LOG(log, "SIGTRAP siginfo: si_code = {0}, pid = {1}", + info.pl_siginfo.si_code, info.pl_siginfo.si_pid); + + switch (info.pl_siginfo.si_code) { + case TRAP_BRKPT: + LLDB_LOG(log, "SIGTRAP/TRAP_BRKPT: si_addr: {0}", + info.pl_siginfo.si_addr); + + if (thread) { + auto thread_info = + m_threads_stepping_with_breakpoint.find(thread->GetID()); + if (thread_info != m_threads_stepping_with_breakpoint.end()) { + thread->SetStoppedByTrace(); + Status brkpt_error = RemoveBreakpoint(thread_info->second); + if (brkpt_error.Fail()) + LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", + thread_info->first, brkpt_error); + m_threads_stepping_with_breakpoint.erase(thread_info); + } else + thread->SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(*thread); + } + SetState(StateType::eStateStopped, true); + return; + case TRAP_TRACE: + LLDB_LOG(log, "SIGTRAP/TRAP_TRACE: si_addr: {0}", + info.pl_siginfo.si_addr); + + if (thread) { + auto ®ctx = static_cast<NativeRegisterContextFreeBSD &>( + thread->GetRegisterContext()); + uint32_t wp_index = LLDB_INVALID_INDEX32; + Status error = regctx.GetWatchpointHitIndex( + wp_index, reinterpret_cast<uintptr_t>(info.pl_siginfo.si_addr)); + if (error.Fail()) + LLDB_LOG(log, + "received error while checking for watchpoint hits, pid = " + "{0}, LWP = {1}, error = {2}", + pid, info.pl_lwpid, error); + if (wp_index != LLDB_INVALID_INDEX32) { + regctx.ClearWatchpointHit(wp_index); + thread->SetStoppedByWatchpoint(wp_index); + SetState(StateType::eStateStopped, true); + break; + } + + thread->SetStoppedByTrace(); + } + + SetState(StateType::eStateStopped, true); + return; + } + } + + // Either user-generated SIGTRAP or an unknown event that would + // otherwise leave the debugger hanging. + LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler"); + MonitorSignal(pid, SIGTRAP); +} + +void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + struct ptrace_lwpinfo info; + + const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return; + } + assert(info.pl_event == PL_EVENT_SIGNAL); + // TODO: do we need to handle !PL_FLAG_SI? + assert(info.pl_flags & PL_FLAG_SI); + assert(info.pl_siginfo.si_signo == signal); + + for (const auto &abs_thread : m_threads) { + NativeThreadFreeBSD &thread = + static_cast<NativeThreadFreeBSD &>(*abs_thread); + assert(info.pl_lwpid >= 0); + if (info.pl_lwpid == 0 || + static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID()) + thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo); + else + thread.SetStoppedWithNoReason(); + } + SetState(StateType::eStateStopped, true); +} + +Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, + int data, int *result) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + Status error; + int ret; + + errno = 0; + ret = + ptrace(req, static_cast<::pid_t>(pid), static_cast<caddr_t>(addr), data); + + if (ret == -1) + error.SetErrorToErrno(); + + if (result) + *result = ret; + + LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret); + + if (error.Fail()) + LLDB_LOG(log, "ptrace() failed: {0}", error); + + return error; +} + +llvm::Expected<llvm::ArrayRef<uint8_t>> +NativeProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { + static const uint8_t g_arm_opcode[] = {0xfe, 0xde, 0xff, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::arm: + switch (size_hint) { + case 2: + return llvm::makeArrayRef(g_thumb_opcode); + case 4: + return llvm::makeArrayRef(g_arm_opcode); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); + } + default: + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); + } +} + +Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "pid {0}", GetID()); + + Status ret; + + int signal = 0; + for (const auto &abs_thread : m_threads) { + assert(abs_thread && "thread list should not contain NULL threads"); + NativeThreadFreeBSD &thread = + static_cast<NativeThreadFreeBSD &>(*abs_thread); + + const ResumeAction *action = + resume_actions.GetActionForThread(thread.GetID(), true); + // we need to explicit issue suspend requests, so it is simpler to map it + // into proper action + ResumeAction suspend_action{thread.GetID(), eStateSuspended, + LLDB_INVALID_SIGNAL_NUMBER}; + + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread.GetID()); + action = &suspend_action; + } + + LLDB_LOG( + log, + "processing resume action state {0} signal {1} for pid {2} tid {3}", + action->state, action->signal, GetID(), thread.GetID()); + + switch (action->state) { + case eStateRunning: + ret = thread.Resume(); + break; + case eStateStepping: + ret = thread.SingleStep(); + break; + case eStateSuspended: + case eStateStopped: + if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) + return Status("Passing signal to suspended thread unsupported"); + + ret = thread.Suspend(); + break; + + default: + return Status( + "NativeProcessFreeBSD::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID()); + } + + if (!ret.Success()) + return ret; + if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) + signal = action->signal; + } + + ret = + PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal); + if (ret.Success()) + SetState(eStateRunning, true); + return ret; +} + +Status NativeProcessFreeBSD::Halt() { + Status error; + + if (kill(GetID(), SIGSTOP) != 0) + error.SetErrorToErrno(); + return error; +} + +Status NativeProcessFreeBSD::Detach() { + Status error; + + // Stop monitoring the inferior. + m_sigchld_handle.reset(); + + // Tell ptrace to detach from the process. + if (GetID() == LLDB_INVALID_PROCESS_ID) + return error; + + return PtraceWrapper(PT_DETACH, GetID()); +} + +Status NativeProcessFreeBSD::Signal(int signo) { + Status error; + + if (kill(GetID(), signo)) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessFreeBSD::Interrupt() { return Halt(); } + +Status NativeProcessFreeBSD::Kill() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "pid {0}", GetID()); + + Status error; + + switch (m_state) { + case StateType::eStateInvalid: + case StateType::eStateExited: + case StateType::eStateCrashed: + case StateType::eStateDetached: + case StateType::eStateUnloaded: + // Nothing to do - the process is already dead. + LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), + StateAsCString(m_state)); + return error; + + case StateType::eStateConnected: + case StateType::eStateAttaching: + case StateType::eStateLaunching: + case StateType::eStateStopped: + case StateType::eStateRunning: + case StateType::eStateStepping: + case StateType::eStateSuspended: + // We can try to kill a process in these states. + break; + } + + return PtraceWrapper(PT_KILL, m_pid); +} + +Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + + if (m_supports_mem_region == LazyBool::eLazyBoolNo) { + // We're done. + return Status("unsupported"); + } + + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) { + return error; + } + + lldb::addr_t prev_base_address = 0; + // FIXME start by finding the last region that is <= target address using + // binary search. Data is sorted. + // There can be a ton of regions on pthreads apps with lots of threads. + for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); + ++it) { + MemoryRegionInfo &proc_entry_info = it->first; + // Sanity check assumption that memory map entries are ascending. + assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && + "descending memory map entries detected, unexpected"); + prev_base_address = proc_entry_info.GetRange().GetRangeBase(); + UNUSED_IF_ASSERT_DISABLED(prev_base_address); + // If the target address comes before this entry, indicate distance to next + // region. + if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetByteSize( + proc_entry_info.GetRange().GetRangeBase() - load_addr); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; + } else if (proc_entry_info.GetRange().Contains(load_addr)) { + // The target address is within the memory region we're processing here. + range_info = proc_entry_info; + return error; + } + // The target memory address comes somewhere after the region we just + // parsed. + } + // If we made it here, we didn't find an entry that contained the given + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; +} + +Status NativeProcessFreeBSD::PopulateMemoryRegionCache() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + // If our cache is empty, pull the latest. There should always be at least + // one memory region if memory region handling is supported. + if (!m_mem_region_cache.empty()) { + LLDB_LOG(log, "reusing {0} cached memory region entries", + m_mem_region_cache.size()); + return Status(); + } + + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, static_cast<int>(m_pid)}; + int ret; + size_t len; + + ret = ::sysctl(mib, 4, nullptr, &len, nullptr, 0); + if (ret != 0) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return Status("sysctl() for KERN_PROC_VMMAP failed"); + } + + std::unique_ptr<WritableMemoryBuffer> buf = + llvm::WritableMemoryBuffer::getNewMemBuffer(len); + ret = ::sysctl(mib, 4, buf->getBufferStart(), &len, nullptr, 0); + if (ret != 0) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return Status("sysctl() for KERN_PROC_VMMAP failed"); + } + + char *bp = buf->getBufferStart(); + char *end = bp + len; + while (bp < end) { + auto *kv = reinterpret_cast<struct kinfo_vmentry *>(bp); + if (kv->kve_structsize == 0) + break; + bp += kv->kve_structsize; + + MemoryRegionInfo info; + info.Clear(); + info.GetRange().SetRangeBase(kv->kve_start); + info.GetRange().SetRangeEnd(kv->kve_end); + info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + + if (kv->kve_protection & VM_PROT_READ) + info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + else + info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + + if (kv->kve_protection & VM_PROT_WRITE) + info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + else + info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + + if (kv->kve_protection & VM_PROT_EXECUTE) + info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + else + info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + + if (kv->kve_path[0]) + info.SetName(kv->kve_path); + + m_mem_region_cache.emplace_back(info, + FileSpec(info.GetName().GetCString())); + } + + if (m_mem_region_cache.empty()) { + // No entries after attempting to read them. This shouldn't happen. Assume + // we don't support map entries. + LLDB_LOG(log, "failed to find any vmmap entries, assuming no support " + "for memory region metadata retrieval"); + m_supports_mem_region = LazyBool::eLazyBoolNo; + return Status("not supported"); + } + LLDB_LOG(log, "read {0} memory region entries from process {1}", + m_mem_region_cache.size(), GetID()); + // We support memory retrieval, remember that. + m_supports_mem_region = LazyBool::eLazyBoolYes; + + return Status(); +} + +size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); } + +Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + if (hardware) + return SetHardwareBreakpoint(addr, size); + return SetSoftwareBreakpoint(addr, size); +} + +Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) { + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in process' memory map!", + module_file_spec.GetFilename().AsCString()); +} + +Status +NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) { + load_addr = LLDB_INVALID_ADDRESS; + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec file(file_name); + for (const auto &it : m_mem_region_cache) { + if (it.second == file) { + load_addr = it.first.GetRange().GetRangeBase(); + return Status(); + } + } + return Status("No load address found for file %s.", file_name.str().c_str()); +} + +void NativeProcessFreeBSD::SigchldHandler() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + // Process all pending waitpid notifications. + int status; + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG); + + if (wait_pid == 0) + return; // We are done. + + if (wait_pid == -1) { + Status error(errno, eErrorTypePOSIX); + LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error); + } + + WaitStatus wait_status = WaitStatus::Decode(status); + bool exited = wait_status.type == WaitStatus::Exit || + (wait_status.type == WaitStatus::Signal && + wait_pid == static_cast<::pid_t>(GetID())); + + LLDB_LOG(log, + "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}", + GetID(), wait_pid, status, exited); + + if (exited) + MonitorExited(wait_pid, wait_status); + else { + assert(wait_status.type == WaitStatus::Stop); + MonitorCallback(wait_pid, wait_status.status); + } +} + +bool NativeProcessFreeBSD::HasThreadNoLock(lldb::tid_t thread_id) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + if (thread->GetID() == thread_id) { + // We have this thread. + return true; + } + } + + // We don't have this thread. + return false; +} + +NativeThreadFreeBSD &NativeProcessFreeBSD::AddThread(lldb::tid_t thread_id) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + + assert(thread_id > 0); + assert(!HasThreadNoLock(thread_id) && + "attempted to add a thread by id that already exists"); + + // If this is the first thread, save it as the current thread + if (m_threads.empty()) + SetCurrentThreadID(thread_id); + + m_threads.push_back(std::make_unique<NativeThreadFreeBSD>(*this, thread_id)); + return static_cast<NativeThreadFreeBSD &>(*m_threads.back()); +} + +void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id); + + assert(thread_id > 0); + assert(HasThreadNoLock(thread_id) && + "attempted to remove a thread that does not exist"); + + for (auto it = m_threads.begin(); it != m_threads.end(); ++it) { + if ((*it)->GetID() == thread_id) { + m_threads.erase(it); + break; + } + } +} + +Status NativeProcessFreeBSD::Attach() { + // Attach to the requested process. + // An attach will cause the thread to stop with a SIGSTOP. + Status status = PtraceWrapper(PT_ATTACH, m_pid); + if (status.Fail()) + return status; + + int wstatus; + // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this + // point we should have a thread stopped if waitpid succeeds. + if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, 0)) < + 0) + return Status(errno, eErrorTypePOSIX); + + // Initialize threads and tracing status + // NB: this needs to be called before we set thread state + status = SetupTrace(); + if (status.Fail()) + return status; + + for (const auto &thread : m_threads) + static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP); + + // Let our process instance know the thread has stopped. + SetCurrentThreadID(m_threads.front()->GetID()); + SetState(StateType::eStateStopped, false); + return Status(); +} + +Status NativeProcessFreeBSD::ReadMemory(lldb::addr_t addr, void *buf, + size_t size, size_t &bytes_read) { + unsigned char *dst = static_cast<unsigned char *>(buf); + struct ptrace_io_desc io; + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + bytes_read = 0; + io.piod_op = PIOD_READ_D; + io.piod_len = size; + + do { + io.piod_offs = (void *)(addr + bytes_read); + io.piod_addr = dst + bytes_read; + + Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io); + if (error.Fail() || io.piod_len == 0) + return error; + + bytes_read += io.piod_len; + io.piod_len = size - bytes_read; + } while (bytes_read < size); + + return Status(); +} + +Status NativeProcessFreeBSD::WriteMemory(lldb::addr_t addr, const void *buf, + size_t size, size_t &bytes_written) { + const unsigned char *src = static_cast<const unsigned char *>(buf); + Status error; + struct ptrace_io_desc io; + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + bytes_written = 0; + io.piod_op = PIOD_WRITE_D; + io.piod_len = size; + + do { + io.piod_addr = + const_cast<void *>(static_cast<const void *>(src + bytes_written)); + io.piod_offs = (void *)(addr + bytes_written); + + Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io); + if (error.Fail() || io.piod_len == 0) + return error; + + bytes_written += io.piod_len; + io.piod_len = size - bytes_written; + } while (bytes_written < size); + + return error; +} + +llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> +NativeProcessFreeBSD::GetAuxvData() const { + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, static_cast<int>(GetID())}; + size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo); + std::unique_ptr<WritableMemoryBuffer> buf = + llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size); + + if (::sysctl(mib, 4, buf->getBufferStart(), &auxv_size, nullptr, 0) != 0) + return std::error_code(errno, std::generic_category()); + + return buf; +} + +Status NativeProcessFreeBSD::SetupTrace() { + // Enable event reporting + int events; + Status status = + PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events)); + if (status.Fail()) + return status; + events |= PTRACE_LWP; + status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events)); + if (status.Fail()) + return status; + + return ReinitializeThreads(); +} + +Status NativeProcessFreeBSD::ReinitializeThreads() { + // Clear old threads + m_threads.clear(); + + int num_lwps; + Status error = PtraceWrapper(PT_GETNUMLWPS, GetID(), nullptr, 0, &num_lwps); + if (error.Fail()) + return error; + + std::vector<lwpid_t> lwp_ids; + lwp_ids.resize(num_lwps); + error = PtraceWrapper(PT_GETLWPLIST, GetID(), lwp_ids.data(), + lwp_ids.size() * sizeof(lwpid_t), &num_lwps); + if (error.Fail()) + return error; + + // Reinitialize from scratch threads and register them in process + for (lwpid_t lwp : lwp_ids) + AddThread(lwp); + + return error; +} + +bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const { + return !m_arch.IsMIPS(); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h new file mode 100644 index 000000000000..ceffc370ca33 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h @@ -0,0 +1,128 @@ +//===-- NativeProcessFreeBSD.h -------------------------------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeProcessFreeBSD_H_ +#define liblldb_NativeProcessFreeBSD_H_ + +#include "Plugins/Process/POSIX/NativeProcessELF.h" +#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h" + +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" + +#include "NativeThreadFreeBSD.h" + +namespace lldb_private { +namespace process_freebsd { +/// \class NativeProcessFreeBSD +/// Manages communication with the inferior (debugee) process. +/// +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. +/// +/// Changes in the inferior process state are broadcasted. +class NativeProcessFreeBSD : public NativeProcessELF, + private NativeProcessSoftwareSingleStep { +public: + class Factory : public NativeProcessProtocol::Factory { + public: + llvm::Expected<std::unique_ptr<NativeProcessProtocol>> + Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop) const override; + + llvm::Expected<std::unique_ptr<NativeProcessProtocol>> + Attach(lldb::pid_t pid, NativeDelegate &native_delegate, + MainLoop &mainloop) const override; + }; + + // NativeProcessProtocol Interface + Status Resume(const ResumeActionList &resume_actions) override; + + Status Halt() override; + + Status Detach() override; + + Status Signal(int signo) override; + + Status Interrupt() override; + + Status Kill() override; + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) override; + + size_t UpdateThreads() override; + + const ArchSpec &GetArchitecture() const override { return m_arch; } + + Status SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) override; + + // The two following methods are probably not necessary and probably + // will never be called. Nevertheless, we implement them right now + // to reduce the differences between different platforms and reduce + // the risk of the lack of implementation actually breaking something, + // at least for the time being. + Status GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) override; + Status GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) override; + + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + GetAuxvData() const override; + + // Interface used by NativeRegisterContext-derived classes. + static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, + int data = 0, int *result = nullptr); + + bool SupportHardwareSingleStepping() const; + +protected: + llvm::Expected<llvm::ArrayRef<uint8_t>> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + +private: + MainLoop::SignalHandleUP m_sigchld_handle; + ArchSpec m_arch; + LazyBool m_supports_mem_region = eLazyBoolCalculate; + std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache; + + // Private Instance Methods + NativeProcessFreeBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, MainLoop &mainloop); + + bool HasThreadNoLock(lldb::tid_t thread_id); + + NativeThreadFreeBSD &AddThread(lldb::tid_t thread_id); + void RemoveThread(lldb::tid_t thread_id); + + void MonitorCallback(lldb::pid_t pid, int signal); + void MonitorExited(lldb::pid_t pid, WaitStatus status); + void MonitorSIGSTOP(lldb::pid_t pid); + void MonitorSIGTRAP(lldb::pid_t pid); + void MonitorSignal(lldb::pid_t pid, int signal); + + Status PopulateMemoryRegionCache(); + void SigchldHandler(); + + Status Attach(); + Status SetupTrace(); + Status ReinitializeThreads(); +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeProcessFreeBSD_H_ diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp new file mode 100644 index 000000000000..3d744f773a26 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp @@ -0,0 +1,29 @@ +//===-- NativeRegisterContextFreeBSD.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 "NativeRegisterContextFreeBSD.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" + +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +// clang-format off +#include <sys/types.h> +#include <sys/ptrace.h> +// clang-format on + +NativeProcessFreeBSD &NativeRegisterContextFreeBSD::GetProcess() { + return static_cast<NativeProcessFreeBSD &>(m_thread.GetProcess()); +} + +::pid_t NativeRegisterContextFreeBSD::GetProcessPid() { + return GetProcess().GetID(); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h new file mode 100644 index 000000000000..0000484beac9 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h @@ -0,0 +1,43 @@ +//===-- NativeRegisterContextFreeBSD.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeRegisterContextFreeBSD_h +#define lldb_NativeRegisterContextFreeBSD_h + +#include "lldb/Host/common/NativeThreadProtocol.h" + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD + : public virtual NativeRegisterContextRegisterInfo { +public: + // This function is implemented in the NativeRegisterContextFreeBSD_* + // subclasses to create a new instance of the host specific + // NativeRegisterContextFreeBSD. The implementations can't collide as only one + // NativeRegisterContextFreeBSD_* variant should be compiled into the final + // executable. + static NativeRegisterContextFreeBSD * + CreateHostNativeRegisterContextFreeBSD(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + virtual llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) = 0; + +protected: + virtual NativeProcessFreeBSD &GetProcess(); + virtual ::pid_t GetProcessPid(); +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_h diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp new file mode 100644 index 000000000000..c4ee3773eaeb --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp @@ -0,0 +1,202 @@ +//===-- NativeRegisterContextFreeBSD_arm.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__arm__) + +#include "NativeRegisterContextFreeBSD_arm.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" + +// clang-format off +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_arm(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_arm::NativeRegisterContextFreeBSD_arm( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_arm(target_arch)) {} + +RegisterInfoPOSIX_arm & +NativeRegisterContextFreeBSD_arm::GetRegisterInfo() const { + return static_cast<RegisterInfoPOSIX_arm &>(*m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_arm::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_arm::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_arm::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_arm::ReadRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_GETVFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_arm::WriteRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_SETVFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_arm::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : "<unknown register>"); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_arm::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : "<unknown register>"); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_arm::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm::GPRegSet); + if (error.Fail()) + return error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm::FPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_arm::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + error = WriteRegisterSet(RegisterInfoPOSIX_arm::GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(RegisterInfoPOSIX_arm::FPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_arm::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + return llvm::Error::success(); +} + +#endif // defined (__arm__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h new file mode 100644 index 000000000000..4be75b958fc1 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h @@ -0,0 +1,68 @@ +//===-- NativeRegisterContextFreeBSD_arm.h ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#if defined(__arm__) + +#ifndef lldb_NativeRegisterContextFreeBSD_arm_h +#define lldb_NativeRegisterContextFreeBSD_arm_h + +// clang-format off +#include <sys/types.h> +#include <machine/reg.h> +#include <machine/vfp.h> +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" + +#include <array> + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_arm : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_arm(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + std::array<uint8_t, sizeof(reg) + sizeof(vfp_state)> m_reg_data; + + Status ReadRegisterSet(uint32_t set); + Status WriteRegisterSet(uint32_t set); + + RegisterInfoPOSIX_arm &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm_h + +#endif // defined (__arm__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp new file mode 100644 index 000000000000..e98e0a8a0caa --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp @@ -0,0 +1,288 @@ +//===-- NativeRegisterContextFreeBSD_arm64.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__aarch64__) + +#include "NativeRegisterContextFreeBSD_arm64.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" + +// clang-format off +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_arm64(target_arch)) +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + , + m_read_dbreg(false) +#endif +{ + GetRegisterInfo().ConfigureVectorRegisterInfos( + RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); + ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs)); +} + +RegisterInfoPOSIX_arm64 & +NativeRegisterContextFreeBSD_arm64::GetRegisterInfo() const { + return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_arm64::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_arm64::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_arm64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_arm64::ReadRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm64::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm64::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_GETFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR)); + case RegisterInfoPOSIX_arm64::SVERegSet: + return Status("not supported"); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm64::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_arm64::WriteRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm64::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm64::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_SETFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR)); + case RegisterInfoPOSIX_arm64::SVERegSet: + return Status("not supported"); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm64::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : "<unknown register>"); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_arm64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : "<unknown register>"); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_arm64::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet); + if (error.Fail()) + return error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_arm64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + error = WriteRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_arm64::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + auto &r_source = static_cast<NativeRegisterContextFreeBSD_arm64 &>(source); + llvm::Error error = r_source.ReadHardwareDebugInfo(); + if (error) + return error; + + m_dbreg = r_source.m_dbreg; + m_hbp_regs = r_source.m_hbp_regs; + m_hwp_regs = r_source.m_hwp_regs; + m_max_hbp_supported = r_source.m_max_hbp_supported; + m_max_hwp_supported = r_source.m_max_hwp_supported; + m_read_dbreg = true; + + // on FreeBSD this writes both breakpoints and watchpoints + return WriteHardwareDebugRegs(eDREGTypeWATCH); +#else + return llvm::Error::success(); +#endif +} + +llvm::Error NativeRegisterContextFreeBSD_arm64::ReadHardwareDebugInfo() { +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS)); + + // we're fully stateful, so no need to reread control registers ever + if (m_read_dbreg) + return llvm::Error::success(); + + Status res = NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, + m_thread.GetID(), &m_dbreg); + if (res.Fail()) + return res.ToError(); + + LLDB_LOG(log, "m_dbreg read: debug_ver={0}, nbkpts={1}, nwtpts={2}", + m_dbreg.db_debug_ver, m_dbreg.db_nbkpts, m_dbreg.db_nwtpts); + m_max_hbp_supported = m_dbreg.db_nbkpts; + m_max_hwp_supported = m_dbreg.db_nwtpts; + assert(m_max_hbp_supported <= m_hbp_regs.size()); + assert(m_max_hwp_supported <= m_hwp_regs.size()); + + m_read_dbreg = true; + return llvm::Error::success(); +#else + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Hardware breakpoints/watchpoints require FreeBSD 14.0"); +#endif +} + +llvm::Error +NativeRegisterContextFreeBSD_arm64::WriteHardwareDebugRegs(DREGType) { +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + assert(m_read_dbreg && "dbregs must be read before writing them back"); + + // copy data from m_*_regs to m_dbreg before writing it back + for (uint32_t i = 0; i < m_max_hbp_supported; i++) { + m_dbreg.db_breakregs[i].dbr_addr = m_hbp_regs[i].address; + m_dbreg.db_breakregs[i].dbr_ctrl = m_hbp_regs[i].control; + } + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + m_dbreg.db_watchregs[i].dbw_addr = m_hwp_regs[i].address; + m_dbreg.db_watchregs[i].dbw_ctrl = m_hwp_regs[i].control; + } + + return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(), + &m_dbreg) + .ToError(); +#else + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Hardware breakpoints/watchpoints require FreeBSD 14.0"); +#endif +} + +#endif // defined (__aarch64__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h new file mode 100644 index 000000000000..a230f8fed48a --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h @@ -0,0 +1,86 @@ +//===-- NativeRegisterContextFreeBSD_arm64.h --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#if defined(__aarch64__) + +#ifndef lldb_NativeRegisterContextFreeBSD_arm64_h +#define lldb_NativeRegisterContextFreeBSD_arm64_h + +// clang-format off +#include <sys/types.h> +#include <sys/param.h> +#include <machine/reg.h> +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" + +#include <array> + +#if __FreeBSD_version >= 1300139 +# define LLDB_HAS_FREEBSD_WATCHPOINT 1 +#endif + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_arm64 + : public NativeRegisterContextFreeBSD, + public NativeRegisterContextDBReg_arm64 { +public: + NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + // Due to alignment, FreeBSD reg/fpreg are a few bytes larger than + // LLDB's GPR/FPU structs. However, all fields have matching offsets + // and sizes, so we do not have to worry about these (and we have + // a unittest to assert that). + std::array<uint8_t, sizeof(reg) + sizeof(fpreg)> m_reg_data; +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + dbreg m_dbreg; + bool m_read_dbreg; +#endif + + Status ReadRegisterSet(uint32_t set); + Status WriteRegisterSet(uint32_t set); + + llvm::Error ReadHardwareDebugInfo() override; + llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override; + + RegisterInfoPOSIX_arm64 &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm64_h + +#endif // defined (__aarch64__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp new file mode 100644 index 000000000000..8e722c09314c --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp @@ -0,0 +1,186 @@ +//===-- NativeRegisterContextFreeBSD_mips64.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__mips64__) + +#include "NativeRegisterContextFreeBSD_mips64.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" + +// clang-format off +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {} + +RegisterContextFreeBSD_mips64 & +NativeRegisterContextFreeBSD_mips64::GetRegisterInfo() const { + return static_cast<RegisterContextFreeBSD_mips64 &>( + *m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_mips64::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_mips64::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_mips64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_mips64::ReadRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + } + llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_mips64::WriteRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + } + llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_mips64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : "<unknown register>"); + + RegSetKind set = GPRegSet; + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_mips64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : "<unknown register>"); + + RegSetKind set = GPRegSet; + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_mips64::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_mips64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_mips64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_mips64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_mips64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + return WriteRegisterSet(GPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + return llvm::Error::success(); +} + +#endif // defined (__mips64__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h new file mode 100644 index 000000000000..6a3eb86a9231 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h @@ -0,0 +1,71 @@ +//===-- NativeRegisterContextFreeBSD_mips64.h -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#if defined(__mips64__) + +#ifndef lldb_NativeRegisterContextFreeBSD_mips64_h +#define lldb_NativeRegisterContextFreeBSD_mips64_h + +// clang-format off +#include <sys/types.h> +#include <machine/reg.h> +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" + +#include <array> + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_mips64 + : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_mips64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + enum RegSetKind { + GPRegSet, + }; + std::array<uint8_t, sizeof(reg)> m_reg_data; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + RegisterContextFreeBSD_mips64 &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_mips64_h + +#endif // defined (__mips64__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp new file mode 100644 index 000000000000..5b5d44a308b1 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp @@ -0,0 +1,289 @@ +//===-- NativeRegisterContextFreeBSD_powerpc.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__powerpc__) + +#include "NativeRegisterContextFreeBSD_powerpc.h" + +#include "lldb/Host/HostInfo.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" +// for register enum definitions +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" + +// clang-format off +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +static const uint32_t g_gpr_regnums[] = { + gpr_r0_powerpc, gpr_r1_powerpc, gpr_r2_powerpc, gpr_r3_powerpc, + gpr_r4_powerpc, gpr_r5_powerpc, gpr_r6_powerpc, gpr_r7_powerpc, + gpr_r8_powerpc, gpr_r9_powerpc, gpr_r10_powerpc, gpr_r11_powerpc, + gpr_r12_powerpc, gpr_r13_powerpc, gpr_r14_powerpc, gpr_r15_powerpc, + gpr_r16_powerpc, gpr_r17_powerpc, gpr_r18_powerpc, gpr_r19_powerpc, + gpr_r20_powerpc, gpr_r21_powerpc, gpr_r22_powerpc, gpr_r23_powerpc, + gpr_r24_powerpc, gpr_r25_powerpc, gpr_r26_powerpc, gpr_r27_powerpc, + gpr_r28_powerpc, gpr_r29_powerpc, gpr_r30_powerpc, gpr_r31_powerpc, + gpr_lr_powerpc, gpr_cr_powerpc, gpr_xer_powerpc, gpr_ctr_powerpc, + gpr_pc_powerpc, +}; + +static const uint32_t g_fpr_regnums[] = { + fpr_f0_powerpc, fpr_f1_powerpc, fpr_f2_powerpc, fpr_f3_powerpc, + fpr_f4_powerpc, fpr_f5_powerpc, fpr_f6_powerpc, fpr_f7_powerpc, + fpr_f8_powerpc, fpr_f9_powerpc, fpr_f10_powerpc, fpr_f11_powerpc, + fpr_f12_powerpc, fpr_f13_powerpc, fpr_f14_powerpc, fpr_f15_powerpc, + fpr_f16_powerpc, fpr_f17_powerpc, fpr_f18_powerpc, fpr_f19_powerpc, + fpr_f20_powerpc, fpr_f21_powerpc, fpr_f22_powerpc, fpr_f23_powerpc, + fpr_f24_powerpc, fpr_f25_powerpc, fpr_f26_powerpc, fpr_f27_powerpc, + fpr_f28_powerpc, fpr_f29_powerpc, fpr_f30_powerpc, fpr_f31_powerpc, + fpr_fpscr_powerpc, +}; + +// Number of register sets provided by this context. +enum { k_num_register_sets = 2 }; + +static const RegisterSet g_reg_sets_powerpc[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_powerpc, + g_gpr_regnums}, + {"Floating Point Registers", "fpr", k_num_fpr_registers_powerpc, + g_fpr_regnums}, +}; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_powerpc(target_arch, native_thread); +} + +static RegisterInfoInterface * +CreateRegisterInfoInterface(const ArchSpec &target_arch) { + if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) { + return new RegisterContextFreeBSD_powerpc32(target_arch); + } else { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + return new RegisterContextFreeBSD_powerpc64(target_arch); + } +} + +NativeRegisterContextFreeBSD_powerpc::NativeRegisterContextFreeBSD_powerpc( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)) {} + +RegisterContextFreeBSD_powerpc & +NativeRegisterContextFreeBSD_powerpc::GetRegisterInfo() const { + return static_cast<RegisterContextFreeBSD_powerpc &>( + *m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_powerpc::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextFreeBSD_powerpc::GetRegisterSet(uint32_t set_index) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::ppc: + return &g_reg_sets_powerpc[set_index]; + default: + llvm_unreachable("Unhandled target architecture."); + } +} + +llvm::Optional<NativeRegisterContextFreeBSD_powerpc::RegSetKind> +NativeRegisterContextFreeBSD_powerpc::GetSetForNativeRegNum( + uint32_t reg_num) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::ppc: + if (reg_num >= k_first_gpr_powerpc && reg_num <= k_last_gpr_powerpc) + return GPRegSet; + if (reg_num >= k_first_fpr && reg_num <= k_last_fpr) + return FPRegSet; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + llvm_unreachable("Register does not belong to any register set"); +} + +uint32_t NativeRegisterContextFreeBSD_powerpc::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + case FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(reg)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + case FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(reg)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_powerpc::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : "<unknown register>"); + + llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_powerpc::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : "<unknown register>"); + + llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_powerpc::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + error = ReadRegisterSet(FPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_powerpc::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_powerpc::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_powerpc::%s data_sp contained mismatched " + "data size, expected %zu, actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_powerpc::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + error = WriteRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(FPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + return llvm::Error::success(); +} + +#endif // defined (__powerpc__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h new file mode 100644 index 000000000000..884c25988ce1 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h @@ -0,0 +1,74 @@ +//===-- NativeRegisterContextFreeBSD_powerpc.h ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#if defined(__powerpc__) + +#ifndef lldb_NativeRegisterContextFreeBSD_powerpc_h +#define lldb_NativeRegisterContextFreeBSD_powerpc_h + +// clang-format off +#include <sys/types.h> +#include <machine/reg.h> +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" + +#include <array> + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_powerpc + : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_powerpc(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + enum RegSetKind { + GPRegSet, + FPRegSet, + }; + std::array<uint8_t, sizeof(reg) + sizeof(fpreg)> m_reg_data; + + llvm::Optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + RegisterContextFreeBSD_powerpc &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_powerpc_h + +#endif // defined (__powerpc__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp new file mode 100644 index 000000000000..d5052e7d1b3a --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp @@ -0,0 +1,656 @@ +//===-- NativeRegisterContextFreeBSD_x86_64.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__i386__) || defined(__x86_64__) + +#include "NativeRegisterContextFreeBSD_x86_64.h" + +// clang-format off +#include <x86/fpu.h> +#include <x86/specialreg.h> +#include <cpuid.h> +// clang-format on + +#include "lldb/Host/HostInfo.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "NativeProcessFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" + +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +// x86 64-bit general purpose registers. +static const uint32_t g_gpr_regnums_x86_64[] = { + lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, + lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64, + lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64, + lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64, + lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64, + lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64, + lldb_eax_x86_64, lldb_ebx_x86_64, lldb_ecx_x86_64, lldb_edx_x86_64, + lldb_edi_x86_64, lldb_esi_x86_64, lldb_ebp_x86_64, lldb_esp_x86_64, + lldb_r8d_x86_64, // Low 32 bits or r8 + lldb_r9d_x86_64, // Low 32 bits or r9 + lldb_r10d_x86_64, // Low 32 bits or r10 + lldb_r11d_x86_64, // Low 32 bits or r11 + lldb_r12d_x86_64, // Low 32 bits or r12 + lldb_r13d_x86_64, // Low 32 bits or r13 + lldb_r14d_x86_64, // Low 32 bits or r14 + lldb_r15d_x86_64, // Low 32 bits or r15 + lldb_ax_x86_64, lldb_bx_x86_64, lldb_cx_x86_64, lldb_dx_x86_64, + lldb_di_x86_64, lldb_si_x86_64, lldb_bp_x86_64, lldb_sp_x86_64, + lldb_r8w_x86_64, // Low 16 bits or r8 + lldb_r9w_x86_64, // Low 16 bits or r9 + lldb_r10w_x86_64, // Low 16 bits or r10 + lldb_r11w_x86_64, // Low 16 bits or r11 + lldb_r12w_x86_64, // Low 16 bits or r12 + lldb_r13w_x86_64, // Low 16 bits or r13 + lldb_r14w_x86_64, // Low 16 bits or r14 + lldb_r15w_x86_64, // Low 16 bits or r15 + lldb_ah_x86_64, lldb_bh_x86_64, lldb_ch_x86_64, lldb_dh_x86_64, + lldb_al_x86_64, lldb_bl_x86_64, lldb_cl_x86_64, lldb_dl_x86_64, + lldb_dil_x86_64, lldb_sil_x86_64, lldb_bpl_x86_64, lldb_spl_x86_64, + lldb_r8l_x86_64, // Low 8 bits or r8 + lldb_r9l_x86_64, // Low 8 bits or r9 + lldb_r10l_x86_64, // Low 8 bits or r10 + lldb_r11l_x86_64, // Low 8 bits or r11 + lldb_r12l_x86_64, // Low 8 bits or r12 + lldb_r13l_x86_64, // Low 8 bits or r13 + lldb_r14l_x86_64, // Low 8 bits or r14 + lldb_r15l_x86_64, // Low 8 bits or r15 + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - + 1 == + k_num_gpr_registers_x86_64, + "g_gpr_regnums_x86_64 has wrong number of register infos"); + +// x86 64-bit floating point registers. +static const uint32_t g_fpu_regnums_x86_64[] = { + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64, + lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64, + lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64, + lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64, + lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64, + lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64, + lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64, + lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64, + lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64, + lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64, + lldb_xmm14_x86_64, lldb_xmm15_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - + 1 == + k_num_fpr_registers_x86_64, + "g_fpu_regnums_x86_64 has wrong number of register infos"); + +static const uint32_t g_avx_regnums_x86_64[] = { + lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64, + lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64, + lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64, + lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - + 1 == + k_num_avx_registers_x86_64, + "g_avx_regnums_x86_64 has wrong number of register infos"); + +static const uint32_t g_mpx_regnums_x86_64[] = { + // Note: we currently do not provide them but this is needed to avoid + // unnamed groups in SBFrame::GetRegisterContext(). + lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, + lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) - + 1 == + k_num_mpx_registers_x86_64, + "g_mpx_regnums_x86_64 has wrong number of register infos"); + +// x86 debug registers. +static const uint32_t g_dbr_regnums_x86_64[] = { + lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, + lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - + 1 == + k_num_dbr_registers_x86_64, + "g_dbr_regnums_x86_64 has wrong number of register infos"); + +// x86 32-bit general purpose registers. +static const uint32_t g_gpr_regnums_i386[] = { + lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386, + lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386, + lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386, + lldb_gs_i386, lldb_ss_i386, lldb_ds_i386, lldb_es_i386, + lldb_ax_i386, lldb_bx_i386, lldb_cx_i386, lldb_dx_i386, + lldb_di_i386, lldb_si_i386, lldb_bp_i386, lldb_sp_i386, + lldb_ah_i386, lldb_bh_i386, lldb_ch_i386, lldb_dh_i386, + lldb_al_i386, lldb_bl_i386, lldb_cl_i386, lldb_dl_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - + 1 == + k_num_gpr_registers_i386, + "g_gpr_regnums_i386 has wrong number of register infos"); + +// x86 32-bit floating point registers. +static const uint32_t g_fpu_regnums_i386[] = { + lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386, + lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386, + lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386, + lldb_st2_i386, lldb_st3_i386, lldb_st4_i386, lldb_st5_i386, + lldb_st6_i386, lldb_st7_i386, lldb_mm0_i386, lldb_mm1_i386, + lldb_mm2_i386, lldb_mm3_i386, lldb_mm4_i386, lldb_mm5_i386, + lldb_mm6_i386, lldb_mm7_i386, lldb_xmm0_i386, lldb_xmm1_i386, + lldb_xmm2_i386, lldb_xmm3_i386, lldb_xmm4_i386, lldb_xmm5_i386, + lldb_xmm6_i386, lldb_xmm7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - + 1 == + k_num_fpr_registers_i386, + "g_fpu_regnums_i386 has wrong number of register infos"); + +static const uint32_t g_avx_regnums_i386[] = { + lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, + lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - + 1 == + k_num_avx_registers_i386, + "g_avx_regnums_i386 has wrong number of register infos"); + +static const uint32_t g_mpx_regnums_i386[] = { + // Note: we currently do not provide them but this is needed to avoid + // unnamed groups in SBFrame::GetRegisterContext(). + lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, + lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) - + 1 == + k_num_mpx_registers_i386, + "g_mpx_regnums_i386 has wrong number of register infos"); + +// x86 debug registers. +static const uint32_t g_dbr_regnums_i386[] = { + lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386, + lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) - + 1 == + k_num_dbr_registers_i386, + "g_dbr_regnums_i386 has wrong number of register infos"); + +// Number of register sets provided by this context. +enum { k_num_register_sets = 5 }; + +// Register sets for x86 32-bit. +static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_i386, + g_gpr_regnums_i386}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_i386, + g_fpu_regnums_i386}, + {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386}, + {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386, + g_avx_regnums_i386}, + {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386, + g_mpx_regnums_i386}, +}; + +// Register sets for x86 64-bit. +static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, + g_gpr_regnums_x86_64}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, + g_fpu_regnums_x86_64}, + {"Debug Registers", "dbr", k_num_dbr_registers_x86_64, + g_dbr_regnums_x86_64}, + {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, + g_avx_regnums_x86_64}, + {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64, + g_mpx_regnums_x86_64}, +}; + +#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize()) + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_x86_64(target_arch, native_thread); +} + +// NativeRegisterContextFreeBSD_x86_64 members. + +static RegisterInfoInterface * +CreateRegisterInfoInterface(const ArchSpec &target_arch) { + if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) { + // 32-bit hosts run with a RegisterContextFreeBSD_i386 context. + return new RegisterContextFreeBSD_i386(target_arch); + } else { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the + // x86_64 register context. + return new RegisterContextFreeBSD_x86_64(target_arch); + } +} + +NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)), + m_regset_offsets({0}) { + assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize()); + std::array<uint32_t, MaxRegSet + 1> first_regnos; + + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + first_regnos[FPRegSet] = lldb_fctrl_i386; + first_regnos[DBRegSet] = lldb_dr0_i386; + break; + case llvm::Triple::x86_64: + first_regnos[FPRegSet] = lldb_fctrl_x86_64; + first_regnos[DBRegSet] = lldb_dr0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + for (int i : {FPRegSet, DBRegSet}) + m_regset_offsets[i] = GetRegisterInfoInterface() + .GetRegisterInfo()[first_regnos[i]] + .byte_offset; +} + +uint32_t NativeRegisterContextFreeBSD_x86_64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextFreeBSD_x86_64::GetRegisterSet(uint32_t set_index) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + return &g_reg_sets_i386[set_index]; + case llvm::Triple::x86_64: + return &g_reg_sets_x86_64[set_index]; + default: + llvm_unreachable("Unhandled target architecture."); + } +} + +llvm::Optional<NativeRegisterContextFreeBSD_x86_64::RegSetKind> +NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum( + uint32_t reg_num) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386) + return GPRegSet; + if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386) + return FPRegSet; + if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386) + return YMMRegSet; + if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386) + return llvm::None; // MPXR + if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386) + return llvm::None; // MPXC + if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386) + return DBRegSet; // DBR + break; + case llvm::Triple::x86_64: + if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64) + return GPRegSet; + if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64) + return FPRegSet; + if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64) + return YMMRegSet; + if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64) + return llvm::None; // MPXR + if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64) + return llvm::None; // MPXC + if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64) + return DBRegSet; // DBR + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + llvm_unreachable("Register does not belong to any register set"); +} + +Status NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_gpr.data()); + case FPRegSet: +#if defined(__x86_64__) + return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(), + m_fpr.data()); +#else + return NativeProcessFreeBSD::PtraceWrapper(PT_GETXMMREGS, m_thread.GetID(), + m_fpr.data()); +#endif + case DBRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, m_thread.GetID(), + m_dbr.data()); + case YMMRegSet: + case MPXRegSet: { + struct ptrace_xstate_info info; + Status ret = NativeProcessFreeBSD::PtraceWrapper( + PT_GETXSTATE_INFO, GetProcessPid(), &info, sizeof(info)); + if (!ret.Success()) + return ret; + + assert(info.xsave_mask & XFEATURE_ENABLED_X87); + assert(info.xsave_mask & XFEATURE_ENABLED_SSE); + + m_xsave_offsets[YMMRegSet] = LLDB_INVALID_XSAVE_OFFSET; + if (info.xsave_mask & XFEATURE_ENABLED_YMM_HI128) { + uint32_t eax, ecx, edx; + __get_cpuid_count(0x0D, 2, &eax, &m_xsave_offsets[YMMRegSet], &ecx, &edx); + } + + m_xsave.resize(info.xsave_len); + return NativeProcessFreeBSD::PtraceWrapper(PT_GETXSTATE, GetProcessPid(), + m_xsave.data(), m_xsave.size()); + } + } + llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_gpr.data()); + case FPRegSet: +#if defined(__x86_64__) + return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(), + m_fpr.data()); +#else + return NativeProcessFreeBSD::PtraceWrapper(PT_SETXMMREGS, m_thread.GetID(), + m_fpr.data()); +#endif + case DBRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(), + m_dbr.data()); + case YMMRegSet: + case MPXRegSet: + // ReadRegisterSet() must always be called before WriteRegisterSet(). + assert(m_xsave.size() > 0); + return NativeProcessFreeBSD::PtraceWrapper(PT_SETXSTATE, GetProcessPid(), + m_xsave.data(), m_xsave.size()); + } + llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg == LLDB_INVALID_REGNUM) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " + "register, cannot read directly", + reg_info->name); + return error; + } + + llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + switch (set) { + case GPRegSet: + case FPRegSet: + case DBRegSet: { + void *data = GetOffsetRegSetData(set, reg_info->byte_offset); + FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_fpr.data()); + if (data == &fpr->ftag) // ftag + reg_value.SetUInt16( + AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm)); + else + reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder()); + break; + } + case YMMRegSet: { + llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg); + if (!ymm_reg) { + error.SetErrorStringWithFormat( + "register \"%s\" not supported by CPU/kernel", reg_info->name); + } else { + YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi); + reg_value.SetBytes(ymm.bytes, reg_info->byte_size, + endian::InlHostByteOrder()); + } + break; + } + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } + + return error; +} + +Status NativeRegisterContextFreeBSD_x86_64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg == LLDB_INVALID_REGNUM) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " + "register, cannot read directly", + reg_info->name); + return error; + } + + llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + switch (set) { + case GPRegSet: + case FPRegSet: + case DBRegSet: { + void *data = GetOffsetRegSetData(set, reg_info->byte_offset); + FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_fpr.data()); + if (data == &fpr->ftag) // ftag + fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16()); + else + ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize()); + break; + } + case YMMRegSet: { + llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg); + if (!ymm_reg) { + error.SetErrorStringWithFormat( + "register \"%s\" not supported by CPU/kernel", reg_info->name); + } else { + YMMReg ymm; + ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize()); + YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi); + } + break; + } + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_x86_64::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + error = ReadRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize()); + dst += GetRegisterInfoInterface().GetGPRSize(); + + return error; +} + +Status NativeRegisterContextFreeBSD_x86_64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_x86_64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_x86_64::%s data_sp contained mismatched " + "data size, expected %zu, actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_x86_64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize()); + + error = WriteRegisterSet(GPRegSet); + if (error.Fail()) + return error; + src += GetRegisterInfoInterface().GetGPRSize(); + + return error; +} + +llvm::Error NativeRegisterContextFreeBSD_x86_64::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + auto &r_source = static_cast<NativeRegisterContextFreeBSD_x86_64 &>(source); + // NB: This implicitly reads the whole dbreg set. + RegisterValue dr7; + Status res = r_source.ReadRegister(GetDR(7), dr7); + if (!res.Fail()) { + // copy dbregs only if any watchpoints were set + if ((dr7.GetAsUInt64() & 0xFF) == 0) + return llvm::Error::success(); + + m_dbr = r_source.m_dbr; + res = WriteRegisterSet(DBRegSet); + } + return res.ToError(); +} + +uint8_t * +NativeRegisterContextFreeBSD_x86_64::GetOffsetRegSetData(RegSetKind set, + size_t reg_offset) { + uint8_t *base; + switch (set) { + case GPRegSet: + base = m_gpr.data(); + break; + case FPRegSet: + base = m_fpr.data(); + break; + case DBRegSet: + base = m_dbr.data(); + break; + case YMMRegSet: + llvm_unreachable("GetRegSetData() is unsuitable for this regset."); + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } + assert(reg_offset >= m_regset_offsets[set]); + return base + (reg_offset - m_regset_offsets[set]); +} + +llvm::Optional<NativeRegisterContextFreeBSD_x86_64::YMMSplitPtr> +NativeRegisterContextFreeBSD_x86_64::GetYMMSplitReg(uint32_t reg) { + uint32_t offset = m_xsave_offsets[YMMRegSet]; + if (offset == LLDB_INVALID_XSAVE_OFFSET) + return llvm::None; + + uint32_t reg_index; + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + reg_index = reg - lldb_ymm0_i386; + break; + case llvm::Triple::x86_64: + reg_index = reg - lldb_ymm0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + auto *fpreg = reinterpret_cast<struct savexmm_ymm *>(m_xsave.data()); + auto *ymmreg = reinterpret_cast<struct ymmacc *>(m_xsave.data() + offset); + + return YMMSplitPtr{&fpreg->sv_xmm[reg_index], &ymmreg[reg_index]}; +} + +#endif // defined(__x86_64__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h new file mode 100644 index 000000000000..efd0f91f77b9 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h @@ -0,0 +1,96 @@ +//===-- NativeRegisterContextFreeBSD_x86_64.h -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#if defined(__i386__) || defined(__x86_64__) + +#ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h +#define lldb_NativeRegisterContextFreeBSD_x86_64_h + +// clang-format off +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <machine/reg.h> +// clang-format on + +#include <array> + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContext_x86.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h" +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" + +#define LLDB_INVALID_XSAVE_OFFSET UINT32_MAX + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_x86_64 + : public NativeRegisterContextFreeBSD, + public NativeRegisterContextDBReg_x86 { +public: + NativeRegisterContextFreeBSD_x86_64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + uint32_t GetRegisterSetCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + // Private member types. + enum RegSetKind { + GPRegSet, + FPRegSet, + DBRegSet, + YMMRegSet, + MPXRegSet, + MaxRegSet = MPXRegSet, + }; + + // Private member variables. + std::array<uint8_t, sizeof(struct reg)> m_gpr; + std::array<uint8_t, 512> m_fpr; // FXSAVE + std::array<uint8_t, sizeof(struct dbreg)> m_dbr; + std::vector<uint8_t> m_xsave; + std::array<uint32_t, MaxRegSet + 1> m_xsave_offsets; + std::array<size_t, MaxRegSet + 1> m_regset_offsets; + + llvm::Optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + uint8_t *GetOffsetRegSetData(RegSetKind set, size_t reg_offset); + + struct YMMSplitPtr { + void *xmm; + void *ymm_hi; + }; + llvm::Optional<YMMSplitPtr> GetYMMSplitReg(uint32_t reg); +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h + +#endif // defined(__x86_64__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp new file mode 100644 index 000000000000..63be12fc7b2b --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp @@ -0,0 +1,291 @@ +//===-- NativeThreadFreeBSD.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 "NativeThreadFreeBSD.h" +#include "NativeRegisterContextFreeBSD.h" + +#include "NativeProcessFreeBSD.h" + +#include "Plugins/Process/POSIX/CrashReason.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" +#include "llvm/Support/Errno.h" + +// clang-format off +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/sysctl.h> +#include <sys/user.h> +// clang-format on + +#include <sstream> +#include <vector> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process, + lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), + m_stop_info(), + m_reg_context_up( + NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + process.GetArchitecture(), *this)), + m_stop_description() {} + +Status NativeThreadFreeBSD::Resume() { + Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID()); + if (!ret.Success()) + return ret; + ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID()); + // we can get EINVAL if the architecture in question does not support + // hardware single-stepping -- that's fine, we have nothing to clear + // then + if (ret.GetError() == EINVAL) + ret.Clear(); + if (ret.Success()) + SetRunning(); + return ret; +} + +Status NativeThreadFreeBSD::SingleStep() { + Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID()); + if (!ret.Success()) + return ret; + ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID()); + if (ret.Success()) + SetStepping(); + return ret; +} + +Status NativeThreadFreeBSD::Suspend() { + Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID()); + if (ret.Success()) + SetStopped(); + return ret; +} + +void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo, + const siginfo_t *info) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonSignal; + m_stop_info.details.signal.signo = signo; + + m_stop_description.clear(); + if (info) { + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + const auto reason = GetCrashReason(*info); + m_stop_description = GetCrashReasonString(reason, *info); + break; + } + } +} + +void NativeThreadFreeBSD::SetStoppedByBreakpoint() { + SetStopped(); + m_stop_info.reason = StopReason::eStopReasonBreakpoint; + m_stop_info.details.signal.signo = SIGTRAP; +} + +void NativeThreadFreeBSD::SetStoppedByTrace() { + SetStopped(); + m_stop_info.reason = StopReason::eStopReasonTrace; + m_stop_info.details.signal.signo = SIGTRAP; +} + +void NativeThreadFreeBSD::SetStoppedByExec() { + SetStopped(); + m_stop_info.reason = StopReason::eStopReasonExec; + m_stop_info.details.signal.signo = SIGTRAP; +} + +void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) { + lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); + + std::ostringstream ostr; + ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; + ostr << wp_index; + + ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); + + SetStopped(); + m_stop_description = ostr.str(); + m_stop_info.reason = StopReason::eStopReasonWatchpoint; + m_stop_info.details.signal.signo = SIGTRAP; +} + +void NativeThreadFreeBSD::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.details.signal.signo = 0; +} + +void NativeThreadFreeBSD::SetStopped() { + const StateType new_state = StateType::eStateStopped; + m_state = new_state; + m_stop_description.clear(); +} + +void NativeThreadFreeBSD::SetRunning() { + m_state = StateType::eStateRunning; + m_stop_info.reason = StopReason::eStopReasonNone; +} + +void NativeThreadFreeBSD::SetStepping() { + m_state = StateType::eStateStepping; + m_stop_info.reason = StopReason::eStopReasonNone; +} + +std::string NativeThreadFreeBSD::GetName() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + + std::vector<struct kinfo_proc> kp; + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, + static_cast<int>(GetProcess().GetID())}; + + while (1) { + size_t len = kp.size() * sizeof(struct kinfo_proc); + void *ptr = len == 0 ? nullptr : kp.data(); + int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0); + if (ptr == nullptr || (error != 0 && errno == ENOMEM)) { + kp.resize(len / sizeof(struct kinfo_proc)); + continue; + } + if (error != 0) { + len = 0; + LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}", + GetID(), m_state, strerror(errno)); + } + kp.resize(len / sizeof(struct kinfo_proc)); + break; + } + + for (auto &procinfo : kp) { + if (procinfo.ki_tid == static_cast<lwpid_t>(GetID())) + return procinfo.ki_tdname; + } + + return ""; +} + +lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; } + +bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + description.clear(); + + switch (m_state) { + case eStateStopped: + case eStateCrashed: + case eStateExited: + case eStateSuspended: + case eStateUnloaded: + stop_info = m_stop_info; + description = m_stop_description; + + return true; + + case eStateInvalid: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), + StateAsCString(m_state)); + return false; + } + llvm_unreachable("unhandled StateType!"); +} + +NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() { + assert(m_reg_context_up); + return *m_reg_context_up; +} + +Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + assert(m_state == eStateStopped); + if (!hardware) + return Status("not implemented"); + Status error = RemoveWatchpoint(addr); + if (error.Fail()) + return error; + uint32_t wp_index = + GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); + if (wp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware watchpoint failed."); + m_watchpoint_index_map.insert({addr, wp_index}); + return Status(); +} + +Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) { + auto wp = m_watchpoint_index_map.find(addr); + if (wp == m_watchpoint_index_map.end()) + return Status(); + uint32_t wp_index = wp->second; + m_watchpoint_index_map.erase(wp); + if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) + return Status(); + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + assert(m_state == eStateStopped); + Status error = RemoveHardwareBreakpoint(addr); + if (error.Fail()) + return error; + + uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); + + if (bp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware breakpoint failed."); + + m_hw_break_index_map.insert({addr, bp_index}); + return Status(); +} + +Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { + auto bp = m_hw_break_index_map.find(addr); + if (bp == m_hw_break_index_map.end()) + return Status(); + + uint32_t bp_index = bp->second; + if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { + m_hw_break_index_map.erase(bp); + return Status(); + } + + return Status("Clearing hardware breakpoint failed."); +} + +llvm::Error +NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) { + llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( + source.GetRegisterContext()); + if (!s) { + m_watchpoint_index_map = source.m_watchpoint_index_map; + m_hw_break_index_map = source.m_hw_break_index_map; + } + return s; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h new file mode 100644 index 000000000000..249d2486b4f7 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h @@ -0,0 +1,83 @@ +//===-- NativeThreadFreeBSD.h --------------------------------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeThreadFreeBSD_H_ +#define liblldb_NativeThreadFreeBSD_H_ + +#include "lldb/Host/common/NativeThreadProtocol.h" + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" + +#include <csignal> +#include <map> +#include <string> + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeThreadFreeBSD : public NativeThreadProtocol { + friend class NativeProcessFreeBSD; + +public: + NativeThreadFreeBSD(NativeProcessFreeBSD &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + NativeRegisterContextFreeBSD &GetRegisterContext() override; + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + +private: + // Interface for friend classes + + Status Resume(); + Status SingleStep(); + Status Suspend(); + + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + void SetStoppedByBreakpoint(); + void SetStoppedByTrace(); + void SetStoppedByExec(); + void SetStoppedByWatchpoint(uint32_t wp_index); + void SetStoppedWithNoReason(); + void SetStopped(); + void SetRunning(); + void SetStepping(); + + llvm::Error CopyWatchpointsFrom(NativeThreadFreeBSD &source); + + // Member Variables + lldb::StateType m_state; + ThreadStopInfo m_stop_info; + std::unique_ptr<NativeRegisterContextFreeBSD> m_reg_context_up; + std::string m_stop_description; + using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>; + WatchpointIndexMap m_watchpoint_index_map; + WatchpointIndexMap m_hw_break_index_map; +}; + +typedef std::shared_ptr<NativeThreadFreeBSD> NativeThreadFreeBSDSP; +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeThreadFreeBSD_H_ diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp deleted file mode 100644 index 4e6f3afda0ab..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp +++ /dev/null @@ -1,44 +0,0 @@ -//===-- POSIXStopInfo.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 "POSIXStopInfo.h" - -using namespace lldb; -using namespace lldb_private; - -//===----------------------------------------------------------------------===// -// POSIXLimboStopInfo - -POSIXLimboStopInfo::~POSIXLimboStopInfo() {} - -lldb::StopReason POSIXLimboStopInfo::GetStopReason() const { - return lldb::eStopReasonThreadExiting; -} - -const char *POSIXLimboStopInfo::GetDescription() { return "thread exiting"; } - -bool POSIXLimboStopInfo::ShouldStop(Event *event_ptr) { return false; } - -bool POSIXLimboStopInfo::ShouldNotify(Event *event_ptr) { return false; } - -//===----------------------------------------------------------------------===// -// POSIXNewThreadStopInfo - -POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() {} - -lldb::StopReason POSIXNewThreadStopInfo::GetStopReason() const { - return lldb::eStopReasonNone; -} - -const char *POSIXNewThreadStopInfo::GetDescription() { - return "thread spawned"; -} - -bool POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr) { return false; } - -bool POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr) { return false; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h deleted file mode 100644 index 88fb7f31fe06..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h +++ /dev/null @@ -1,66 +0,0 @@ -//===-- POSIXStopInfo.h -----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_POSIXStopInfo_H_ -#define liblldb_POSIXStopInfo_H_ - -#include "FreeBSDThread.h" -#include "Plugins/Process/POSIX/CrashReason.h" -#include "lldb/Target/StopInfo.h" -#include <string> - -//===----------------------------------------------------------------------===// -/// \class POSIXStopInfo -/// Simple base class for all POSIX-specific StopInfo objects. -/// -class POSIXStopInfo : public lldb_private::StopInfo { -public: - POSIXStopInfo(lldb_private::Thread &thread, uint32_t status) - : StopInfo(thread, status) {} -}; - -//===----------------------------------------------------------------------===// -/// \class POSIXLimboStopInfo -/// Represents the stop state of a process ready to exit. -/// -class POSIXLimboStopInfo : public POSIXStopInfo { -public: - POSIXLimboStopInfo(FreeBSDThread &thread) : POSIXStopInfo(thread, 0) {} - - ~POSIXLimboStopInfo(); - - lldb::StopReason GetStopReason() const; - - const char *GetDescription(); - - bool ShouldStop(lldb_private::Event *event_ptr); - - bool ShouldNotify(lldb_private::Event *event_ptr); -}; - -//===----------------------------------------------------------------------===// -/// \class POSIXNewThreadStopInfo -/// Represents the stop state of process when a new thread is spawned. -/// - -class POSIXNewThreadStopInfo : public POSIXStopInfo { -public: - POSIXNewThreadStopInfo(FreeBSDThread &thread) : POSIXStopInfo(thread, 0) {} - - ~POSIXNewThreadStopInfo(); - - lldb::StopReason GetStopReason() const; - - const char *GetDescription(); - - bool ShouldStop(lldb_private::Event *event_ptr); - - bool ShouldNotify(lldb_private::Event *event_ptr); -}; - -#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp deleted file mode 100644 index a44080640f6c..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ /dev/null @@ -1,1077 +0,0 @@ -//===-- ProcessFreeBSD.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 <errno.h> -#include <pthread.h> -#include <pthread_np.h> -#include <stdlib.h> -#include <sys/sysctl.h> -#include <sys/types.h> -#include <sys/user.h> -#include <machine/elf.h> - -#include <mutex> -#include <unordered_map> - -#include "lldb/Core/PluginManager.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/Host.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/State.h" - -#include "FreeBSDThread.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/FreeBSDSignals.h" -#include "Plugins/Process/Utility/InferiorCallPOSIX.h" -#include "ProcessFreeBSD.h" -#include "ProcessMonitor.h" - -#include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Host/Host.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Target/Platform.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/State.h" - -#include "lldb/Host/posix/Fcntl.h" - -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Threading.h" - -using namespace lldb; -using namespace lldb_private; - -LLDB_PLUGIN_DEFINE(ProcessFreeBSD) - -namespace { -UnixSignalsSP &GetFreeBSDSignals() { - static UnixSignalsSP s_freebsd_signals_sp(new FreeBSDSignals()); - return s_freebsd_signals_sp; -} -} - -// Static functions. - -lldb::ProcessSP -ProcessFreeBSD::CreateInstance(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path) { - lldb::ProcessSP process_sp; - if (crash_file_path == NULL) - process_sp.reset( - new ProcessFreeBSD(target_sp, listener_sp, GetFreeBSDSignals())); - return process_sp; -} - -void ProcessFreeBSD::Initialize() { - static llvm::once_flag g_once_flag; - - llvm::call_once(g_once_flag, []() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), CreateInstance); - }); -} - -lldb_private::ConstString ProcessFreeBSD::GetPluginNameStatic() { - static ConstString g_name("freebsd"); - return g_name; -} - -const char *ProcessFreeBSD::GetPluginDescriptionStatic() { - return "Process plugin for FreeBSD"; -} - -// ProcessInterface protocol. - -lldb_private::ConstString ProcessFreeBSD::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t ProcessFreeBSD::GetPluginVersion() { return 1; } - -void ProcessFreeBSD::Terminate() {} - -Status ProcessFreeBSD::DoDetach(bool keep_stopped) { - Status error; - if (keep_stopped) { - error.SetErrorString("Detaching with keep_stopped true is not currently " - "supported on FreeBSD."); - return error; - } - - error = m_monitor->Detach(GetID()); - - if (error.Success()) - SetPrivateState(eStateDetached); - - return error; -} - -Status ProcessFreeBSD::DoResume() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - SetPrivateState(eStateRunning); - - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - bool do_step = false; - bool software_single_step = !SupportHardwareSingleStepping(); - - for (tid_collection::const_iterator t_pos = m_run_tids.begin(), - t_end = m_run_tids.end(); - t_pos != t_end; ++t_pos) { - m_monitor->ThreadSuspend(*t_pos, false); - } - for (tid_collection::const_iterator t_pos = m_step_tids.begin(), - t_end = m_step_tids.end(); - t_pos != t_end; ++t_pos) { - m_monitor->ThreadSuspend(*t_pos, false); - do_step = true; - if (software_single_step) { - Status error = SetupSoftwareSingleStepping(*t_pos); - if (error.Fail()) - return error; - } - } - for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(), - t_end = m_suspend_tids.end(); - t_pos != t_end; ++t_pos) { - m_monitor->ThreadSuspend(*t_pos, true); - // XXX Cannot PT_CONTINUE properly with suspended threads. - do_step = true; - } - - LLDB_LOGF(log, "process %" PRIu64 " resuming (%s)", GetID(), - do_step ? "step" : "continue"); - if (do_step && !software_single_step) - m_monitor->SingleStep(GetID(), m_resume_signo); - else - m_monitor->Resume(GetID(), m_resume_signo); - - return Status(); -} - -bool ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOGF(log, "ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__, - GetID()); - - std::vector<lldb::pid_t> tds; - if (!GetMonitor().GetCurrentThreadIDs(tds)) { - return false; - } - - ThreadList old_thread_list_copy(old_thread_list); - for (size_t i = 0; i < tds.size(); ++i) { - tid_t tid = tds[i]; - ThreadSP thread_sp(old_thread_list_copy.RemoveThreadByID(tid, false)); - if (!thread_sp) { - thread_sp.reset(new FreeBSDThread(*this, tid)); - LLDB_LOGF(log, "ProcessFreeBSD::%s new tid = %" PRIu64, __FUNCTION__, - tid); - } else { - LLDB_LOGF(log, "ProcessFreeBSD::%s existing tid = %" PRIu64, __FUNCTION__, - tid); - } - new_thread_list.AddThread(thread_sp); - } - for (size_t i = 0; i < old_thread_list_copy.GetSize(false); ++i) { - ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); - if (old_thread_sp) { - LLDB_LOGF(log, "ProcessFreeBSD::%s remove tid", __FUNCTION__); - } - } - - return true; -} - -Status ProcessFreeBSD::WillResume() { - m_resume_signo = 0; - m_suspend_tids.clear(); - m_run_tids.clear(); - m_step_tids.clear(); - return Process::WillResume(); -} - -void ProcessFreeBSD::SendMessage(const ProcessMessage &message) { - std::lock_guard<std::recursive_mutex> guard(m_message_mutex); - - switch (message.GetKind()) { - case ProcessMessage::eInvalidMessage: - return; - - case ProcessMessage::eAttachMessage: - SetPrivateState(eStateStopped); - return; - - case ProcessMessage::eLimboMessage: - case ProcessMessage::eExitMessage: - SetExitStatus(message.GetExitStatus(), NULL); - break; - - case ProcessMessage::eSignalMessage: - case ProcessMessage::eSignalDeliveredMessage: - case ProcessMessage::eBreakpointMessage: - case ProcessMessage::eTraceMessage: - case ProcessMessage::eWatchpointMessage: - case ProcessMessage::eCrashMessage: - SetPrivateState(eStateStopped); - break; - - case ProcessMessage::eNewThreadMessage: - llvm_unreachable("eNewThreadMessage unexpected on FreeBSD"); - break; - - case ProcessMessage::eExecMessage: - SetPrivateState(eStateStopped); - break; - } - - m_message_queue.push(message); -} - -// Constructors and destructors. - -ProcessFreeBSD::ProcessFreeBSD(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - UnixSignalsSP &unix_signals_sp) - : Process(target_sp, listener_sp, unix_signals_sp), - m_byte_order(endian::InlHostByteOrder()), m_monitor(NULL), m_module(NULL), - m_message_mutex(), m_exit_now(false), m_seen_initial_stop(), - m_resume_signo(0) { - // FIXME: Putting this code in the ctor and saving the byte order in a - // member variable is a hack to avoid const qual issues in GetByteOrder. - lldb::ModuleSP module = GetTarget().GetExecutableModule(); - if (module && module->GetObjectFile()) - m_byte_order = module->GetObjectFile()->GetByteOrder(); -} - -ProcessFreeBSD::~ProcessFreeBSD() { delete m_monitor; } - -// Process protocol. -void ProcessFreeBSD::Finalize() { - Process::Finalize(); - - if (m_monitor) - m_monitor->StopMonitor(); -} - -bool ProcessFreeBSD::CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) { - // For now we are just making sure the file exists for a given module - ModuleSP exe_module_sp(target_sp->GetExecutableModule()); - if (exe_module_sp.get()) - return FileSystem::Instance().Exists(exe_module_sp->GetFileSpec()); - // If there is no executable module, we return true since we might be - // preparing to attach. - return true; -} - -Status -ProcessFreeBSD::DoAttachToProcessWithID(lldb::pid_t pid, - const ProcessAttachInfo &attach_info) { - Status error; - assert(m_monitor == NULL); - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOGV(log, "pid = {0}", GetID()); - - m_monitor = new ProcessMonitor(this, pid, error); - - if (!error.Success()) - return error; - - PlatformSP platform_sp(GetTarget().GetPlatform()); - assert(platform_sp.get()); - if (!platform_sp) - return error; // FIXME: Detatch? - - // Find out what we can about this process - ProcessInstanceInfo process_info; - platform_sp->GetProcessInfo(pid, process_info); - - // Resolve the executable module - ModuleSP exe_module_sp; - FileSpecList executable_search_paths( - Target::GetDefaultExecutableSearchPaths()); - ModuleSpec exe_module_spec(process_info.GetExecutableFile(), - GetTarget().GetArchitecture()); - error = platform_sp->ResolveExecutable( - exe_module_spec, exe_module_sp, - executable_search_paths.GetSize() ? &executable_search_paths : NULL); - if (!error.Success()) - return error; - - // Fix the target architecture if necessary - const ArchSpec &module_arch = exe_module_sp->GetArchitecture(); - if (module_arch.IsValid() && - !GetTarget().GetArchitecture().IsExactMatch(module_arch)) - GetTarget().SetArchitecture(module_arch); - - // Initialize the target module list - GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsYes); - - SetSTDIOFileDescriptor(m_monitor->GetTerminalFD()); - - SetID(pid); - - return error; -} - -Status ProcessFreeBSD::WillLaunch(Module *module) { - Status error; - return error; -} - -FileSpec -ProcessFreeBSD::GetFileSpec(const lldb_private::FileAction *file_action, - const FileSpec &default_file_spec, - const FileSpec &dbg_pts_file_spec) { - FileSpec file_spec{}; - - if (file_action && file_action->GetAction() == FileAction::eFileActionOpen) { - file_spec = file_action->GetFileSpec(); - // By default the stdio paths passed in will be pseudo-terminal (/dev/pts). - // If so, convert to using a different default path instead to redirect I/O - // to the debugger console. This should also handle user overrides to - // /dev/null or a different file. - if (!file_spec || file_spec == dbg_pts_file_spec) - file_spec = default_file_spec; - } - return file_spec; -} - -Status ProcessFreeBSD::DoLaunch(Module *module, - ProcessLaunchInfo &launch_info) { - Status error; - assert(m_monitor == NULL); - - FileSpec working_dir = launch_info.GetWorkingDirectory(); - if (working_dir) { - FileSystem::Instance().Resolve(working_dir); - if (!FileSystem::Instance().IsDirectory(working_dir.GetPath())) { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return error; - } - } - - SetPrivateState(eStateLaunching); - - const lldb_private::FileAction *file_action; - - // Default of empty will mean to use existing open file descriptors - FileSpec stdin_file_spec{}; - FileSpec stdout_file_spec{}; - FileSpec stderr_file_spec{}; - - const FileSpec dbg_pts_file_spec{ - launch_info.GetPTY().GetSecondaryName(NULL, 0)}; - - file_action = launch_info.GetFileActionForFD(STDIN_FILENO); - stdin_file_spec = - GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); - - file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); - stdout_file_spec = - GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); - - file_action = launch_info.GetFileActionForFD(STDERR_FILENO); - stderr_file_spec = - GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); - - m_monitor = new ProcessMonitor( - this, module, launch_info.GetArguments().GetConstArgumentVector(), - launch_info.GetEnvironment(), stdin_file_spec, stdout_file_spec, - stderr_file_spec, working_dir, launch_info, error); - - m_module = module; - - if (!error.Success()) - return error; - - int terminal = m_monitor->GetTerminalFD(); - if (terminal >= 0) { -// The reader thread will close the file descriptor when done, so we pass it a -// copy. -#ifdef F_DUPFD_CLOEXEC - int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0); - if (stdio == -1) { - error.SetErrorToErrno(); - return error; - } -#else - // Special case when F_DUPFD_CLOEXEC does not exist (Debian kFreeBSD) - int stdio = fcntl(terminal, F_DUPFD, 0); - if (stdio == -1) { - error.SetErrorToErrno(); - return error; - } - stdio = fcntl(terminal, F_SETFD, FD_CLOEXEC); - if (stdio == -1) { - error.SetErrorToErrno(); - return error; - } -#endif - SetSTDIOFileDescriptor(stdio); - } - - SetID(m_monitor->GetPID()); - return error; -} - -void ProcessFreeBSD::DidLaunch() {} - -addr_t ProcessFreeBSD::GetImageInfoAddress() { - Target *target = &GetTarget(); - ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(target); - - if (addr.IsValid()) - return addr.GetLoadAddress(target); - return LLDB_INVALID_ADDRESS; -} - -Status ProcessFreeBSD::DoHalt(bool &caused_stop) { - Status error; - - if (IsStopped()) { - caused_stop = false; - } else if (kill(GetID(), SIGSTOP)) { - caused_stop = false; - error.SetErrorToErrno(); - } else { - caused_stop = true; - } - return error; -} - -Status ProcessFreeBSD::DoSignal(int signal) { - Status error; - - if (kill(GetID(), signal)) - error.SetErrorToErrno(); - - return error; -} - -Status ProcessFreeBSD::DoDestroy() { - Status error; - - if (!HasExited()) { - assert(m_monitor); - m_exit_now = true; - if (GetID() == LLDB_INVALID_PROCESS_ID) { - error.SetErrorString("invalid process id"); - return error; - } - if (!m_monitor->Kill()) { - error.SetErrorToErrno(); - return error; - } - - SetPrivateState(eStateExited); - } - - return error; -} - -void ProcessFreeBSD::DoDidExec() { - Target *target = &GetTarget(); - if (target) { - PlatformSP platform_sp(target->GetPlatform()); - assert(platform_sp.get()); - if (platform_sp) { - ProcessInstanceInfo process_info; - platform_sp->GetProcessInfo(GetID(), process_info); - ModuleSP exe_module_sp; - ModuleSpec exe_module_spec(process_info.GetExecutableFile(), - target->GetArchitecture()); - FileSpecList executable_search_paths( - Target::GetDefaultExecutableSearchPaths()); - Status error = platform_sp->ResolveExecutable( - exe_module_spec, exe_module_sp, - executable_search_paths.GetSize() ? &executable_search_paths : NULL); - if (!error.Success()) - return; - target->SetExecutableModule(exe_module_sp, eLoadDependentsYes); - } - } -} - -bool ProcessFreeBSD::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) { - bool added_to_set = false; - ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid); - if (it == m_seen_initial_stop.end()) { - m_seen_initial_stop.insert(stop_tid); - added_to_set = true; - } - return added_to_set; -} - -bool ProcessFreeBSD::WaitingForInitialStop(lldb::tid_t stop_tid) { - return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end()); -} - -FreeBSDThread * -ProcessFreeBSD::CreateNewFreeBSDThread(lldb_private::Process &process, - lldb::tid_t tid) { - return new FreeBSDThread(process, tid); -} - -void ProcessFreeBSD::RefreshStateAfterStop() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOGV(log, "message_queue size = {0}", m_message_queue.size()); - - std::lock_guard<std::recursive_mutex> guard(m_message_mutex); - - // This method used to only handle one message. Changing it to loop allows - // it to handle the case where we hit a breakpoint while handling a different - // breakpoint. - while (!m_message_queue.empty()) { - ProcessMessage &message = m_message_queue.front(); - - // Resolve the thread this message corresponds to and pass it along. - lldb::tid_t tid = message.GetTID(); - LLDB_LOGV(log, " message_queue size = {0}, pid = {1}", - m_message_queue.size(), tid); - - m_thread_list.RefreshStateAfterStop(); - - FreeBSDThread *thread = static_cast<FreeBSDThread *>( - GetThreadList().FindThreadByID(tid, false).get()); - if (thread) - thread->Notify(message); - - if (message.GetKind() == ProcessMessage::eExitMessage) { - // FIXME: We should tell the user about this, but the limbo message is - // probably better for that. - LLDB_LOG(log, "removing thread, tid = {0}", tid); - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - - ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false); - thread_sp.reset(); - m_seen_initial_stop.erase(tid); - } - - m_message_queue.pop(); - } -} - -bool ProcessFreeBSD::IsAlive() { - StateType state = GetPrivateState(); - return state != eStateDetached && state != eStateExited && - state != eStateInvalid && state != eStateUnloaded; -} - -size_t ProcessFreeBSD::DoReadMemory(addr_t vm_addr, void *buf, size_t size, - Status &error) { - assert(m_monitor); - return m_monitor->ReadMemory(vm_addr, buf, size, error); -} - -size_t ProcessFreeBSD::DoWriteMemory(addr_t vm_addr, const void *buf, - size_t size, Status &error) { - assert(m_monitor); - return m_monitor->WriteMemory(vm_addr, buf, size, error); -} - -addr_t ProcessFreeBSD::DoAllocateMemory(size_t size, uint32_t permissions, - Status &error) { - addr_t allocated_addr = LLDB_INVALID_ADDRESS; - - unsigned prot = 0; - if (permissions & lldb::ePermissionsReadable) - prot |= eMmapProtRead; - if (permissions & lldb::ePermissionsWritable) - prot |= eMmapProtWrite; - if (permissions & lldb::ePermissionsExecutable) - prot |= eMmapProtExec; - - if (InferiorCallMmap(this, allocated_addr, 0, size, prot, - eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { - m_addr_to_mmap_size[allocated_addr] = size; - error.Clear(); - } else { - allocated_addr = LLDB_INVALID_ADDRESS; - error.SetErrorStringWithFormat( - "unable to allocate %zu bytes of memory with permissions %s", size, - GetPermissionsAsCString(permissions)); - } - - return allocated_addr; -} - -Status ProcessFreeBSD::DoDeallocateMemory(lldb::addr_t addr) { - Status error; - MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); - if (pos != m_addr_to_mmap_size.end() && - InferiorCallMunmap(this, addr, pos->second)) - m_addr_to_mmap_size.erase(pos); - else - error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, - addr); - - return error; -} - -size_t -ProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) { - static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xD4}; - static const uint8_t g_i386_opcode[] = {0xCC}; - - ArchSpec arch = GetTarget().GetArchitecture(); - const uint8_t *opcode = NULL; - size_t opcode_size = 0; - - switch (arch.GetMachine()) { - default: - assert(false && "CPU type not supported!"); - break; - - case llvm::Triple::arm: { - // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the - // linux kernel does otherwise. - static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; - static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; - - lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); - AddressClass addr_class = AddressClass::eUnknown; - - if (bp_loc_sp) - addr_class = bp_loc_sp->GetAddress().GetAddressClass(); - - if (addr_class == AddressClass::eCodeAlternateISA || - (addr_class == AddressClass::eUnknown && - bp_loc_sp->GetAddress().GetOffset() & 1)) { - opcode = g_thumb_breakpoint_opcode; - opcode_size = sizeof(g_thumb_breakpoint_opcode); - } else { - opcode = g_arm_breakpoint_opcode; - opcode_size = sizeof(g_arm_breakpoint_opcode); - } - } break; - case llvm::Triple::aarch64: - opcode = g_aarch64_opcode; - opcode_size = sizeof(g_aarch64_opcode); - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - opcode = g_i386_opcode; - opcode_size = sizeof(g_i386_opcode); - break; - } - - bp_site->SetTrapOpcode(opcode, opcode_size); - return opcode_size; -} - -Status ProcessFreeBSD::EnableBreakpointSite(BreakpointSite *bp_site) { - return EnableSoftwareBreakpoint(bp_site); -} - -Status ProcessFreeBSD::DisableBreakpointSite(BreakpointSite *bp_site) { - return DisableSoftwareBreakpoint(bp_site); -} - -Status ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) { - Status error; - if (wp) { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOGF(log, "ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 ")", - watchID); - if (wp->IsEnabled()) { - LLDB_LOGF(log, - "ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", - watchID, (uint64_t)addr); - return error; - } - - // Try to find a vacant watchpoint slot in the inferiors' main thread - uint32_t wp_hw_index = LLDB_INVALID_INDEX32; - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - FreeBSDThread *thread = static_cast<FreeBSDThread *>( - m_thread_list.GetThreadAtIndex(0, false).get()); - - if (thread) - wp_hw_index = thread->FindVacantWatchpointIndex(); - - if (wp_hw_index == LLDB_INVALID_INDEX32) { - error.SetErrorString("Setting hardware watchpoint failed."); - } else { - wp->SetHardwareIndex(wp_hw_index); - bool wp_enabled = true; - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) { - thread = static_cast<FreeBSDThread *>( - m_thread_list.GetThreadAtIndex(i, false).get()); - if (thread) - wp_enabled &= thread->EnableHardwareWatchpoint(wp); - else - wp_enabled = false; - } - if (wp_enabled) { - wp->SetEnabled(true, notify); - return error; - } else { - // Watchpoint enabling failed on at least one of the threads so roll - // back all of them - DisableWatchpoint(wp, false); - error.SetErrorString("Setting hardware watchpoint failed"); - } - } - } else - error.SetErrorString("Watchpoint argument was NULL."); - return error; -} - -Status ProcessFreeBSD::DisableWatchpoint(Watchpoint *wp, bool notify) { - Status error; - if (wp) { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOGF(log, "ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 ")", - watchID); - if (!wp->IsEnabled()) { - LLDB_LOGF(log, - "ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", - watchID, (uint64_t)addr); - // This is needed (for now) to keep watchpoints disabled correctly - wp->SetEnabled(false, notify); - return error; - } - - if (wp->IsHardware()) { - bool wp_disabled = true; - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) { - FreeBSDThread *thread = static_cast<FreeBSDThread *>( - m_thread_list.GetThreadAtIndex(i, false).get()); - if (thread) - wp_disabled &= thread->DisableHardwareWatchpoint(wp); - else - wp_disabled = false; - } - if (wp_disabled) { - wp->SetHardwareIndex(LLDB_INVALID_INDEX32); - wp->SetEnabled(false, notify); - return error; - } else - error.SetErrorString("Disabling hardware watchpoint failed"); - } - } else - error.SetErrorString("Watchpoint argument was NULL."); - return error; -} - -Status ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) { - Status error; - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - FreeBSDThread *thread = static_cast<FreeBSDThread *>( - m_thread_list.GetThreadAtIndex(0, false).get()); - if (thread) - num = thread->NumSupportedHardwareWatchpoints(); - else - error.SetErrorString("Process does not exist."); - return error; -} - -Status ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num, bool &after) { - Status error = GetWatchpointSupportInfo(num); - // Watchpoints trigger and halt the inferior after the corresponding - // instruction has been executed. - after = true; - return error; -} - -uint32_t ProcessFreeBSD::UpdateThreadListIfNeeded() { - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - // Do not allow recursive updates. - return m_thread_list.GetSize(false); -} - -ByteOrder ProcessFreeBSD::GetByteOrder() const { - // FIXME: We should be able to extract this value directly. See comment in - // ProcessFreeBSD(). - return m_byte_order; -} - -size_t ProcessFreeBSD::PutSTDIN(const char *buf, size_t len, Status &error) { - ssize_t status; - if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0) { - error.SetErrorToErrno(); - return 0; - } - return status; -} - -// Utility functions. - -bool ProcessFreeBSD::HasExited() { - switch (GetPrivateState()) { - default: - break; - - case eStateDetached: - case eStateExited: - return true; - } - - return false; -} - -bool ProcessFreeBSD::IsStopped() { - switch (GetPrivateState()) { - default: - break; - - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - return true; - } - - return false; -} - -bool ProcessFreeBSD::IsAThreadRunning() { - bool is_running = false; - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) { - FreeBSDThread *thread = static_cast<FreeBSDThread *>( - m_thread_list.GetThreadAtIndex(i, false).get()); - StateType thread_state = thread->GetState(); - if (thread_state == eStateRunning || thread_state == eStateStepping) { - is_running = true; - break; - } - } - return is_running; -} - -lldb_private::DataExtractor ProcessFreeBSD::GetAuxvData() { - // If we're the local platform, we can ask the host for auxv data. - PlatformSP platform_sp = GetTarget().GetPlatform(); - assert(platform_sp && platform_sp->IsHost()); - - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, (int)m_process->GetID()}; - size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo); - DataBufferSP buf_sp(new DataBufferHeap(auxv_size, 0)); - - if (::sysctl(mib, 4, buf_sp->GetBytes(), &auxv_size, NULL, 0) != 0) { - perror("sysctl failed on auxv"); - buf_sp.reset(); - } - - return DataExtractor(buf_sp, GetByteOrder(), GetAddressByteSize()); -} - -struct EmulatorBaton { - ProcessFreeBSD *m_process; - RegisterContext *m_reg_context; - - // eRegisterKindDWARF -> RegisterValue - std::unordered_map<uint32_t, RegisterValue> m_register_values; - - EmulatorBaton(ProcessFreeBSD *process, RegisterContext *reg_context) - : m_process(process), m_reg_context(reg_context) {} -}; - -static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, void *dst, size_t length) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - - Status error; - size_t bytes_read = - emulator_baton->m_process->DoReadMemory(addr, dst, length, error); - if (!error.Success()) - bytes_read = 0; - return bytes_read; -} - -static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, - const RegisterInfo *reg_info, - RegisterValue ®_value) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - - auto it = emulator_baton->m_register_values.find( - reg_info->kinds[eRegisterKindDWARF]); - if (it != emulator_baton->m_register_values.end()) { - reg_value = it->second; - return true; - } - - // The emulator only fills in the dwarf register numbers (and in some cases - // the generic register numbers). Get the full register info from the - // register context based on the dwarf register numbers. - const RegisterInfo *full_reg_info = - emulator_baton->m_reg_context->GetRegisterInfo( - eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); - - bool error = - emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value); - return error; -} - -static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - const RegisterInfo *reg_info, - const RegisterValue ®_value) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = - reg_value; - return true; -} - -static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, const void *dst, - size_t length) { - return length; -} - -bool ProcessFreeBSD::SingleStepBreakpointHit( - void *baton, lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, lldb::user_id_t break_loc_id) { - return false; -} - -Status ProcessFreeBSD::SetSoftwareSingleStepBreakpoint(lldb::tid_t tid, - lldb::addr_t addr) { - Status error; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - if (log) { - LLDB_LOGF(log, "ProcessFreeBSD::%s addr = 0x%" PRIx64, __FUNCTION__, addr); - LLDB_LOGF(log, "SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, - addr); - } - - // Validate the address. - if (addr == LLDB_INVALID_ADDRESS) - return Status("ProcessFreeBSD::%s invalid load address specified.", - __FUNCTION__); - - Breakpoint *const sw_step_break = - m_process->GetTarget().CreateBreakpoint(addr, true, false).get(); - sw_step_break->SetCallback(SingleStepBreakpointHit, this, true); - sw_step_break->SetBreakpointKind("software-single-step"); - - LLDB_LOGF(log, "ProcessFreeBSD::%s addr = 0x%" PRIx64 " -- SUCCESS", - __FUNCTION__, addr); - - m_threads_stepping_with_breakpoint.insert({tid, sw_step_break->GetID()}); - return Status(); -} - -bool ProcessFreeBSD::IsSoftwareStepBreakpoint(lldb::tid_t tid) { - ThreadSP thread = GetThreadList().FindThreadByID(tid); - if (!thread) - return false; - - assert(thread->GetRegisterContext()); - lldb::addr_t stop_pc = thread->GetRegisterContext()->GetPC(); - - const auto &iter = m_threads_stepping_with_breakpoint.find(tid); - if (iter == m_threads_stepping_with_breakpoint.end()) - return false; - - lldb::break_id_t bp_id = iter->second; - BreakpointSP bp = GetTarget().GetBreakpointByID(bp_id); - if (!bp) - return false; - - BreakpointLocationSP bp_loc = bp->FindLocationByAddress(stop_pc); - if (!bp_loc) - return false; - - GetTarget().RemoveBreakpointByID(bp_id); - m_threads_stepping_with_breakpoint.erase(tid); - return true; -} - -bool ProcessFreeBSD::SupportHardwareSingleStepping() const { - lldb_private::ArchSpec arch = GetTarget().GetArchitecture(); - if (arch.GetMachine() == llvm::Triple::arm || arch.IsMIPS()) - return false; - return true; -} - -Status ProcessFreeBSD::SetupSoftwareSingleStepping(lldb::tid_t tid) { - std::unique_ptr<EmulateInstruction> emulator_up( - EmulateInstruction::FindPlugin(GetTarget().GetArchitecture(), - eInstructionTypePCModifying, nullptr)); - - if (emulator_up == nullptr) - return Status("Instruction emulator not found!"); - - FreeBSDThread *thread = static_cast<FreeBSDThread *>( - m_thread_list.FindThreadByID(tid, false).get()); - if (thread == NULL) - return Status("Thread not found not found!"); - - lldb::RegisterContextSP register_context_sp = thread->GetRegisterContext(); - - EmulatorBaton baton(this, register_context_sp.get()); - emulator_up->SetBaton(&baton); - emulator_up->SetReadMemCallback(&ReadMemoryCallback); - emulator_up->SetReadRegCallback(&ReadRegisterCallback); - emulator_up->SetWriteMemCallback(&WriteMemoryCallback); - emulator_up->SetWriteRegCallback(&WriteRegisterCallback); - - if (!emulator_up->ReadInstruction()) - return Status("Read instruction failed!"); - - bool emulation_result = - emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); - const RegisterInfo *reg_info_pc = register_context_sp->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - auto pc_it = - baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); - - lldb::addr_t next_pc; - if (emulation_result) { - assert(pc_it != baton.m_register_values.end() && - "Emulation was successful but PC wasn't updated"); - next_pc = pc_it->second.GetAsUInt64(); - } else if (pc_it == baton.m_register_values.end()) { - // Emulate instruction failed and it haven't changed PC. Advance PC with - // the size of the current opcode because the emulation of all - // PC modifying instruction should be successful. The failure most - // likely caused by a not supported instruction which don't modify PC. - next_pc = - register_context_sp->GetPC() + emulator_up->GetOpcode().GetByteSize(); - } else { - // The instruction emulation failed after it modified the PC. It is an - // unknown error where we can't continue because the next instruction is - // modifying the PC but we don't know how. - return Status("Instruction emulation failed unexpectedly"); - } - - SetSoftwareSingleStepBreakpoint(tid, next_pc); - return Status(); -} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h deleted file mode 100644 index 536da0c0aa70..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h +++ /dev/null @@ -1,220 +0,0 @@ -//===-- ProcessFreeBSD.h ------------------------------------------*- C++ -//-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessFreeBSD_H_ -#define liblldb_ProcessFreeBSD_H_ - -#include "Plugins/Process/POSIX/ProcessMessage.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/ThreadList.h" -#include <mutex> -#include <queue> -#include <set> - -class ProcessMonitor; -class FreeBSDThread; - -class ProcessFreeBSD : public lldb_private::Process { - -public: - // Static functions. - static lldb::ProcessSP - CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const lldb_private::FileSpec *crash_file_path); - - static void Initialize(); - - static void Terminate(); - - static lldb_private::ConstString GetPluginNameStatic(); - - static const char *GetPluginDescriptionStatic(); - - // Constructors and destructors - ProcessFreeBSD(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - lldb::UnixSignalsSP &unix_signals_sp); - - ~ProcessFreeBSD(); - - virtual lldb_private::Status WillResume() override; - - // PluginInterface protocol - virtual lldb_private::ConstString GetPluginName() override; - - virtual uint32_t GetPluginVersion() override; - -public: - // Process protocol. - void Finalize() override; - - bool CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) override; - - lldb_private::Status WillLaunch(lldb_private::Module *module) override; - - lldb_private::Status DoAttachToProcessWithID( - lldb::pid_t pid, - const lldb_private::ProcessAttachInfo &attach_info) override; - - lldb_private::Status - DoLaunch(lldb_private::Module *exe_module, - lldb_private::ProcessLaunchInfo &launch_info) override; - - void DidLaunch() override; - - lldb_private::Status DoResume() override; - - lldb_private::Status DoHalt(bool &caused_stop) override; - - lldb_private::Status DoDetach(bool keep_stopped) override; - - lldb_private::Status DoSignal(int signal) override; - - lldb_private::Status DoDestroy() override; - - void DoDidExec() override; - - void RefreshStateAfterStop() override; - - bool IsAlive() override; - - size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - lldb_private::Status &error) override; - - size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Status &error) override; - - lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, - lldb_private::Status &error) override; - - lldb_private::Status DoDeallocateMemory(lldb::addr_t ptr) override; - - virtual size_t - GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite *bp_site); - - lldb_private::Status - EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - - lldb_private::Status - DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - - lldb_private::Status EnableWatchpoint(lldb_private::Watchpoint *wp, - bool notify = true) override; - - lldb_private::Status DisableWatchpoint(lldb_private::Watchpoint *wp, - bool notify = true) override; - - lldb_private::Status GetWatchpointSupportInfo(uint32_t &num) override; - - lldb_private::Status GetWatchpointSupportInfo(uint32_t &num, - bool &after) override; - - virtual uint32_t UpdateThreadListIfNeeded(); - - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; - - virtual lldb::ByteOrder GetByteOrder() const; - - lldb::addr_t GetImageInfoAddress() override; - - size_t PutSTDIN(const char *buf, size_t len, - lldb_private::Status &error) override; - - lldb_private::DataExtractor GetAuxvData() override; - - // ProcessFreeBSD internal API. - - /// Registers the given message with this process. - virtual void SendMessage(const ProcessMessage &message); - - ProcessMonitor &GetMonitor() { - assert(m_monitor); - return *m_monitor; - } - - lldb_private::FileSpec - GetFileSpec(const lldb_private::FileAction *file_action, - const lldb_private::FileSpec &default_file_spec, - const lldb_private::FileSpec &dbg_pts_file_spec); - - /// Adds the thread to the list of threads for which we have received the - /// initial stopping signal. - /// The \p stop_tid parameter indicates the thread which the stop happened - /// for. - bool AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); - - bool WaitingForInitialStop(lldb::tid_t stop_tid); - - virtual FreeBSDThread *CreateNewFreeBSDThread(lldb_private::Process &process, - lldb::tid_t tid); - - static bool SingleStepBreakpointHit( - void *baton, lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, lldb::user_id_t break_loc_id); - - lldb_private::Status SetupSoftwareSingleStepping(lldb::tid_t tid); - - lldb_private::Status SetSoftwareSingleStepBreakpoint(lldb::tid_t tid, - lldb::addr_t addr); - - bool IsSoftwareStepBreakpoint(lldb::tid_t tid); - - bool SupportHardwareSingleStepping() const; - - typedef std::vector<lldb::tid_t> tid_collection; - tid_collection &GetStepTids() { return m_step_tids; } - -protected: - static const size_t MAX_TRAP_OPCODE_SIZE = 8; - - /// Target byte order. - lldb::ByteOrder m_byte_order; - - /// Process monitor; - ProcessMonitor *m_monitor; - - /// The module we are executing. - lldb_private::Module *m_module; - - /// Message queue notifying this instance of inferior process state changes. - std::recursive_mutex m_message_mutex; - std::queue<ProcessMessage> m_message_queue; - - /// Drive any exit events to completion. - bool m_exit_now; - - /// Returns true if the process has exited. - bool HasExited(); - - /// Returns true if the process is stopped. - bool IsStopped(); - - /// Returns true if at least one running is currently running - bool IsAThreadRunning(); - - typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap; - MMapMap m_addr_to_mmap_size; - - typedef std::set<lldb::tid_t> ThreadStopSet; - /// Every thread begins with a stop signal. This keeps track - /// of the threads for which we have received the stop signal. - ThreadStopSet m_seen_initial_stop; - - friend class FreeBSDThread; - - tid_collection m_suspend_tids; - tid_collection m_run_tids; - tid_collection m_step_tids; - std::map<lldb::tid_t, lldb::break_id_t> m_threads_stepping_with_breakpoint; - - int m_resume_signo; -}; - -#endif // liblldb_ProcessFreeBSD_H_ diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp deleted file mode 100644 index 050cab730d67..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ /dev/null @@ -1,1427 +0,0 @@ -//===-- ProcessMonitor.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 <errno.h> -#include <poll.h> -#include <signal.h> -#include <stdint.h> -#include <string.h> -#include <sys/ptrace.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "lldb/Host/Host.h" -#include "lldb/Host/PseudoTerminal.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Thread.h" -#include "lldb/Target/UnixSignals.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Scalar.h" -#include "lldb/Utility/Status.h" -#include "llvm/Support/Errno.h" - -#include "FreeBSDThread.h" -#include "Plugins/Process/POSIX/CrashReason.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "ProcessFreeBSD.h" -#include "ProcessMonitor.h" - -using namespace lldb; -using namespace lldb_private; - -// Wrapper for ptrace to catch errors and log calls. - -const char *Get_PT_IO_OP(int op) { - switch (op) { - case PIOD_READ_D: - return "READ_D"; - case PIOD_WRITE_D: - return "WRITE_D"; - case PIOD_READ_I: - return "READ_I"; - case PIOD_WRITE_I: - return "WRITE_I"; - default: - return "Unknown op"; - } -} - -// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets -// errno on error because -1 is reserved as a valid result. -extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, - const char *reqName, const char *file, int line) { - long int result; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - if (log) { - LLDB_LOGF(log, - "ptrace(%s, %" PRIu64 ", %p, %x) called from file %s line %d", - reqName, pid, addr, data, file, line); - if (req == PT_IO) { - struct ptrace_io_desc *pi = (struct ptrace_io_desc *)addr; - - LLDB_LOGF(log, "PT_IO: op=%s offs=%zx size=%zu", - Get_PT_IO_OP(pi->piod_op), (size_t)pi->piod_offs, pi->piod_len); - } - } - - // PtraceDisplayBytes(req, data); - - errno = 0; - result = ptrace(req, pid, (caddr_t)addr, data); - - // PtraceDisplayBytes(req, data); - - if (log && errno != 0) { - const char *str; - switch (errno) { - case ESRCH: - str = "ESRCH"; - break; - case EINVAL: - str = "EINVAL"; - break; - case EBUSY: - str = "EBUSY"; - break; - case EPERM: - str = "EPERM"; - break; - default: - str = "<unknown>"; - } - LLDB_LOGF(log, "ptrace() failed; errno=%d (%s)", errno, str); - } - - if (log) { -#ifdef __amd64__ - if (req == PT_GETREGS) { - struct reg *r = (struct reg *)addr; - - LLDB_LOGF(log, "PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx", - r->r_rip, r->r_rsp, r->r_rbp, r->r_rax); - } - if (req == PT_GETDBREGS || req == PT_SETDBREGS) { - struct dbreg *r = (struct dbreg *)addr; - char setget = (req == PT_GETDBREGS) ? 'G' : 'S'; - - for (int i = 0; i <= 7; i++) - LLDB_LOGF(log, "PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]); - } -#endif - } - - return result; -} - -// Wrapper for ptrace when logging is not required. Sets errno to 0 prior to -// calling ptrace. -extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data) { - long result = 0; - errno = 0; - result = ptrace(req, pid, (caddr_t)addr, data); - return result; -} - -#define PTRACE(req, pid, addr, data) \ - PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__) - -// Static implementations of ProcessMonitor::ReadMemory and -// ProcessMonitor::WriteMemory. This enables mutual recursion between these -// functions without needed to go thru the thread funnel. - -static size_t DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf, - size_t size, Status &error) { - struct ptrace_io_desc pi_desc; - - pi_desc.piod_op = PIOD_READ_D; - pi_desc.piod_offs = (void *)vm_addr; - pi_desc.piod_addr = buf; - pi_desc.piod_len = size; - - if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) { - error.SetErrorToErrno(); - return 0; - } - return pi_desc.piod_len; -} - -static size_t DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, - const void *buf, size_t size, Status &error) { - struct ptrace_io_desc pi_desc; - - pi_desc.piod_op = PIOD_WRITE_D; - pi_desc.piod_offs = (void *)vm_addr; - pi_desc.piod_addr = const_cast<void *>(buf); - pi_desc.piod_len = size; - - if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) { - error.SetErrorToErrno(); - return 0; - } - return pi_desc.piod_len; -} - -// Simple helper function to ensure flags are enabled on the given file -// descriptor. -static bool EnsureFDFlags(int fd, int flags, Status &error) { - int status; - - if ((status = fcntl(fd, F_GETFL)) == -1) { - error.SetErrorToErrno(); - return false; - } - - if (fcntl(fd, F_SETFL, status | flags) == -1) { - error.SetErrorToErrno(); - return false; - } - - return true; -} - -/// \class Operation -/// Represents a ProcessMonitor operation. -/// -/// Under FreeBSD, it is not possible to ptrace() from any other thread but -/// the one that spawned or attached to the process from the start. -/// Therefore, when a ProcessMonitor is asked to deliver or change the state -/// of an inferior process the operation must be "funneled" to a specific -/// thread to perform the task. The Operation class provides an abstract base -/// for all services the ProcessMonitor must perform via the single virtual -/// function Execute, thus encapsulating the code that needs to run in the -/// privileged context. -class Operation { -public: - virtual ~Operation() {} - virtual void Execute(ProcessMonitor *monitor) = 0; -}; - -/// \class ReadOperation -/// Implements ProcessMonitor::ReadMemory. -class ReadOperation : public Operation { -public: - ReadOperation(lldb::addr_t addr, void *buff, size_t size, Status &error, - size_t &result) - : m_addr(addr), m_buff(buff), m_size(size), m_error(error), - m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::addr_t m_addr; - void *m_buff; - size_t m_size; - Status &m_error; - size_t &m_result; -}; - -void ReadOperation::Execute(ProcessMonitor *monitor) { - lldb::pid_t pid = monitor->GetPID(); - - m_result = DoReadMemory(pid, m_addr, m_buff, m_size, m_error); -} - -/// \class WriteOperation -/// Implements ProcessMonitor::WriteMemory. -class WriteOperation : public Operation { -public: - WriteOperation(lldb::addr_t addr, const void *buff, size_t size, - Status &error, size_t &result) - : m_addr(addr), m_buff(buff), m_size(size), m_error(error), - m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::addr_t m_addr; - const void *m_buff; - size_t m_size; - Status &m_error; - size_t &m_result; -}; - -void WriteOperation::Execute(ProcessMonitor *monitor) { - lldb::pid_t pid = monitor->GetPID(); - - m_result = DoWriteMemory(pid, m_addr, m_buff, m_size, m_error); -} - -/// \class ReadRegOperation -/// Implements ProcessMonitor::ReadRegisterValue. -class ReadRegOperation : public Operation { -public: - ReadRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, - RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), m_size(size), m_value(value), - m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - unsigned m_offset; - unsigned m_size; - RegisterValue &m_value; - bool &m_result; -}; - -void ReadRegOperation::Execute(ProcessMonitor *monitor) { - struct reg regs; - int rc; - - if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0)) < 0) { - m_result = false; - } else { - // 'struct reg' contains only 32- or 64-bit register values. Punt on - // others. Also, not all entries may be uintptr_t sized, such as 32-bit - // processes on powerpc64 (probably the same for i386 on amd64) - if (m_size == sizeof(uint32_t)) - m_value = *(uint32_t *)(((caddr_t)®s) + m_offset); - else if (m_size == sizeof(uint64_t)) - m_value = *(uint64_t *)(((caddr_t)®s) + m_offset); - else - memcpy((void *)&m_value, (((caddr_t)®s) + m_offset), m_size); - m_result = true; - } -} - -/// \class WriteRegOperation -/// Implements ProcessMonitor::WriteRegisterValue. -class WriteRegOperation : public Operation { -public: - WriteRegOperation(lldb::tid_t tid, unsigned offset, - const RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), m_value(value), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - unsigned m_offset; - const RegisterValue &m_value; - bool &m_result; -}; - -void WriteRegOperation::Execute(ProcessMonitor *monitor) { - struct reg regs; - - if (PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0) < 0) { - m_result = false; - return; - } - *(uintptr_t *)(((caddr_t)®s) + m_offset) = - (uintptr_t)m_value.GetAsUInt64(); - if (PTRACE(PT_SETREGS, m_tid, (caddr_t)®s, 0) < 0) - m_result = false; - else - m_result = true; -} - -/// \class ReadDebugRegOperation -/// Implements ProcessMonitor::ReadDebugRegisterValue. -class ReadDebugRegOperation : public Operation { -public: - ReadDebugRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, - RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), m_size(size), m_value(value), - m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - unsigned m_offset; - unsigned m_size; - RegisterValue &m_value; - bool &m_result; -}; - -void ReadDebugRegOperation::Execute(ProcessMonitor *monitor) { - struct dbreg regs; - int rc; - - if ((rc = PTRACE(PT_GETDBREGS, m_tid, (caddr_t)®s, 0)) < 0) { - m_result = false; - } else { - if (m_size == sizeof(uintptr_t)) - m_value = *(uintptr_t *)(((caddr_t)®s) + m_offset); - else - memcpy((void *)&m_value, (((caddr_t)®s) + m_offset), m_size); - m_result = true; - } -} - -/// \class WriteDebugRegOperation -/// Implements ProcessMonitor::WriteDebugRegisterValue. -class WriteDebugRegOperation : public Operation { -public: - WriteDebugRegOperation(lldb::tid_t tid, unsigned offset, - const RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), m_value(value), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - unsigned m_offset; - const RegisterValue &m_value; - bool &m_result; -}; - -void WriteDebugRegOperation::Execute(ProcessMonitor *monitor) { - struct dbreg regs; - - if (PTRACE(PT_GETDBREGS, m_tid, (caddr_t)®s, 0) < 0) { - m_result = false; - return; - } - *(uintptr_t *)(((caddr_t)®s) + m_offset) = - (uintptr_t)m_value.GetAsUInt64(); - if (PTRACE(PT_SETDBREGS, m_tid, (caddr_t)®s, 0) < 0) - m_result = false; - else - m_result = true; -} - -/// \class ReadGPROperation -/// Implements ProcessMonitor::ReadGPR. -class ReadGPROperation : public Operation { -public: - ReadGPROperation(lldb::tid_t tid, void *buf, bool &result) - : m_tid(tid), m_buf(buf), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - void *m_buf; - bool &m_result; -}; - -void ReadGPROperation::Execute(ProcessMonitor *monitor) { - int rc; - - errno = 0; - rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)m_buf, 0); - if (errno != 0) - m_result = false; - else - m_result = true; -} - -/// \class ReadFPROperation -/// Implements ProcessMonitor::ReadFPR. -class ReadFPROperation : public Operation { -public: - ReadFPROperation(lldb::tid_t tid, void *buf, bool &result) - : m_tid(tid), m_buf(buf), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - void *m_buf; - bool &m_result; -}; - -void ReadFPROperation::Execute(ProcessMonitor *monitor) { - if (PTRACE(PT_GETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0) - m_result = false; - else - m_result = true; -} - -/// \class WriteGPROperation -/// Implements ProcessMonitor::WriteGPR. -class WriteGPROperation : public Operation { -public: - WriteGPROperation(lldb::tid_t tid, void *buf, bool &result) - : m_tid(tid), m_buf(buf), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - void *m_buf; - bool &m_result; -}; - -void WriteGPROperation::Execute(ProcessMonitor *monitor) { - if (PTRACE(PT_SETREGS, m_tid, (caddr_t)m_buf, 0) < 0) - m_result = false; - else - m_result = true; -} - -/// \class WriteFPROperation -/// Implements ProcessMonitor::WriteFPR. -class WriteFPROperation : public Operation { -public: - WriteFPROperation(lldb::tid_t tid, void *buf, bool &result) - : m_tid(tid), m_buf(buf), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - void *m_buf; - bool &m_result; -}; - -void WriteFPROperation::Execute(ProcessMonitor *monitor) { - if (PTRACE(PT_SETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0) - m_result = false; - else - m_result = true; -} - -/// \class ResumeOperation -/// Implements ProcessMonitor::Resume. -class ResumeOperation : public Operation { -public: - ResumeOperation(uint32_t signo, bool &result) - : m_signo(signo), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - uint32_t m_signo; - bool &m_result; -}; - -void ResumeOperation::Execute(ProcessMonitor *monitor) { - lldb::pid_t pid = monitor->GetPID(); - int data = 0; - - if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) - data = m_signo; - - if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data)) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "ResumeOperation ({0}) failed: {1}", pid, - llvm::sys::StrError(errno)); - m_result = false; - } else - m_result = true; -} - -/// \class SingleStepOperation -/// Implements ProcessMonitor::SingleStep. -class SingleStepOperation : public Operation { -public: - SingleStepOperation(uint32_t signo, bool &result) - : m_signo(signo), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - uint32_t m_signo; - bool &m_result; -}; - -void SingleStepOperation::Execute(ProcessMonitor *monitor) { - lldb::pid_t pid = monitor->GetPID(); - int data = 0; - - if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) - data = m_signo; - - if (PTRACE(PT_STEP, pid, NULL, data)) - m_result = false; - else - m_result = true; -} - -/// \class LwpInfoOperation -/// Implements ProcessMonitor::GetLwpInfo. -class LwpInfoOperation : public Operation { -public: - LwpInfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err) - : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - void *m_info; - bool &m_result; - int &m_err; -}; - -void LwpInfoOperation::Execute(ProcessMonitor *monitor) { - struct ptrace_lwpinfo plwp; - - if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) { - m_result = false; - m_err = errno; - } else { - memcpy(m_info, &plwp, sizeof(plwp)); - m_result = true; - } -} - -/// \class ThreadSuspendOperation -/// Implements ProcessMonitor::ThreadSuspend. -class ThreadSuspendOperation : public Operation { -public: - ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result) - : m_tid(tid), m_suspend(suspend), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - bool m_suspend; - bool &m_result; -}; - -void ThreadSuspendOperation::Execute(ProcessMonitor *monitor) { - m_result = !PTRACE(m_suspend ? PT_SUSPEND : PT_RESUME, m_tid, NULL, 0); -} - -/// \class EventMessageOperation -/// Implements ProcessMonitor::GetEventMessage. -class EventMessageOperation : public Operation { -public: - EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result) - : m_tid(tid), m_message(message), m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - lldb::tid_t m_tid; - unsigned long *m_message; - bool &m_result; -}; - -void EventMessageOperation::Execute(ProcessMonitor *monitor) { - struct ptrace_lwpinfo plwp; - - if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) - m_result = false; - else { - if (plwp.pl_flags & PL_FLAG_FORKED) { - *m_message = plwp.pl_child_pid; - m_result = true; - } else - m_result = false; - } -} - -/// \class KillOperation -/// Implements ProcessMonitor::Kill. -class KillOperation : public Operation { -public: - KillOperation(bool &result) : m_result(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - bool &m_result; -}; - -void KillOperation::Execute(ProcessMonitor *monitor) { - lldb::pid_t pid = monitor->GetPID(); - - if (PTRACE(PT_KILL, pid, NULL, 0)) - m_result = false; - else - m_result = true; -} - -/// \class DetachOperation -/// Implements ProcessMonitor::Detach. -class DetachOperation : public Operation { -public: - DetachOperation(Status &result) : m_error(result) {} - - void Execute(ProcessMonitor *monitor); - -private: - Status &m_error; -}; - -void DetachOperation::Execute(ProcessMonitor *monitor) { - lldb::pid_t pid = monitor->GetPID(); - - if (PTRACE(PT_DETACH, pid, NULL, 0) < 0) - m_error.SetErrorToErrno(); -} - -ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor) - : m_monitor(monitor) { - sem_init(&m_semaphore, 0, 0); -} - -ProcessMonitor::OperationArgs::~OperationArgs() { sem_destroy(&m_semaphore); } - -ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor, - lldb_private::Module *module, - char const **argv, Environment env, - const FileSpec &stdin_file_spec, - const FileSpec &stdout_file_spec, - const FileSpec &stderr_file_spec, - const FileSpec &working_dir) - : OperationArgs(monitor), m_module(module), m_argv(argv), - m_env(std::move(env)), m_stdin_file_spec(stdin_file_spec), - m_stdout_file_spec(stdout_file_spec), - m_stderr_file_spec(stderr_file_spec), m_working_dir(working_dir) {} - -ProcessMonitor::LaunchArgs::~LaunchArgs() {} - -ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor, lldb::pid_t pid) - : OperationArgs(monitor), m_pid(pid) {} - -ProcessMonitor::AttachArgs::~AttachArgs() {} - -/// The basic design of the ProcessMonitor is built around two threads. -/// -/// One thread (@see SignalThread) simply blocks on a call to waitpid() -/// looking for changes in the debugee state. When a change is detected a -/// ProcessMessage is sent to the associated ProcessFreeBSD instance. This -/// thread "drives" state changes in the debugger. -/// -/// The second thread (@see OperationThread) is responsible for two things 1) -/// launching or attaching to the inferior process, and then 2) servicing -/// operations such as register reads/writes, stepping, etc. See the comments -/// on the Operation class for more info as to why this is needed. -ProcessMonitor::ProcessMonitor( - ProcessFreeBSD *process, Module *module, const char *argv[], - Environment env, const FileSpec &stdin_file_spec, - const FileSpec &stdout_file_spec, const FileSpec &stderr_file_spec, - const FileSpec &working_dir, - const lldb_private::ProcessLaunchInfo & /* launch_info */, - lldb_private::Status &error) - : m_process(static_cast<ProcessFreeBSD *>(process)), - m_operation_thread(), m_monitor_thread(), m_pid(LLDB_INVALID_PROCESS_ID), m_terminal_fd(-1), m_operation(0) { - using namespace std::placeholders; - - std::unique_ptr<LaunchArgs> args( - new LaunchArgs(this, module, argv, std::move(env), stdin_file_spec, - stdout_file_spec, stderr_file_spec, working_dir)); - - sem_init(&m_operation_pending, 0, 0); - sem_init(&m_operation_done, 0, 0); - - StartLaunchOpThread(args.get(), error); - if (!error.Success()) - return; - - if (llvm::sys::RetryAfterSignal(-1, sem_wait, &args->m_semaphore) == -1) { - error.SetErrorToErrno(); - return; - } - - // Check that the launch was a success. - if (!args->m_error.Success()) { - StopOpThread(); - error = args->m_error; - return; - } - - // Finally, start monitoring the child process for change in state. - llvm::Expected<lldb_private::HostThread> monitor_thread = - Host::StartMonitoringChildProcess( - std::bind(&ProcessMonitor::MonitorCallback, this, _1, _2, _3, _4), - GetPID(), true); - if (!monitor_thread || !monitor_thread->IsJoinable()) { - error.SetErrorToGenericError(); - error.SetErrorString("Process launch failed."); - return; - } - m_monitor_thread = *monitor_thread; -} - -ProcessMonitor::ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid, - lldb_private::Status &error) - : m_process(static_cast<ProcessFreeBSD *>(process)), - m_operation_thread(), m_monitor_thread(), m_pid(pid), m_terminal_fd(-1), m_operation(0) { - using namespace std::placeholders; - - sem_init(&m_operation_pending, 0, 0); - sem_init(&m_operation_done, 0, 0); - - std::unique_ptr<AttachArgs> args(new AttachArgs(this, pid)); - - StartAttachOpThread(args.get(), error); - if (!error.Success()) - return; - - if (llvm::sys::RetryAfterSignal(-1, sem_wait, &args->m_semaphore) == -1) { - error.SetErrorToErrno(); - return; - } - - // Check that the attach was a success. - if (!args->m_error.Success()) { - StopOpThread(); - error = args->m_error; - return; - } - - // Finally, start monitoring the child process for change in state. - llvm::Expected<lldb_private::HostThread> monitor_thread = - Host::StartMonitoringChildProcess( - std::bind(&ProcessMonitor::MonitorCallback, this, _1, _2, _3, _4), - GetPID(), true); - if (!monitor_thread || !monitor_thread->IsJoinable()) { - error.SetErrorToGenericError(); - error.SetErrorString("Process attach failed."); - return; - } - m_monitor_thread = *monitor_thread; -} - -ProcessMonitor::~ProcessMonitor() { StopMonitor(); } - -// Thread setup and tear down. -void ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Status &error) { - static const char *g_thread_name = "freebsd.op"; - - if (m_operation_thread && m_operation_thread->IsJoinable()) - return; - - llvm::Expected<lldb_private::HostThread> operation_thread = - ThreadLauncher::LaunchThread(g_thread_name, LaunchOpThread, args); - if (operation_thread) - m_operation_thread = *operation_thread; - else - error = operation_thread.takeError(); -} - -void *ProcessMonitor::LaunchOpThread(void *arg) { - LaunchArgs *args = static_cast<LaunchArgs *>(arg); - - if (!Launch(args)) { - sem_post(&args->m_semaphore); - return NULL; - } - - ServeOperation(args); - return NULL; -} - -bool ProcessMonitor::Launch(LaunchArgs *args) { - ProcessMonitor *monitor = args->m_monitor; - ProcessFreeBSD &process = monitor->GetProcess(); - const char **argv = args->m_argv; - const FileSpec &stdin_file_spec = args->m_stdin_file_spec; - const FileSpec &stdout_file_spec = args->m_stdout_file_spec; - const FileSpec &stderr_file_spec = args->m_stderr_file_spec; - const FileSpec &working_dir = args->m_working_dir; - - PseudoTerminal terminal; - const size_t err_len = 1024; - char err_str[err_len]; - ::pid_t pid; - - // Propagate the environment if one is not supplied. - Environment::Envp envp = - (args->m_env.empty() ? Host::GetEnvironment() : args->m_env).getEnvp(); - - if ((pid = terminal.Fork(err_str, err_len)) == -1) { - args->m_error.SetErrorToGenericError(); - args->m_error.SetErrorString("Process fork failed."); - goto FINISH; - } - - // Recognized child exit status codes. - enum { - ePtraceFailed = 1, - eDupStdinFailed, - eDupStdoutFailed, - eDupStderrFailed, - eChdirFailed, - eExecFailed, - eSetGidFailed - }; - - // Child process. - if (pid == 0) { - // Trace this process. - if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0) - exit(ePtraceFailed); - - // terminal has already dupped the tty descriptors to stdin/out/err. This - // closes original fd from which they were copied (and avoids leaking - // descriptors to the debugged process. - terminal.CloseSecondaryFileDescriptor(); - - // Do not inherit setgid powers. - if (setgid(getgid()) != 0) - exit(eSetGidFailed); - - // Let us have our own process group. - setpgid(0, 0); - - // Dup file descriptors if needed. - // - // FIXME: If two or more of the paths are the same we needlessly open - // the same file multiple times. - if (stdin_file_spec) - if (!DupDescriptor(stdin_file_spec, STDIN_FILENO, O_RDONLY)) - exit(eDupStdinFailed); - - if (stdout_file_spec) - if (!DupDescriptor(stdout_file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT)) - exit(eDupStdoutFailed); - - if (stderr_file_spec) - if (!DupDescriptor(stderr_file_spec, STDERR_FILENO, O_WRONLY | O_CREAT)) - exit(eDupStderrFailed); - - // Change working directory - if (working_dir && 0 != ::chdir(working_dir.GetCString())) - exit(eChdirFailed); - - // Execute. We should never return. - execve(argv[0], const_cast<char *const *>(argv), envp); - exit(eExecFailed); - } - - // Wait for the child process to to trap on its call to execve. - ::pid_t wpid; - int status; - if ((wpid = waitpid(pid, &status, 0)) < 0) { - args->m_error.SetErrorToErrno(); - goto FINISH; - } else if (WIFEXITED(status)) { - // open, dup or execve likely failed for some reason. - args->m_error.SetErrorToGenericError(); - switch (WEXITSTATUS(status)) { - case ePtraceFailed: - args->m_error.SetErrorString("Child ptrace failed."); - break; - case eDupStdinFailed: - args->m_error.SetErrorString("Child open stdin failed."); - break; - case eDupStdoutFailed: - args->m_error.SetErrorString("Child open stdout failed."); - break; - case eDupStderrFailed: - args->m_error.SetErrorString("Child open stderr failed."); - break; - case eChdirFailed: - args->m_error.SetErrorString("Child failed to set working directory."); - break; - case eExecFailed: - args->m_error.SetErrorString("Child exec failed."); - break; - case eSetGidFailed: - args->m_error.SetErrorString("Child setgid failed."); - break; - default: - args->m_error.SetErrorString("Child returned unknown exit status."); - break; - } - goto FINISH; - } - assert(WIFSTOPPED(status) && wpid == (::pid_t)pid && - "Could not sync with inferior process."); - -#ifdef notyet - // Have the child raise an event on exit. This is used to keep the child in - // limbo until it is destroyed. - if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0) { - args->m_error.SetErrorToErrno(); - goto FINISH; - } -#endif - // Release the master terminal descriptor and pass it off to the - // ProcessMonitor instance. Similarly stash the inferior pid. - monitor->m_terminal_fd = terminal.ReleasePrimaryFileDescriptor(); - monitor->m_pid = pid; - - // Set the terminal fd to be in non blocking mode (it simplifies the - // implementation of ProcessFreeBSD::GetSTDOUT to have a non-blocking - // descriptor to read from). - if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error)) - goto FINISH; - - process.SendMessage(ProcessMessage::Attach(pid)); - -FINISH: - return args->m_error.Success(); -} - -void ProcessMonitor::StartAttachOpThread(AttachArgs *args, - lldb_private::Status &error) { - static const char *g_thread_name = "freebsd.op"; - - if (m_operation_thread && m_operation_thread->IsJoinable()) - return; - - llvm::Expected<lldb_private::HostThread> operation_thread = - ThreadLauncher::LaunchThread(g_thread_name, AttachOpThread, args); - if (operation_thread) - m_operation_thread = *operation_thread; - else - error = operation_thread.takeError(); -} - -void *ProcessMonitor::AttachOpThread(void *arg) { - AttachArgs *args = static_cast<AttachArgs *>(arg); - - Attach(args); - - ServeOperation(args); - return NULL; -} - -void ProcessMonitor::Attach(AttachArgs *args) { - lldb::pid_t pid = args->m_pid; - - ProcessMonitor *monitor = args->m_monitor; - ProcessFreeBSD &process = monitor->GetProcess(); - - if (pid <= 1) { - args->m_error.SetErrorToGenericError(); - args->m_error.SetErrorString("Attaching to process 1 is not allowed."); - return; - } - - // Attach to the requested process. - if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0) { - args->m_error.SetErrorToErrno(); - return; - } - - int status; - if ((status = waitpid(pid, NULL, 0)) < 0) { - args->m_error.SetErrorToErrno(); - return; - } - - process.SendMessage(ProcessMessage::Attach(pid)); -} - -size_t -ProcessMonitor::GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids) { - lwpid_t *tids; - int tdcnt; - - thread_ids.clear(); - - tdcnt = PTRACE(PT_GETNUMLWPS, m_pid, NULL, 0); - if (tdcnt <= 0) - return 0; - tids = (lwpid_t *)malloc(tdcnt * sizeof(*tids)); - if (tids == NULL) - return 0; - if (PTRACE(PT_GETLWPLIST, m_pid, (void *)tids, tdcnt) < 0) { - free(tids); - return 0; - } - thread_ids = std::vector<lldb::tid_t>(tids, tids + tdcnt); - free(tids); - return thread_ids.size(); -} - -bool ProcessMonitor::MonitorCallback(ProcessMonitor *monitor, lldb::pid_t pid, - bool exited, int signal, int status) { - ProcessMessage message; - ProcessFreeBSD *process = monitor->m_process; - assert(process); - bool stop_monitoring; - struct ptrace_lwpinfo plwp; - int ptrace_err; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - if (exited) { - LLDB_LOGF(log, "ProcessMonitor::%s() got exit signal, tid = %" PRIu64, - __FUNCTION__, pid); - message = ProcessMessage::Exit(pid, status); - process->SendMessage(message); - return pid == process->GetID(); - } - - if (!monitor->GetLwpInfo(pid, &plwp, ptrace_err)) - stop_monitoring = true; // pid is gone. Bail. - else { - switch (plwp.pl_siginfo.si_signo) { - case SIGTRAP: - message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, plwp.pl_lwpid); - break; - - default: - message = MonitorSignal(monitor, &plwp.pl_siginfo, plwp.pl_lwpid); - break; - } - - process->SendMessage(message); - stop_monitoring = message.GetKind() == ProcessMessage::eExitMessage; - } - - return stop_monitoring; -} - -ProcessMessage ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, - const siginfo_t *info, - lldb::tid_t tid) { - ProcessMessage message; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - assert(monitor); - assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!"); - - switch (info->si_code) { - default: - assert(false && "Unexpected SIGTRAP code!"); - break; - - case (SIGTRAP /* | (PTRACE_EVENT_EXIT << 8) */): { - // The inferior process is about to exit. Maintain the process in a state - // of "limbo" until we are explicitly commanded to detach, destroy, resume, - // etc. - unsigned long data = 0; - if (!monitor->GetEventMessage(tid, &data)) - data = -1; - LLDB_LOGF(log, - "ProcessMonitor::%s() received exit? event, data = %lx, tid " - "= %" PRIu64, - __FUNCTION__, data, tid); - message = ProcessMessage::Limbo(tid, (data >> 8)); - break; - } - - case 0: - case TRAP_TRACE: -#ifdef TRAP_CAP - // Map TRAP_CAP to a trace trap in the absense of a more specific handler. - case TRAP_CAP: -#endif - LLDB_LOGF(log, - "ProcessMonitor::%s() received trace event, tid = %" PRIu64 - " : si_code = %d", - __FUNCTION__, tid, info->si_code); - message = ProcessMessage::Trace(tid); - break; - - case SI_KERNEL: - case TRAP_BRKPT: - if (monitor->m_process->IsSoftwareStepBreakpoint(tid)) { - LLDB_LOGF(log, - "ProcessMonitor::%s() received sw single step breakpoint " - "event, tid = %" PRIu64, - __FUNCTION__, tid); - message = ProcessMessage::Trace(tid); - } else { - LLDB_LOGF( - log, "ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64, - __FUNCTION__, tid); - message = ProcessMessage::Break(tid); - } - break; - } - - return message; -} - -ProcessMessage ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, - const siginfo_t *info, - lldb::tid_t tid) { - ProcessMessage message; - int signo = info->si_signo; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - // POSIX says that process behaviour is undefined after it ignores a SIGFPE, - // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2) - // or raise(3). Similarly for tgkill(2) on FreeBSD. - // - // IOW, user generated signals never generate what we consider to be a - // "crash". - // - // Similarly, ACK signals generated by this monitor. - if (info->si_code == SI_USER) { - LLDB_LOGF(log, - "ProcessMonitor::%s() received signal %s with code %s, pid = %d", - __FUNCTION__, - monitor->m_process->GetUnixSignals()->GetSignalAsCString(signo), - "SI_USER", info->si_pid); - if (info->si_pid == getpid()) - return ProcessMessage::SignalDelivered(tid, signo); - else - return ProcessMessage::Signal(tid, signo); - } - - LLDB_LOGF(log, "ProcessMonitor::%s() received signal %s", __FUNCTION__, - monitor->m_process->GetUnixSignals()->GetSignalAsCString(signo)); - - switch (signo) { - case SIGSEGV: - case SIGILL: - case SIGFPE: - case SIGBUS: - lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr); - const auto reason = GetCrashReason(*info); - if (reason != CrashReason::eInvalidCrashReason) { - return ProcessMessage::Crash(tid, reason, signo, fault_addr); - } // else; Use atleast si_signo info for other si_code - } - - // Everything else is "normal" and does not require any special action on our - // part. - return ProcessMessage::Signal(tid, signo); -} - -void ProcessMonitor::ServeOperation(OperationArgs *args) { - ProcessMonitor *monitor = args->m_monitor; - - // We are finised with the arguments and are ready to go. Sync with the - // parent thread and start serving operations on the inferior. - sem_post(&args->m_semaphore); - - for (;;) { - // wait for next pending operation - sem_wait(&monitor->m_operation_pending); - - monitor->m_operation->Execute(monitor); - - // notify calling thread that operation is complete - sem_post(&monitor->m_operation_done); - } -} - -void ProcessMonitor::DoOperation(Operation *op) { - std::lock_guard<std::mutex> guard(m_operation_mutex); - - m_operation = op; - - // notify operation thread that an operation is ready to be processed - sem_post(&m_operation_pending); - - // wait for operation to complete - sem_wait(&m_operation_done); -} - -size_t ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - Status &error) { - size_t result; - ReadOperation op(vm_addr, buf, size, error, result); - DoOperation(&op); - return result; -} - -size_t ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, - size_t size, lldb_private::Status &error) { - size_t result; - WriteOperation op(vm_addr, buf, size, error, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::ReadRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, unsigned size, - RegisterValue &value) { - bool result; - ReadRegOperation op(tid, offset, size, value, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, - const RegisterValue &value) { - bool result; - WriteRegOperation op(tid, offset, value, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::ReadDebugRegisterValue( - lldb::tid_t tid, unsigned offset, const char *reg_name, unsigned size, - lldb_private::RegisterValue &value) { - bool result; - ReadDebugRegOperation op(tid, offset, size, value, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::WriteDebugRegisterValue( - lldb::tid_t tid, unsigned offset, const char *reg_name, - const lldb_private::RegisterValue &value) { - bool result; - WriteDebugRegOperation op(tid, offset, value, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size) { - bool result; - ReadGPROperation op(tid, buf, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size) { - bool result; - ReadFPROperation op(tid, buf, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, - size_t buf_size, unsigned int regset) { - return false; -} - -bool ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size) { - bool result; - WriteGPROperation op(tid, buf, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size) { - bool result; - WriteFPROperation op(tid, buf, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, - size_t buf_size, unsigned int regset) { - return false; -} - -bool ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) { - return false; -} - -bool ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo) { - bool result; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - if (log) { - const char *signame = - m_process->GetUnixSignals()->GetSignalAsCString(signo); - if (signame == nullptr) - signame = "<none>"; - LLDB_LOGF(log, - "ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", - __FUNCTION__, GetPID(), signame); - } - ResumeOperation op(signo, result); - DoOperation(&op); - LLDB_LOGF(log, "ProcessMonitor::%s() resuming result = %s", __FUNCTION__, - result ? "true" : "false"); - return result; -} - -bool ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo) { - bool result; - SingleStepOperation op(signo, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::Kill() { - bool result; - KillOperation op(result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, - int &ptrace_err) { - bool result; - LwpInfoOperation op(tid, lwpinfo, result, ptrace_err); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::ThreadSuspend(lldb::tid_t tid, bool suspend) { - bool result; - ThreadSuspendOperation op(tid, suspend, result); - DoOperation(&op); - return result; -} - -bool ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message) { - bool result; - EventMessageOperation op(tid, message, result); - DoOperation(&op); - return result; -} - -lldb_private::Status ProcessMonitor::Detach(lldb::tid_t tid) { - lldb_private::Status error; - if (tid != LLDB_INVALID_THREAD_ID) { - DetachOperation op(error); - DoOperation(&op); - } - return error; -} - -bool ProcessMonitor::DupDescriptor(const FileSpec &file_spec, int fd, - int flags) { - int target_fd = llvm::sys::RetryAfterSignal(-1, open, - file_spec.GetCString(), flags, 0666); - - if (target_fd == -1) - return false; - - if (dup2(target_fd, fd) == -1) - return false; - - return (close(target_fd) == -1) ? false : true; -} - -void ProcessMonitor::StopMonitoringChildProcess() { - if (m_monitor_thread && m_monitor_thread->IsJoinable()) { - m_monitor_thread->Cancel(); - m_monitor_thread->Join(nullptr); - m_monitor_thread->Reset(); - } -} - -void ProcessMonitor::StopMonitor() { - StopMonitoringChildProcess(); - StopOpThread(); - sem_destroy(&m_operation_pending); - sem_destroy(&m_operation_done); - if (m_terminal_fd >= 0) { - close(m_terminal_fd); - m_terminal_fd = -1; - } -} - -// FIXME: On Linux, when a new thread is created, we receive to notifications, -// (1) a SIGTRAP|PTRACE_EVENT_CLONE from the main process thread with the child -// thread id as additional information, and (2) a SIGSTOP|SI_USER from the new -// child thread indicating that it has is stopped because we attached. We have -// no guarantee of the order in which these arrive, but we need both before we -// are ready to proceed. We currently keep a list of threads which have sent -// the initial SIGSTOP|SI_USER event. Then when we receive the -// SIGTRAP|PTRACE_EVENT_CLONE notification, if the initial stop has not -// occurred we call ProcessMonitor::WaitForInitialTIDStop() to wait for it. -// -// Right now, the above logic is in ProcessPOSIX, so we need a definition of -// this function in the FreeBSD ProcessMonitor implementation even if it isn't -// logically needed. -// -// We really should figure out what actually happens on FreeBSD and move the -// Linux-specific logic out of ProcessPOSIX as needed. - -bool ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid) { return true; } - -void ProcessMonitor::StopOpThread() { - if (m_operation_thread && m_operation_thread->IsJoinable()) { - m_operation_thread->Cancel(); - m_operation_thread->Join(nullptr); - m_operation_thread->Reset(); - } -} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h deleted file mode 100644 index c5edfc0be95a..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ /dev/null @@ -1,279 +0,0 @@ -//===-- ProcessMonitor.h -------------------------------------- -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessMonitor_H_ -#define liblldb_ProcessMonitor_H_ - -#include <semaphore.h> -#include <signal.h> - -#include <mutex> - -#include "lldb/Host/HostThread.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/lldb-types.h" - -namespace lldb_private { -class Status; -class Module; -class Scalar; -} // End lldb_private namespace. - -class ProcessFreeBSD; -class Operation; - -/// \class ProcessMonitor -/// Manages communication with the inferior (debugee) process. -/// -/// Upon construction, this class prepares and launches an inferior process -/// for debugging. -/// -/// Changes in the inferior process state are propagated to the associated -/// ProcessFreeBSD instance by calling ProcessFreeBSD::SendMessage with the -/// appropriate ProcessMessage events. -/// -/// A purposely minimal set of operations are provided to interrogate and change -/// the inferior process state. -class ProcessMonitor { -public: - /// Launches an inferior process ready for debugging. Forms the - /// implementation of Process::DoLaunch. - ProcessMonitor(ProcessFreeBSD *process, lldb_private::Module *module, - char const *argv[], lldb_private::Environment env, - const lldb_private::FileSpec &stdin_file_spec, - const lldb_private::FileSpec &stdout_file_spec, - const lldb_private::FileSpec &stderr_file_spec, - const lldb_private::FileSpec &working_dir, - const lldb_private::ProcessLaunchInfo &launch_info, - lldb_private::Status &error); - - ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid, - lldb_private::Status &error); - - ~ProcessMonitor(); - - /// Provides the process number of debugee. - lldb::pid_t GetPID() const { return m_pid; } - - /// Returns the process associated with this ProcessMonitor. - ProcessFreeBSD &GetProcess() { return *m_process; } - - /// Returns a file descriptor to the controlling terminal of the inferior - /// process. - /// - /// Reads from this file descriptor yield both the standard output and - /// standard error of this debugee. Even if stderr and stdout were - /// redirected on launch it may still happen that data is available on this - /// descriptor (if the inferior process opens /dev/tty, for example). This - /// descriptor is closed after a call to StopMonitor(). - /// - /// If this monitor was attached to an existing process this method returns - /// -1. - int GetTerminalFD() const { return m_terminal_fd; } - - /// Reads \p size bytes from address @vm_adder in the inferior process - /// address space. - /// - /// This method is provided to implement Process::DoReadMemory. - size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - lldb_private::Status &error); - - /// Writes \p size bytes from address \p vm_adder in the inferior process - /// address space. - /// - /// This method is provided to implement Process::DoWriteMemory. - size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Status &error); - - /// Reads the contents from the register identified by the given - /// (architecture dependent) offset. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, - unsigned size, lldb_private::RegisterValue &value); - - /// Writes the given value to the register identified by the given - /// (architecture dependent) offset. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool WriteRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, - const lldb_private::RegisterValue &value); - - /// Reads the contents from the debug register identified by the given - /// (architecture dependent) offset. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, unsigned size, - lldb_private::RegisterValue &value); - - /// Writes the given value to the debug register identified by the given - /// (architecture dependent) offset. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, - const lldb_private::RegisterValue &value); - /// Reads all general purpose registers into the specified buffer. - bool ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Reads all floating point registers into the specified buffer. - bool ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Reads the specified register set into the specified buffer. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, - unsigned int regset); - - /// Writes all general purpose registers into the specified buffer. - bool WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Writes all floating point registers into the specified buffer. - bool WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Writes the specified register set into the specified buffer. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, - unsigned int regset); - - /// Reads the value of the thread-specific pointer for a given thread ID. - bool ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value); - - /// Returns current thread IDs in process - size_t GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids); - - /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID - /// to the memory region pointed to by \p lwpinfo. - bool GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no); - - /// Suspends or unsuspends a thread prior to process resume or step. - bool ThreadSuspend(lldb::tid_t tid, bool suspend); - - /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) - /// corresponding to the given thread IDto the memory pointed to by @p - /// message. - bool GetEventMessage(lldb::tid_t tid, unsigned long *message); - - /// Resumes the process. If \p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. - bool Resume(lldb::tid_t unused, uint32_t signo); - - /// Single steps the process. If \p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. - bool SingleStep(lldb::tid_t unused, uint32_t signo); - - /// Terminate the traced process. - bool Kill(); - - lldb_private::Status Detach(lldb::tid_t tid); - - void StopMonitor(); - - // Waits for the initial stop message from a new thread. - bool WaitForInitialTIDStop(lldb::tid_t tid); - -private: - ProcessFreeBSD *m_process; - - llvm::Optional<lldb_private::HostThread> m_operation_thread; - llvm::Optional<lldb_private::HostThread> m_monitor_thread; - lldb::pid_t m_pid; - - int m_terminal_fd; - - // current operation which must be executed on the privileged thread - Operation *m_operation; - std::mutex m_operation_mutex; - - // semaphores notified when Operation is ready to be processed and when - // the operation is complete. - sem_t m_operation_pending; - sem_t m_operation_done; - - struct OperationArgs { - OperationArgs(ProcessMonitor *monitor); - - ~OperationArgs(); - - ProcessMonitor *m_monitor; // The monitor performing the attach. - sem_t m_semaphore; // Posted to once operation complete. - lldb_private::Status m_error; // Set if process operation failed. - }; - - /// \class LauchArgs - /// - /// Simple structure to pass data to the thread responsible for launching a - /// child process. - struct LaunchArgs : OperationArgs { - LaunchArgs(ProcessMonitor *monitor, lldb_private::Module *module, - char const **argv, lldb_private::Environment env, - const lldb_private::FileSpec &stdin_file_spec, - const lldb_private::FileSpec &stdout_file_spec, - const lldb_private::FileSpec &stderr_file_spec, - const lldb_private::FileSpec &working_dir); - - ~LaunchArgs(); - - lldb_private::Module *m_module; // The executable image to launch. - char const **m_argv; // Process arguments. - lldb_private::Environment m_env; // Process environment. - const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty. - const lldb_private::FileSpec - m_stdout_file_spec; // Redirect stdout or empty. - const lldb_private::FileSpec - m_stderr_file_spec; // Redirect stderr or empty. - const lldb_private::FileSpec m_working_dir; // Working directory or empty. - }; - - void StartLaunchOpThread(LaunchArgs *args, lldb_private::Status &error); - - static void *LaunchOpThread(void *arg); - - static bool Launch(LaunchArgs *args); - - struct AttachArgs : OperationArgs { - AttachArgs(ProcessMonitor *monitor, lldb::pid_t pid); - - ~AttachArgs(); - - lldb::pid_t m_pid; // pid of the process to be attached. - }; - - void StartAttachOpThread(AttachArgs *args, lldb_private::Status &error); - - static void *AttachOpThread(void *args); - - static void Attach(AttachArgs *args); - - static void ServeOperation(OperationArgs *args); - - static bool DupDescriptor(const lldb_private::FileSpec &file_spec, int fd, - int flags); - - static bool MonitorCallback(ProcessMonitor *monitor, lldb::pid_t pid, - bool exited, int signal, int status); - - static ProcessMessage MonitorSIGTRAP(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid); - - static ProcessMessage MonitorSignal(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid); - - void DoOperation(Operation *op); - - /// Stops the child monitor thread. - void StopMonitoringChildProcess(); - - /// Stops the operation thread used to attach/launch a process. - void StopOpThread(); -}; - -#endif // #ifndef liblldb_ProcessMonitor_H_ diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h deleted file mode 100644 index cf52a065232c..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h +++ /dev/null @@ -1,63 +0,0 @@ -//===-- RegisterContextPOSIX.h --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIX_H_ -#define liblldb_RegisterContextPOSIX_H_ - -#include "Plugins/Process/Utility/RegisterInfoInterface.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Utility/ArchSpec.h" - -/// \class POSIXBreakpointProtocol -/// -/// Extends RegisterClass with a few virtual operations useful on POSIX. -class POSIXBreakpointProtocol { -public: - POSIXBreakpointProtocol() { m_watchpoints_initialized = false; } - virtual ~POSIXBreakpointProtocol() {} - - /// Updates the register state of the associated thread after hitting a - /// breakpoint (if that make sense for the architecture). Default - /// implementation simply returns true for architectures which do not - /// require any update. - /// - /// \return - /// True if the operation succeeded and false otherwise. - virtual bool UpdateAfterBreakpoint() = 0; - - /// Determines the index in lldb's register file given a kernel byte offset. - virtual unsigned GetRegisterIndexFromOffset(unsigned offset) = 0; - - // Checks to see if a watchpoint specified by hw_index caused the inferior - // to stop. - virtual bool IsWatchpointHit(uint32_t hw_index) = 0; - - // Resets any watchpoints that have been hit. - virtual bool ClearWatchpointHits() = 0; - - // Returns the watchpoint address associated with a watchpoint hardware - // index. - virtual lldb::addr_t GetWatchpointAddress(uint32_t hw_index) = 0; - - virtual bool IsWatchpointVacant(uint32_t hw_index) = 0; - - virtual bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) = 0; - - // From lldb_private::RegisterContext - virtual uint32_t NumSupportedHardwareWatchpoints() = 0; - - // Force m_watchpoints_initialized to TRUE - void ForceWatchpointsInitialized() { m_watchpoints_initialized = true; } - -protected: - bool m_watchpoints_initialized; -}; - -#endif // #ifndef liblldb_RegisterContextPOSIX_H_ diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp deleted file mode 100644 index 4216f68faf5c..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp +++ /dev/null @@ -1,259 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm.cpp ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===---------------------------------------------------------------------===// - -#include "lldb/Target/Thread.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/RegisterValue.h" - -#include "ProcessFreeBSD.h" -#include "ProcessMonitor.h" -#include "RegisterContextPOSIXProcessMonitor_arm.h" -#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" - -using namespace lldb_private; -using namespace lldb; - -#define REG_CONTEXT_SIZE (GetGPRSize()) - -RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm( - Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info) {} - -ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm::GetMonitor() { - ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); - return process->GetMonitor(); -} - -bool RegisterContextPOSIXProcessMonitor_arm::ReadGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_arm::ReadFPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); -} - -bool RegisterContextPOSIXProcessMonitor_arm::WriteGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_arm::WriteFPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); -} - -bool RegisterContextPOSIXProcessMonitor_arm::ReadRegister( - const unsigned reg, RegisterValue &value) { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), - GetRegisterName(reg), GetRegisterSize(reg), - value); -} - -bool RegisterContextPOSIXProcessMonitor_arm::WriteRegister( - const unsigned reg, const RegisterValue &value) { - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) { - Status error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData( - full_reg_info, dst, sizeof(dst), byte_order, error); - if (error.Success() && dest_size) { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData( - reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) { - // Copy the src bytes to the destination. - memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue( - m_thread.GetID(), GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), value_to_write); -} - -bool RegisterContextPOSIXProcessMonitor_arm::ReadRegister( - const RegisterInfo *reg_info, RegisterValue &value) { - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg)) { - if (!ReadFPR()) - return false; - } else { - return ReadRegister(reg, value); - } - - // Get pointer to m_fpr variable and set the data from it. - assert(reg_info->byte_offset < sizeof m_fpr); - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; - switch (reg_info->byte_size) { - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; - } -} - -bool RegisterContextPOSIXProcessMonitor_arm::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue &value) { - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) { - return WriteRegister(reg, value); - } else if (IsFPR(reg)) { - return WriteFPR(); - } - - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues( - DataBufferSP &data_sp) { - bool success = false; - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (ReadGPR() && ReadFPR()) { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) { - ::memcpy(dst, &m_gpr_arm, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy(dst, &m_fpr, sizeof(m_fpr)); - } - } - return success; -} - -bool RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues( - const DataBufferSP &data_sp) { - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { - uint8_t *src = data_sp->GetBytes(); - if (src) { - ::memcpy(&m_gpr_arm, src, GetGPRSize()); - - if (WriteGPR()) { - src += GetGPRSize(); - ::memcpy(&m_fpr, src, sizeof(m_fpr)); - - success = WriteFPR(); - } - } - } - return success; -} - -uint32_t RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint( - addr_t addr, size_t size, bool read, bool write) { - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint() { - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - return true; -} - -unsigned RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset( - unsigned offset) { - unsigned reg; - for (reg = 0; reg < k_num_registers_arm; reg++) { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_arm && "Invalid register offset."); - return reg; -} - -bool RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits() { - return false; -} - -addr_t RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress( - uint32_t hw_index) { - return LLDB_INVALID_ADDRESS; -} - -bool RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex( - addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints() { - return 0; -} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h deleted file mode 100644 index b376967df99c..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h +++ /dev/null @@ -1,76 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm.h --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" -#include "RegisterContextPOSIX.h" - -class RegisterContextPOSIXProcessMonitor_arm : public RegisterContextPOSIX_arm, - public POSIXBreakpointProtocol { -public: - RegisterContextPOSIXProcessMonitor_arm( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool ReadGPR(); - - bool ReadFPR(); - - bool WriteGPR(); - - bool WriteFPR(); - - // lldb_private::RegisterContext - bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool WriteRegister(const unsigned reg, - const lldb_private::RegisterValue &value); - - bool ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value); - - bool WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value); - - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, - bool write); - - bool ClearHardwareWatchpoint(uint32_t hw_index); - - bool HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool UpdateAfterBreakpoint(); - - unsigned GetRegisterIndexFromOffset(unsigned offset); - - bool IsWatchpointHit(uint32_t hw_index); - - bool ClearWatchpointHits(); - - lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - - bool IsWatchpointVacant(uint32_t hw_index); - - bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, - bool write, uint32_t hw_index); - - uint32_t NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor &GetMonitor(); -}; - -#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp deleted file mode 100644 index d3eafae1e6de..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp +++ /dev/null @@ -1,264 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm64.cpp ----------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===---------------------------------------------------------------------===// - -#include "lldb/Target/Thread.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/RegisterValue.h" - -#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" -#include "ProcessFreeBSD.h" -#include "ProcessMonitor.h" -#include "RegisterContextPOSIXProcessMonitor_arm64.h" - -#define REG_CONTEXT_SIZE (GetGPRSize()) - -using namespace lldb; -using namespace lldb_private; - -RegisterContextPOSIXProcessMonitor_arm64:: - RegisterContextPOSIXProcessMonitor_arm64( - lldb_private::Thread &thread, - std::unique_ptr<RegisterInfoPOSIX_arm64> register_info) - : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {} - -ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() { - lldb::ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); - return process->GetMonitor(); -} - -bool RegisterContextPOSIXProcessMonitor_arm64::ReadGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_arm64::ReadFPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); -} - -bool RegisterContextPOSIXProcessMonitor_arm64::WriteGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_arm64::WriteFPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); -} - -bool RegisterContextPOSIXProcessMonitor_arm64::ReadRegister( - const unsigned reg, lldb_private::RegisterValue &value) { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), - GetRegisterName(reg), GetRegisterSize(reg), - value); -} - -bool RegisterContextPOSIXProcessMonitor_arm64::WriteRegister( - const unsigned reg, const lldb_private::RegisterValue &value) { - unsigned reg_to_write = reg; - lldb_private::RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { - lldb_private::RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const lldb_private::RegisterInfo *full_reg_info = - GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) { - lldb_private::Status error; - lldb::ByteOrder byte_order = GetByteOrder(); - uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData( - full_reg_info, dst, sizeof(dst), byte_order, error); - if (error.Success() && dest_size) { - uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData( - reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) { - // Copy the src bytes to the destination. - ::memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue( - m_thread.GetID(), GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), value_to_write); -} - -bool RegisterContextPOSIXProcessMonitor_arm64::ReadRegister( - const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value) { - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (IsFPR(reg)) { - if (!ReadFPR()) - return false; - } else { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - return ReadRegister(full_reg, value); - } - - // Get pointer to m_fpr variable and set the data from it. - assert(reg_info->byte_offset < sizeof m_fpr); - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; - switch (reg_info->byte_size) { - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; - } -} - -bool RegisterContextPOSIXProcessMonitor_arm64::WriteRegister( - const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value) { - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (IsGPR(reg)) - return WriteRegister(reg, value); - - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - bool success = false; - data_sp.reset(new lldb_private::DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (ReadGPR() && ReadFPR()) { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) { - ::memcpy(dst, &m_gpr_arm64, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy(dst, &m_fpr, sizeof m_fpr); - } - } - return success; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { - uint8_t *src = data_sp->GetBytes(); - if (src) { - ::memcpy(&m_gpr_arm64, src, GetGPRSize()); - if (WriteGPR()) { - src += GetGPRSize(); - ::memcpy(&m_fpr, src, sizeof m_fpr); - success = WriteFPR(); - } - } - } - return success; -} - -uint32_t RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, bool read, bool write) { - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() { - if (GetPC() == LLDB_INVALID_ADDRESS) - return false; - - return true; -} - -unsigned RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset( - unsigned offset) { - unsigned reg; - for (reg = 0; reg < k_num_registers_arm64; reg++) { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_arm64 && "Invalid register offset."); - return reg; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits() { - return false; -} - -lldb::addr_t RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress( - uint32_t hw_index) { - return LLDB_INVALID_ADDRESS; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex( - lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints() { - return 0; -} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h deleted file mode 100644 index f100d905e28f..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h +++ /dev/null @@ -1,77 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm64.h --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" -#include "RegisterContextPOSIX.h" - -class RegisterContextPOSIXProcessMonitor_arm64 - : public RegisterContextPOSIX_arm64, - public POSIXBreakpointProtocol { -public: - RegisterContextPOSIXProcessMonitor_arm64( - lldb_private::Thread &thread, - std::unique_ptr<RegisterInfoPOSIX_arm64> register_info); - -protected: - bool ReadGPR(); - - bool ReadFPR(); - - bool WriteGPR(); - - bool WriteFPR(); - - // lldb_private::RegisterContext - bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool WriteRegister(const unsigned reg, - const lldb_private::RegisterValue &value); - - bool ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value); - - bool WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value); - - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, - bool write); - - bool ClearHardwareWatchpoint(uint32_t hw_index); - - bool HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool UpdateAfterBreakpoint(); - - unsigned GetRegisterIndexFromOffset(unsigned offset); - - bool IsWatchpointHit(uint32_t hw_index); - - bool ClearWatchpointHits(); - - lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - - bool IsWatchpointVacant(uint32_t hw_index); - - bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, - bool write, uint32_t hw_index); - - uint32_t NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor &GetMonitor(); -}; - -#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp deleted file mode 100644 index 23c76f234c8e..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ /dev/null @@ -1,262 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_mips64.cpp ---------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Target/Thread.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/RegisterValue.h" - -#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" -#include "ProcessFreeBSD.h" -#include "ProcessMonitor.h" -#include "RegisterContextPOSIXProcessMonitor_mips64.h" - -using namespace lldb_private; -using namespace lldb; - -#define REG_CONTEXT_SIZE (GetGPRSize()) - -RegisterContextPOSIXProcessMonitor_mips64:: - RegisterContextPOSIXProcessMonitor_mips64( - Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) {} - -ProcessMonitor &RegisterContextPOSIXProcessMonitor_mips64::GetMonitor() { - ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); - return process->GetMonitor(); -} - -bool RegisterContextPOSIXProcessMonitor_mips64::ReadGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_mips64::ReadFPR() { - // XXX not yet implemented - return false; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::WriteGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_mips64::WriteFPR() { - // XXX not yet implemented - return false; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::ReadRegister( - const unsigned reg, RegisterValue &value) { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), - GetRegisterName(reg), GetRegisterSize(reg), - value); -} - -bool RegisterContextPOSIXProcessMonitor_mips64::WriteRegister( - const unsigned reg, const RegisterValue &value) { - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) { - Status error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData( - full_reg_info, dst, sizeof(dst), byte_order, error); - if (error.Success() && dest_size) { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData( - reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) { - // Copy the src bytes to the destination. - memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue( - m_thread.GetID(), GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), value_to_write); -} - -bool RegisterContextPOSIXProcessMonitor_mips64::ReadRegister( - const RegisterInfo *reg_info, RegisterValue &value) { - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg)) { - if (!ReadFPR()) - return false; - } else { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - - bool success = ReadRegister(full_reg, value); - - if (success) { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned - // value one byte to the right. - if (is_subreg && (reg_info->byte_offset & 0x1)) - value.SetUInt64(value.GetAsUInt64() >> 8); - - // If our return byte size was greater than the return value reg size, - // then use the type specified by reg_info rather than the uint64_t - // default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; - } - - return false; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue &value) { - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) - return WriteRegister(reg, value); - - return false; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues( - DataBufferSP &data_sp) { - bool success = false; - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (ReadGPR() && ReadFPR()) { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) { - ::memcpy(dst, &m_gpr_mips64, GetGPRSize()); - } - } - return success; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues( - const DataBufferSP &data_sp) { - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { - uint8_t *src = data_sp->GetBytes(); - if (src) { - ::memcpy(&m_gpr_mips64, src, GetGPRSize()); - - if (WriteGPR()) { - src += GetGPRSize(); - } - } - } - return success; -} - -uint32_t RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint( - addr_t addr, size_t size, bool read, bool write) { - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep( - bool enable) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint() { - // PC points one byte past the int3 responsible for the breakpoint. - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - SetPC(pc - 1); - return true; -} - -unsigned RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset( - unsigned offset) { - unsigned reg; - for (reg = 0; reg < k_num_registers_mips64; reg++) { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_mips64 && "Invalid register offset."); - return reg; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits() { - return false; -} - -addr_t RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress( - uint32_t hw_index) { - return LLDB_INVALID_ADDRESS; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex( - addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints() { - return 0; -} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h deleted file mode 100644 index a482cd3f1e1c..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h +++ /dev/null @@ -1,80 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_mips64.h -------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" -#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h" -#include "RegisterContextPOSIX.h" - -class RegisterContextPOSIXProcessMonitor_mips64 - : public RegisterContextPOSIX_mips64, - public POSIXBreakpointProtocol { -public: - RegisterContextPOSIXProcessMonitor_mips64( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool ReadGPR(); - - bool ReadFPR(); - - bool WriteGPR(); - - bool WriteFPR(); - - // lldb_private::RegisterContext - bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool WriteRegister(const unsigned reg, - const lldb_private::RegisterValue &value); - - bool ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value); - - bool WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value); - - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, - bool write); - - bool ClearHardwareWatchpoint(uint32_t hw_index); - - bool HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool UpdateAfterBreakpoint(); - - unsigned GetRegisterIndexFromOffset(unsigned offset); - - bool IsWatchpointHit(uint32_t hw_index); - - bool ClearWatchpointHits(); - - lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - - bool IsWatchpointVacant(uint32_t hw_index); - - bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, - bool write, uint32_t hw_index); - - uint32_t NumSupportedHardwareWatchpoints(); - -private: - uint64_t - m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers. - ProcessMonitor &GetMonitor(); -}; - -#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp deleted file mode 100644 index f8342775a81b..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp +++ /dev/null @@ -1,274 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_powerpc.cpp --------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Target/Thread.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/RegisterValue.h" - -#include "ProcessFreeBSD.h" -#include "ProcessMonitor.h" -#include "RegisterContextPOSIXProcessMonitor_powerpc.h" -#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" - -using namespace lldb_private; -using namespace lldb; - -#define REG_CONTEXT_SIZE (GetGPRSize()) - -RegisterContextPOSIXProcessMonitor_powerpc:: - RegisterContextPOSIXProcessMonitor_powerpc( - Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info) {} - -ProcessMonitor &RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor() { - ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); - return process->GetMonitor(); -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr_powerpc, - sizeof(m_fpr_powerpc)); -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::ReadVMX() { - // XXX: Need a way to read/write process VMX registers with ptrace. - return false; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr_powerpc, - sizeof(m_fpr_powerpc)); -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::WriteVMX() { - // XXX: Need a way to read/write process VMX registers with ptrace. - return false; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister( - const unsigned reg, RegisterValue &value) { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), - GetRegisterName(reg), GetRegisterSize(reg), - value); -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister( - const unsigned reg, const RegisterValue &value) { - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) { - Status error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData( - full_reg_info, dst, sizeof(dst), byte_order, error); - if (error.Success() && dest_size) { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData( - reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) { - // Copy the src bytes to the destination. - memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); - // Account for the fact that 32-bit targets on powerpc64 really use 64-bit - // registers in ptrace, but expose here 32-bit registers with a higher - // offset. - uint64_t offset = GetRegisterOffset(reg_to_write); - offset &= ~(sizeof(uintptr_t) - 1); - return monitor.WriteRegisterValue( - m_thread.GetID(), offset, GetRegisterName(reg_to_write), value_to_write); -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister( - const RegisterInfo *reg_info, RegisterValue &value) { - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg)) { - if (!ReadFPR()) - return false; - uint8_t *src = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; - value.SetUInt64(*(uint64_t *)src); - } else if (IsGPR(reg)) { - bool success = ReadRegister(reg, value); - - if (success) { - // If our return byte size was greater than the return value reg size, - // then use the type specified by reg_info rather than the uint64_t - // default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; - } - - return false; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue &value) { - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) { - return WriteRegister(reg, value); - } else if (IsFPR(reg)) { - assert(reg_info->byte_offset < sizeof(m_fpr_powerpc)); - uint8_t *dst = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; - *(uint64_t *)dst = value.GetAsUInt64(); - return WriteFPR(); - } - - return false; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues( - DataBufferSP &data_sp) { - bool success = false; - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (ReadGPR() && ReadFPR()) { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) { - ::memcpy(dst, &m_gpr_powerpc, GetGPRSize()); - dst += GetGPRSize(); - } - } - return success; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues( - const DataBufferSP &data_sp) { - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { - uint8_t *src = data_sp->GetBytes(); - if (src) { - ::memcpy(&m_gpr_powerpc, src, GetGPRSize()); - - if (WriteGPR()) { - src += GetGPRSize(); - ::memcpy(&m_fpr_powerpc, src, sizeof(m_fpr_powerpc)); - - success = WriteFPR(); - } - } - } - return success; -} - -uint32_t RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint( - addr_t addr, size_t size, bool read, bool write) { - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep( - bool enable) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint() { - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - return true; -} - -unsigned RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset( - unsigned offset) { - unsigned reg; - for (reg = 0; reg < k_num_registers_powerpc; reg++) { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_powerpc && "Invalid register offset."); - return reg; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits() { - return false; -} - -addr_t RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress( - uint32_t hw_index) { - return LLDB_INVALID_ADDRESS; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant( - uint32_t hw_index) { - return false; -} - -bool RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex( - addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints() { - return 0; -} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h deleted file mode 100644 index 17b649feebf1..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h +++ /dev/null @@ -1,84 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_powerpc.h -------------*- C++ -//-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" -#include "RegisterContextPOSIX.h" - -class RegisterContextPOSIXProcessMonitor_powerpc - : public RegisterContextPOSIX_powerpc, - public POSIXBreakpointProtocol { -public: - RegisterContextPOSIXProcessMonitor_powerpc( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool IsVMX(); - - bool ReadGPR(); - - bool ReadFPR(); - - bool ReadVMX(); - - bool WriteGPR(); - - bool WriteFPR(); - - bool WriteVMX(); - - // lldb_private::RegisterContext - bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool WriteRegister(const unsigned reg, - const lldb_private::RegisterValue &value); - - bool ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value); - - bool WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value); - - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, - bool write); - - bool ClearHardwareWatchpoint(uint32_t hw_index); - - bool HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool UpdateAfterBreakpoint(); - - unsigned GetRegisterIndexFromOffset(unsigned offset); - - bool IsWatchpointHit(uint32_t hw_index); - - bool ClearWatchpointHits(); - - lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - - bool IsWatchpointVacant(uint32_t hw_index); - - bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, - bool write, uint32_t hw_index); - - uint32_t NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor &GetMonitor(); -}; - -#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp deleted file mode 100644 index b1739e1e3bd8..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp +++ /dev/null @@ -1,613 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_x86.cpp ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Target/Thread.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/RegisterValue.h" - -#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h" -#include "Plugins/Process/FreeBSD/ProcessMonitor.h" -#include "RegisterContextPOSIXProcessMonitor_x86.h" - -using namespace lldb_private; -using namespace lldb; - -// Support ptrace extensions even when compiled without required kernel support -#ifndef NT_X86_XSTATE -#define NT_X86_XSTATE 0x202 -#endif - -#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(FPR)) - -static uint32_t size_and_rw_bits(size_t size, bool read, bool write) { - uint32_t rw; - - if (read) - rw = 0x3; // READ or READ/WRITE - else if (write) - rw = 0x1; // WRITE - else - assert(0 && "read and write cannot both be false"); - - switch (size) { - case 1: - return rw; - case 2: - return (0x1 << 2) | rw; - case 4: - return (0x3 << 2) | rw; - case 8: - return (0x2 << 2) | rw; - default: - assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); - return 0; // Unreachable. Just to silence compiler. - } -} - -RegisterContextPOSIXProcessMonitor_x86_64:: - RegisterContextPOSIXProcessMonitor_x86_64( - Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info) { - // Store byte offset of fctrl (i.e. first register of FPR) wrt 'UserArea' - const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl"); - m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset; - - m_iovec.iov_base = &m_fpr.xsave; - m_iovec.iov_len = sizeof(m_fpr.xsave); -} - -ProcessMonitor &RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor() { - ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); - return process->GetMonitor(); -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::ReadGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::ReadFPR() { - ProcessMonitor &monitor = GetMonitor(); - if (GetFPRType() == eFXSAVE) - return monitor.ReadFPR(m_thread.GetID(), &m_fpr.fxsave, - sizeof(m_fpr.fxsave)); - - if (GetFPRType() == eXSAVE) - return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, - sizeof(m_fpr.xsave), NT_X86_XSTATE); - return false; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::WriteGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::WriteFPR() { - ProcessMonitor &monitor = GetMonitor(); - if (GetFPRType() == eFXSAVE) - return monitor.WriteFPR(m_thread.GetID(), &m_fpr.fxsave, - sizeof(m_fpr.fxsave)); - - if (GetFPRType() == eXSAVE) - return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, - sizeof(m_fpr.xsave), NT_X86_XSTATE); - return false; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister( - const unsigned reg, RegisterValue &value) { - ProcessMonitor &monitor = GetMonitor(); - -#if defined(__FreeBSD__) - if (reg >= m_reg_info.first_dr) - return monitor.ReadDebugRegisterValue( - m_thread.GetID(), GetRegisterOffset(reg), GetRegisterName(reg), - GetRegisterSize(reg), value); -#endif - return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), - GetRegisterName(reg), GetRegisterSize(reg), - value); -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister( - const unsigned reg, const RegisterValue &value) { - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) { - Status error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData( - full_reg_info, dst, sizeof(dst), byte_order, error); - if (error.Success() && dest_size) { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData( - reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) { - // Copy the src bytes to the destination. - memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); -#if defined(__FreeBSD__) - if (reg >= m_reg_info.first_dr) - return monitor.WriteDebugRegisterValue( - m_thread.GetID(), GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), value_to_write); -#endif - return monitor.WriteRegisterValue( - m_thread.GetID(), GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), value_to_write); -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister( - const RegisterInfo *reg_info, RegisterValue &value) { - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg, GetFPRType())) { - if (!ReadFPR()) - return false; - } else { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - - bool success = ReadRegister(full_reg, value); - - if (success) { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned - // value one byte to the right. - if (is_subreg && (reg_info->byte_offset & 0x1)) - value.SetUInt64(value.GetAsUInt64() >> 8); - - // If our return byte size was greater than the return value reg size, - // then use the type specified by reg_info rather than the uint64_t - // default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; - } - - if (reg_info->encoding == eEncodingVector) { - ByteOrder byte_order = GetByteOrder(); - - if (byte_order != ByteOrder::eByteOrderInvalid) { - if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) - value.SetBytes(m_fpr.fxsave.stmm[reg - m_reg_info.first_st].bytes, - reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) - value.SetBytes(m_fpr.fxsave.stmm[reg - m_reg_info.first_mm].bytes, - reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) - value.SetBytes(m_fpr.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, - reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) { - // Concatenate ymm using the register halves in xmm.bytes and - // ymmh.bytes - if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order)) - value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, - reg_info->byte_size, byte_order); - else - return false; - } - return value.GetType() == RegisterValue::eTypeBytes; - } - return false; - } - - // Get pointer to m_fpr.fxsave variable and set the data from it. Byte - // offsets of all registers are calculated wrt 'UserArea' structure. However, - // ReadFPR() reads fpu registers {using ptrace(PT_GETFPREGS,..)} and stores - // them in 'm_fpr' (of type FPR structure). To extract values of fpu - // registers, m_fpr should be read at byte offsets calculated wrt to FPR - // structure. - - // Since, FPR structure is also one of the member of UserArea structure. - // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - - // byte_offset(fctrl wrt UserArea) - assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr)); - uint8_t *src = - (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea; - switch (reg_info->byte_size) { - case 1: - value.SetUInt8(*(uint8_t *)src); - return true; - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; - } -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue &value) { - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) - return WriteRegister(reg, value); - - if (IsFPR(reg, GetFPRType())) { - if (reg_info->encoding == eEncodingVector) { - if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) - ::memcpy(m_fpr.fxsave.stmm[reg - m_reg_info.first_st].bytes, - value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) - ::memcpy(m_fpr.fxsave.stmm[reg - m_reg_info.first_mm].bytes, - value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) - ::memcpy(m_fpr.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, - value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) { - if (GetFPRType() != eXSAVE) - return false; // the target processor does not support AVX - - // Store ymm register content, and split into the register halves in - // xmm.bytes and ymmh.bytes - ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, - value.GetBytes(), value.GetByteSize()); - if (false == CopyYMMtoXSTATE(reg, GetByteOrder())) - return false; - } - } else { - // Get pointer to m_fpr.fxsave variable and set the data to it. Byte - // offsets of all registers are calculated wrt 'UserArea' structure. - // However, WriteFPR() takes m_fpr (of type FPR structure) and writes - // only fpu registers using ptrace(PT_SETFPREGS,..) API. Hence fpu - // registers should be written in m_fpr at byte offsets calculated wrt - // FPR structure. - - // Since, FPR structure is also one of the member of UserArea structure. - // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - - // byte_offset(fctrl wrt UserArea) - assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) < - sizeof(m_fpr)); - uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset - - m_fctrl_offset_in_userarea; - switch (reg_info->byte_size) { - case 1: - *(uint8_t *)dst = value.GetAsUInt8(); - break; - case 2: - *(uint16_t *)dst = value.GetAsUInt16(); - break; - case 4: - *(uint32_t *)dst = value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return false; - } - } - - if (WriteFPR()) { - if (IsAVX(reg)) - return CopyYMMtoXSTATE(reg, GetByteOrder()); - return true; - } - } - return false; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues( - DataBufferSP &data_sp) { - bool success = false; - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (ReadGPR() && ReadFPR()) { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) { - ::memcpy(dst, &m_gpr_x86_64, GetGPRSize()); - dst += GetGPRSize(); - if (GetFPRType() == eFXSAVE) - ::memcpy(dst, &m_fpr.fxsave, sizeof(m_fpr.fxsave)); - } - - if (GetFPRType() == eXSAVE) { - ByteOrder byte_order = GetByteOrder(); - - // Assemble the YMM register content from the register halves. - for (uint32_t reg = m_reg_info.first_ymm; - success && reg <= m_reg_info.last_ymm; ++reg) - success = CopyXSTATEtoYMM(reg, byte_order); - - if (success) { - // Copy the extended register state including the assembled ymm - // registers. - ::memcpy(dst, &m_fpr, sizeof(m_fpr)); - } - } - } - return success; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::WriteAllRegisterValues( - const DataBufferSP &data_sp) { - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { - uint8_t *src = data_sp->GetBytes(); - if (src) { - ::memcpy(&m_gpr_x86_64, src, GetGPRSize()); - - if (WriteGPR()) { - src += GetGPRSize(); - if (GetFPRType() == eFXSAVE) - ::memcpy(&m_fpr.fxsave, src, sizeof(m_fpr.fxsave)); - if (GetFPRType() == eXSAVE) - ::memcpy(&m_fpr.xsave, src, sizeof(m_fpr.xsave)); - - success = WriteFPR(); - if (success) { - if (GetFPRType() == eXSAVE) { - ByteOrder byte_order = GetByteOrder(); - - // Parse the YMM register content from the register halves. - for (uint32_t reg = m_reg_info.first_ymm; - success && reg <= m_reg_info.last_ymm; ++reg) - success = CopyYMMtoXSTATE(reg, byte_order); - } - } - } - } - } - return success; -} - -uint32_t RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpoint( - addr_t addr, size_t size, bool read, bool write) { - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::ClearHardwareWatchpoint( - uint32_t hw_index) { - if (hw_index < NumSupportedHardwareWatchpoints()) { - RegisterValue current_dr7_bits; - - if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits)) { - uint64_t new_dr7_bits = - current_dr7_bits.GetAsUInt64() & ~(3 << (2 * hw_index)); - - if (WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits))) - return true; - } - } - - return false; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::HardwareSingleStep( - bool enable) { - enum { TRACE_BIT = 0x100 }; - uint64_t rflags; - - if ((rflags = ReadRegisterAsUnsigned(m_reg_info.gpr_flags, -1UL)) == -1UL) - return false; - - if (enable) { - if (rflags & TRACE_BIT) - return true; - - rflags |= TRACE_BIT; - } else { - if (!(rflags & TRACE_BIT)) - return false; - - rflags &= ~TRACE_BIT; - } - - return WriteRegisterFromUnsigned(m_reg_info.gpr_flags, rflags); -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::UpdateAfterBreakpoint() { - // PC points one byte past the int3 responsible for the breakpoint. - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - SetPC(pc - 1); - return true; -} - -unsigned RegisterContextPOSIXProcessMonitor_x86_64::GetRegisterIndexFromOffset( - unsigned offset) { - unsigned reg; - for (reg = 0; reg < m_reg_info.num_registers; reg++) { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < m_reg_info.num_registers && "Invalid register offset."); - return reg; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointHit( - uint32_t hw_index) { - bool is_hit = false; - - if (m_watchpoints_initialized == false) { - // Reset the debug status and debug control registers - RegisterValue zero_bits = RegisterValue(uint64_t(0)); - if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || - !WriteRegister(m_reg_info.first_dr + 7, zero_bits)) - assert(false && "Could not initialize watchpoint registers"); - m_watchpoints_initialized = true; - } - - if (hw_index < NumSupportedHardwareWatchpoints()) { - RegisterValue value; - - if (ReadRegister(m_reg_info.first_dr + 6, value)) { - uint64_t val = value.GetAsUInt64(); - is_hit = val & (1 << hw_index); - } - } - - return is_hit; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::ClearWatchpointHits() { - return WriteRegister(m_reg_info.first_dr + 6, RegisterValue((uint64_t)0)); -} - -addr_t RegisterContextPOSIXProcessMonitor_x86_64::GetWatchpointAddress( - uint32_t hw_index) { - addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS; - - if (hw_index < NumSupportedHardwareWatchpoints()) { - if (!IsWatchpointVacant(hw_index)) { - RegisterValue value; - - if (ReadRegister(m_reg_info.first_dr + hw_index, value)) - wp_monitor_addr = value.GetAsUInt64(); - } - } - - return wp_monitor_addr; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointVacant( - uint32_t hw_index) { - bool is_vacant = false; - RegisterValue value; - - assert(hw_index < NumSupportedHardwareWatchpoints()); - - if (m_watchpoints_initialized == false) { - // Reset the debug status and debug control registers - RegisterValue zero_bits = RegisterValue(uint64_t(0)); - if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || - !WriteRegister(m_reg_info.first_dr + 7, zero_bits)) - assert(false && "Could not initialize watchpoint registers"); - m_watchpoints_initialized = true; - } - - if (ReadRegister(m_reg_info.first_dr + 7, value)) { - uint64_t val = value.GetAsUInt64(); - is_vacant = (val & (3 << 2 * hw_index)) == 0; - } - - return is_vacant; -} - -bool RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpointWithIndex( - addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - - if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints) - return false; - - if (!(size == 1 || size == 2 || size == 4 || size == 8)) - return false; - - if (read == false && write == false) - return false; - - if (!IsWatchpointVacant(hw_index)) - return false; - - // Set both dr7 (debug control register) and dri (debug address register). - - // dr7{7-0} encodes the local/global enable bits: - // global enable --. .-- local enable - // | | - // v v - // dr0 -> bits{1-0} - // dr1 -> bits{3-2} - // dr2 -> bits{5-4} - // dr3 -> bits{7-6} - // - // dr7{31-16} encodes the rw/len bits: - // b_x+3, b_x+2, b_x+1, b_x - // where bits{x+1, x} => rw - // 0b00: execute, 0b01: write, 0b11: read-or-write, - // 0b10: io read-or-write (unused) - // and bits{x+3, x+2} => len - // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte - // - // dr0 -> bits{19-16} - // dr1 -> bits{23-20} - // dr2 -> bits{27-24} - // dr3 -> bits{31-28} - if (hw_index < num_hw_watchpoints) { - RegisterValue current_dr7_bits; - - if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits)) { - uint64_t new_dr7_bits = - current_dr7_bits.GetAsUInt64() | - (1 << (2 * hw_index) | - size_and_rw_bits(size, read, write) << (16 + 4 * hw_index)); - - if (WriteRegister(m_reg_info.first_dr + hw_index, RegisterValue(addr)) && - WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits))) - return true; - } - } - - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_x86_64::NumSupportedHardwareWatchpoints() { - // Available debug address registers: dr0, dr1, dr2, dr3 - return 4; -} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h deleted file mode 100644 index c9dc02a88e01..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h +++ /dev/null @@ -1,81 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_x86.h ----------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" -#include "RegisterContextPOSIX.h" -#include <sys/uio.h> - -class RegisterContextPOSIXProcessMonitor_x86_64 - : public RegisterContextPOSIX_x86, - public POSIXBreakpointProtocol { -public: - RegisterContextPOSIXProcessMonitor_x86_64( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool ReadGPR(); - - bool ReadFPR(); - - bool WriteGPR(); - - bool WriteFPR(); - - // lldb_private::RegisterContext - bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool WriteRegister(const unsigned reg, - const lldb_private::RegisterValue &value); - - bool ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value); - - bool WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value); - - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, - bool write); - - bool ClearHardwareWatchpoint(uint32_t hw_index); - - bool HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool UpdateAfterBreakpoint(); - - unsigned GetRegisterIndexFromOffset(unsigned offset); - - bool IsWatchpointHit(uint32_t hw_index); - - bool ClearWatchpointHits(); - - lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - - bool IsWatchpointVacant(uint32_t hw_index); - - bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, - bool write, uint32_t hw_index); - - uint32_t NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor &GetMonitor(); - uint32_t - m_fctrl_offset_in_userarea; // Offset of 'fctrl' in 'UserArea' Structure - struct iovec m_iovec; -}; - -#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index 5109022d80dd..57f0eb3cceb6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -98,18 +98,7 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, Info.GetArchitecture(), mainloop)); - // Enable event reporting - ptrace_event_t events; - status = PtraceWrapper(PT_GET_EVENT_MASK, pid, &events, sizeof(events)); - if (status.Fail()) - return status.ToError(); - // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN? - events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT; - status = PtraceWrapper(PT_SET_EVENT_MASK, pid, &events, sizeof(events)); - if (status.Fail()) - return status.ToError(); - - status = process_up->ReinitializeThreads(); + status = process_up->SetupTrace(); if (status.Fail()) return status.ToError(); @@ -218,10 +207,14 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { // Get details on the signal raised. if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err); return; } - NativeThreadNetBSD* thread = nullptr; + LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid, + info.psi_lwpid, info.psi_siginfo.si_code); + NativeThreadNetBSD *thread = nullptr; + if (info.psi_lwpid > 0) { for (const auto &t : m_threads) { if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) { @@ -231,8 +224,7 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason(); } if (!thread) - LLDB_LOG(log, - "thread not found in m_threads, pid = {0}, LWP = {1}", pid, + LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid, info.psi_lwpid); } @@ -243,12 +235,12 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { FixupBreakpointPCAsNeeded(*thread); } SetState(StateType::eStateStopped, true); - break; + return; case TRAP_TRACE: if (thread) thread->SetStoppedByTrace(); SetState(StateType::eStateStopped, true); - break; + return; case TRAP_EXEC: { Status error = ReinitializeThreads(); if (error.Fail()) { @@ -262,7 +254,8 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { for (const auto &thread : m_threads) static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec(); SetState(StateType::eStateStopped, true); - } break; + return; + } case TRAP_LWP: { ptrace_state_t pst; Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst)); @@ -272,35 +265,31 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { } switch (pst.pe_report_event) { - case PTRACE_LWP_CREATE: { - LLDB_LOG(log, - "monitoring new thread, pid = {0}, LWP = {1}", pid, - pst.pe_lwp); - NativeThreadNetBSD& t = AddThread(pst.pe_lwp); - error = t.CopyWatchpointsFrom( - static_cast<NativeThreadNetBSD &>(*GetCurrentThread())); - if (error.Fail()) { - LLDB_LOG(log, - "failed to copy watchpoints to new thread {0}: {1}", - pst.pe_lwp, error); - SetState(StateType::eStateInvalid); - return; - } - } break; - case PTRACE_LWP_EXIT: - LLDB_LOG(log, - "removing exited thread, pid = {0}, LWP = {1}", pid, - pst.pe_lwp); - RemoveThread(pst.pe_lwp); - break; + case PTRACE_LWP_CREATE: { + LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid, + pst.pe_lwp); + NativeThreadNetBSD &t = AddThread(pst.pe_lwp); + error = t.CopyWatchpointsFrom( + static_cast<NativeThreadNetBSD &>(*GetCurrentThread())); + if (error.Fail()) { + LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}", + pst.pe_lwp, error); + SetState(StateType::eStateInvalid); + return; + } + } break; + case PTRACE_LWP_EXIT: + LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid, + pst.pe_lwp); + RemoveThread(pst.pe_lwp); + break; } - error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void*>(1), 0); - if (error.Fail()) { + error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0); + if (error.Fail()) SetState(StateType::eStateInvalid); - return; - } - } break; + return; + } case TRAP_DBREG: { if (!thread) break; @@ -308,29 +297,42 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { auto ®ctx = static_cast<NativeRegisterContextNetBSD &>( thread->GetRegisterContext()); uint32_t wp_index = LLDB_INVALID_INDEX32; - Status error = regctx.GetWatchpointHitIndex(wp_index, - (uintptr_t)info.psi_siginfo.si_addr); + Status error = regctx.GetWatchpointHitIndex( + wp_index, (uintptr_t)info.psi_siginfo.si_addr); if (error.Fail()) LLDB_LOG(log, "received error while checking for watchpoint hits, pid = " - "{0}, LWP = {1}, error = {2}", pid, info.psi_lwpid, error); + "{0}, LWP = {1}, error = {2}", + pid, info.psi_lwpid, error); if (wp_index != LLDB_INVALID_INDEX32) { thread->SetStoppedByWatchpoint(wp_index); regctx.ClearWatchpointHit(wp_index); SetState(StateType::eStateStopped, true); - break; + return; } thread->SetStoppedByTrace(); SetState(StateType::eStateStopped, true); - } break; + return; } + } + + // Either user-generated SIGTRAP or an unknown event that would + // otherwise leave the debugger hanging. + LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler"); + MonitorSignal(pid, SIGTRAP); } void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); ptrace_siginfo_t info; + const auto siginfo_err = PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return; + } for (const auto &abs_thread : m_threads) { NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread); @@ -489,16 +491,14 @@ Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) { signal = siginfo->psi_siginfo.si_signo; } - ret = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), - signal); + ret = + PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal); if (ret.Success()) SetState(eStateRunning, true); return ret; } -Status NativeProcessNetBSD::Halt() { - return PtraceWrapper(PT_STOP, GetID()); -} +Status NativeProcessNetBSD::Halt() { return PtraceWrapper(PT_STOP, GetID()); } Status NativeProcessNetBSD::Detach() { Status error; @@ -662,8 +662,8 @@ Status NativeProcessNetBSD::PopulateMemoryRegionCache() { if (vm[i].kve_path[0]) info.SetName(vm[i].kve_path); - m_mem_region_cache.emplace_back( - info, FileSpec(info.GetName().GetCString())); + m_mem_region_cache.emplace_back(info, + FileSpec(info.GetName().GetCString())); } free(vm); @@ -684,15 +684,6 @@ Status NativeProcessNetBSD::PopulateMemoryRegionCache() { return Status(); } -Status NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) { - return Status("Unimplemented"); -} - -Status NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) { - return Status("Unimplemented"); -} - lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() { // punt on this for now return LLDB_INVALID_ADDRESS; @@ -710,21 +701,47 @@ Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) { - return Status("Unimplemented"); + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in process' memory map!", + module_file_spec.GetFilename().AsCString()); } Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) { load_addr = LLDB_INVALID_ADDRESS; - return Status(); + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec file(file_name); + for (const auto &it : m_mem_region_cache) { + if (it.second == file) { + load_addr = it.first.GetRange().GetRangeBase(); + return Status(); + } + } + return Status("No load address found for file %s.", file_name.str().c_str()); } void NativeProcessNetBSD::SigchldHandler() { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); // Process all pending waitpid notifications. int status; - ::pid_t wait_pid = - llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WALLSIG | WNOHANG); + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, + WALLSIG | WNOHANG); if (wait_pid == 0) return; // We are done. @@ -806,12 +823,13 @@ Status NativeProcessNetBSD::Attach() { int wstatus; // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this // point we should have a thread stopped if waitpid succeeds. - if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, - m_pid, nullptr, WALLSIG)) < 0) + if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, + WALLSIG)) < 0) return Status(errno, eErrorTypePOSIX); - /* Initialize threads */ - status = ReinitializeThreads(); + // Initialize threads and tracing status + // NB: this needs to be called before we set thread state + status = SetupTrace(); if (status.Fail()) return status; @@ -819,7 +837,8 @@ Status NativeProcessNetBSD::Attach() { static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP); // Let our process instance know the thread has stopped. - SetState(StateType::eStateStopped); + SetCurrentThreadID(m_threads.front()->GetID()); + SetState(StateType::eStateStopped, false); return Status(); } @@ -864,7 +883,8 @@ Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf, io.piod_len = size; do { - io.piod_addr = const_cast<void *>(static_cast<const void *>(src + bytes_written)); + io.piod_addr = + const_cast<void *>(static_cast<const void *>(src + bytes_written)); io.piod_offs = (void *)(addr + bytes_written); Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io); @@ -909,6 +929,22 @@ NativeProcessNetBSD::GetAuxvData() const { return std::move(buf); } +Status NativeProcessNetBSD::SetupTrace() { + // Enable event reporting + ptrace_event_t events; + Status status = + PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events)); + if (status.Fail()) + return status; + // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN? + events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT; + status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events)); + if (status.Fail()) + return status; + + return ReinitializeThreads(); +} + Status NativeProcessNetBSD::ReinitializeThreads() { // Clear old threads m_threads.clear(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 6a06773f40a8..3d59a4f72e94 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -60,11 +60,6 @@ public: Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override; - Status AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) override; - - Status DeallocateMemory(lldb::addr_t addr) override; - lldb::addr_t GetSharedLibraryInfoAddress() override; size_t UpdateThreads() override; @@ -74,9 +69,13 @@ public: Status SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override; + // The two following methods are probably not necessary and probably + // will never be called. Nevertheless, we implement them right now + // to reduce the differences between different platforms and reduce + // the risk of the lack of implementation actually breaking something, + // at least for the time being. Status GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) override; - Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) override; @@ -112,6 +111,7 @@ private: void SigchldHandler(); Status Attach(); + Status SetupTrace(); Status ReinitializeThreads(); }; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp index 03b505c19890..4755dab0b073 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp @@ -20,12 +20,6 @@ using namespace lldb_private::process_netbsd; #include <sys/ptrace.h> // clang-format on -NativeRegisterContextNetBSD::NativeRegisterContextNetBSD( - NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p) - : NativeRegisterContextRegisterInfo(native_thread, - reg_info_interface_p) {} - Status NativeRegisterContextNetBSD::DoRegisterSet(int ptrace_req, void *buf) { return NativeProcessNetBSD::PtraceWrapper(ptrace_req, GetProcessPid(), buf, m_thread.GetID()); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h index 13e023d856d2..08490aad9e0b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h @@ -18,11 +18,9 @@ namespace process_netbsd { class NativeProcessNetBSD; -class NativeRegisterContextNetBSD : public NativeRegisterContextRegisterInfo { +class NativeRegisterContextNetBSD + : public virtual NativeRegisterContextRegisterInfo { public: - NativeRegisterContextNetBSD(NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p); - // This function is implemented in the NativeRegisterContextNetBSD_* // subclasses to create a new instance of the host specific // NativeRegisterContextNetBSD. The implementations can't collide as only one @@ -31,11 +29,9 @@ public: static NativeRegisterContextNetBSD * CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); - virtual Status + virtual llvm::Error CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) = 0; - virtual Status ClearWatchpointHit(uint32_t wp_index) = 0; - protected: Status DoRegisterSet(int req, void *buf); virtual NativeProcessNetBSD &GetProcess(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp index ca4706a65657..ed1884c94a4b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp @@ -36,9 +36,6 @@ using namespace lldb_private; using namespace lldb_private::process_netbsd; -// Private namespace. - -namespace { // x86 64-bit general purpose registers. static const uint32_t g_gpr_regnums_x86_64[] = { lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, @@ -87,20 +84,21 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - // x86 64-bit floating point registers. static const uint32_t g_fpu_regnums_x86_64[] = { - lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, - lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, - lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64, - lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64, - lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64, - lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64, - lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64, - lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64, - lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64, - lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, - lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, - lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64, - lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64, - lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64, + lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64, + lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64, + lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64, + lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64, + lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64, + lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64, + lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64, + lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64, + lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64, + lldb_xmm14_x86_64, lldb_xmm15_x86_64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - @@ -108,27 +106,34 @@ static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - k_num_fpr_registers_x86_64, "g_fpu_regnums_x86_64 has wrong number of register infos"); -// x86 64-bit registers available via XState. -static const uint32_t g_xstate_regnums_x86_64[] = { +static const uint32_t g_avx_regnums_x86_64[] = { lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64, lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64, lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64, lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - + 1 == + k_num_avx_registers_x86_64, + "g_avx_regnums_x86_64 has wrong number of register infos"); + +static const uint32_t g_mpx_regnums_x86_64[] = { // Note: we currently do not provide them but this is needed to avoid // unnamed groups in SBFrame::GetRegisterContext(). - lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, - lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, + lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, + lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; -static_assert((sizeof(g_xstate_regnums_x86_64) / sizeof(g_xstate_regnums_x86_64[0])) - +static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) - 1 == - k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, - "g_xstate_regnums_x86_64 has wrong number of register infos"); + k_num_mpx_registers_x86_64, + "g_mpx_regnums_x86_64 has wrong number of register infos"); // x86 debug registers. static const uint32_t g_dbr_regnums_x86_64[] = { - lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, - lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, + lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, + lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - @@ -137,7 +142,7 @@ static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - "g_dbr_regnums_x86_64 has wrong number of register infos"); // x86 32-bit general purpose registers. -const uint32_t g_gpr_regnums_i386[] = { +static const uint32_t g_gpr_regnums_i386[] = { lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386, lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386, lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386, @@ -154,7 +159,7 @@ static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - "g_gpr_regnums_i386 has wrong number of register infos"); // x86 32-bit floating point registers. -const uint32_t g_fpu_regnums_i386[] = { +static const uint32_t g_fpu_regnums_i386[] = { lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386, lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386, lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386, @@ -171,25 +176,32 @@ static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - k_num_fpr_registers_i386, "g_fpu_regnums_i386 has wrong number of register infos"); -// x86 64-bit registers available via XState. -static const uint32_t g_xstate_regnums_i386[] = { - lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, - lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, +static const uint32_t g_avx_regnums_i386[] = { + lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, + lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - + 1 == + k_num_avx_registers_i386, + "g_avx_regnums_i386 has wrong number of register infos"); + +static const uint32_t g_mpx_regnums_i386[] = { // Note: we currently do not provide them but this is needed to avoid // unnamed groups in SBFrame::GetRegisterContext(). - lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, - lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386, + lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, + lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386, LLDB_INVALID_REGNUM // register sets need to end with this flag }; -static_assert((sizeof(g_xstate_regnums_i386) / sizeof(g_xstate_regnums_i386[0])) - +static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) - 1 == - k_num_avx_registers_i386 + k_num_mpx_registers_i386, - "g_xstate_regnums_i386 has wrong number of register infos"); + k_num_mpx_registers_i386, + "g_mpx_regnums_i386 has wrong number of register infos"); // x86 debug registers. static const uint32_t g_dbr_regnums_i386[] = { - lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386, - lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386, + lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386, + lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) - @@ -197,9 +209,8 @@ static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) - k_num_dbr_registers_i386, "g_dbr_regnums_i386 has wrong number of register infos"); - // Number of register sets provided by this context. -enum { k_num_register_sets = 4 }; +enum { k_num_register_sets = 5 }; // Register sets for x86 32-bit. static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { @@ -207,11 +218,11 @@ static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { g_gpr_regnums_i386}, {"Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386}, - {"Extended State Registers", "xstate", - k_num_avx_registers_i386 + k_num_mpx_registers_i386, - g_xstate_regnums_i386}, - {"Debug Registers", "dbr", k_num_dbr_registers_i386, - g_dbr_regnums_i386}, + {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386}, + {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386, + g_avx_regnums_i386}, + {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386, + g_mpx_regnums_i386}, }; // Register sets for x86 64-bit. @@ -220,15 +231,15 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { g_gpr_regnums_x86_64}, {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64}, - {"Extended State Registers", "xstate", - k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, - g_xstate_regnums_x86_64}, {"Debug Registers", "dbr", k_num_dbr_registers_x86_64, g_dbr_regnums_x86_64}, + {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, + g_avx_regnums_x86_64}, + {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64, + g_mpx_regnums_x86_64}, }; #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize()) -} // namespace NativeRegisterContextNetBSD * NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD( @@ -246,28 +257,41 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) { } else { assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); - // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 - // register context. + // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the + // x86_64 register context. return new RegisterContextNetBSD_x86_64(target_arch); } } NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextNetBSD(native_thread, - CreateRegisterInfoInterface(target_arch)), - m_gpr(), m_fpr(), m_dbr() {} + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)), + m_regset_offsets({0}) { + assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize()); + std::array<uint32_t, MaxRegularRegSet + 1> first_regnos; -// CONSIDER after local and llgs debugging are merged, register set support can -// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual. -uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const { - uint32_t sets = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - if (GetSetForNativeRegNum(set_index) != -1) - ++sets; + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + first_regnos[FPRegSet] = lldb_fctrl_i386; + first_regnos[DBRegSet] = lldb_dr0_i386; + break; + case llvm::Triple::x86_64: + first_regnos[FPRegSet] = lldb_fctrl_x86_64; + first_regnos[DBRegSet] = lldb_dr0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); } - return sets; + for (int i : {FPRegSet, DBRegSet}) + m_regset_offsets[i] = GetRegisterInfoInterface() + .GetRegisterInfo()[first_regnos[i]] + .byte_offset; +} + +uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const { + return k_num_register_sets; } const RegisterSet * @@ -278,199 +302,79 @@ NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const { case llvm::Triple::x86_64: return &g_reg_sets_x86_64[set_index]; default: - assert(false && "Unhandled target architecture."); - return nullptr; + llvm_unreachable("Unhandled target architecture."); } - - return nullptr; } -static constexpr int RegNumX86ToX86_64(int regnum) { - switch (regnum) { - case lldb_eax_i386: - return lldb_rax_x86_64; - case lldb_ebx_i386: - return lldb_rbx_x86_64; - case lldb_ecx_i386: - return lldb_rcx_x86_64; - case lldb_edx_i386: - return lldb_rdx_x86_64; - case lldb_edi_i386: - return lldb_rdi_x86_64; - case lldb_esi_i386: - return lldb_rsi_x86_64; - case lldb_ebp_i386: - return lldb_rbp_x86_64; - case lldb_esp_i386: - return lldb_rsp_x86_64; - case lldb_eip_i386: - return lldb_rip_x86_64; - case lldb_eflags_i386: - return lldb_rflags_x86_64; - case lldb_cs_i386: - return lldb_cs_x86_64; - case lldb_fs_i386: - return lldb_fs_x86_64; - case lldb_gs_i386: - return lldb_gs_x86_64; - case lldb_ss_i386: - return lldb_ss_x86_64; - case lldb_ds_i386: - return lldb_ds_x86_64; - case lldb_es_i386: - return lldb_es_x86_64; - case lldb_fctrl_i386: - return lldb_fctrl_x86_64; - case lldb_fstat_i386: - return lldb_fstat_x86_64; - case lldb_ftag_i386: - return lldb_fstat_x86_64; - case lldb_fop_i386: - return lldb_fop_x86_64; - case lldb_fiseg_i386: - return lldb_fiseg_x86_64; - case lldb_fioff_i386: - return lldb_fioff_x86_64; - case lldb_foseg_i386: - return lldb_foseg_x86_64; - case lldb_fooff_i386: - return lldb_fooff_x86_64; - case lldb_mxcsr_i386: - return lldb_mxcsr_x86_64; - case lldb_mxcsrmask_i386: - return lldb_mxcsrmask_x86_64; - case lldb_st0_i386: - case lldb_st1_i386: - case lldb_st2_i386: - case lldb_st3_i386: - case lldb_st4_i386: - case lldb_st5_i386: - case lldb_st6_i386: - case lldb_st7_i386: - return lldb_st0_x86_64 + regnum - lldb_st0_i386; - case lldb_mm0_i386: - case lldb_mm1_i386: - case lldb_mm2_i386: - case lldb_mm3_i386: - case lldb_mm4_i386: - case lldb_mm5_i386: - case lldb_mm6_i386: - case lldb_mm7_i386: - return lldb_mm0_x86_64 + regnum - lldb_mm0_i386; - case lldb_xmm0_i386: - case lldb_xmm1_i386: - case lldb_xmm2_i386: - case lldb_xmm3_i386: - case lldb_xmm4_i386: - case lldb_xmm5_i386: - case lldb_xmm6_i386: - case lldb_xmm7_i386: - return lldb_xmm0_x86_64 + regnum - lldb_xmm0_i386; - case lldb_ymm0_i386: - case lldb_ymm1_i386: - case lldb_ymm2_i386: - case lldb_ymm3_i386: - case lldb_ymm4_i386: - case lldb_ymm5_i386: - case lldb_ymm6_i386: - case lldb_ymm7_i386: - return lldb_ymm0_x86_64 + regnum - lldb_ymm0_i386; - case lldb_dr0_i386: - case lldb_dr1_i386: - case lldb_dr2_i386: - case lldb_dr3_i386: - case lldb_dr4_i386: - case lldb_dr5_i386: - case lldb_dr6_i386: - case lldb_dr7_i386: - return lldb_dr0_x86_64 + regnum - lldb_dr0_i386; - default: - assert(false && "Unhandled i386 register."); - return 0; - } -} - -int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum( - int reg_num) const { +llvm::Optional<NativeRegisterContextNetBSD_x86_64::RegSetKind> +NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum( + uint32_t reg_num) const { switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { case llvm::Triple::x86: - if (reg_num <= k_last_gpr_i386) + if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386) return GPRegSet; - else if (reg_num <= k_last_fpr_i386) + if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386) return FPRegSet; - else if (reg_num <= k_last_avx_i386) - return XStateRegSet; // AVX - else if (reg_num <= lldb_dr7_i386) + if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386) + return YMMRegSet; + if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386) + return llvm::None; // MPXR + if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386) + return llvm::None; // MPXC + if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386) return DBRegSet; // DBR - else - return -1; + break; case llvm::Triple::x86_64: - if (reg_num <= k_last_gpr_x86_64) + if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64) return GPRegSet; - else if (reg_num <= k_last_fpr_x86_64) + if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64) return FPRegSet; - else if (reg_num <= k_last_avx_x86_64) - return XStateRegSet; // AVX - else if (reg_num <= k_last_mpxr_x86_64) - return -1; // MPXR - else if (reg_num <= k_last_mpxc_x86_64) - return -1; // MPXC - else if (reg_num <= lldb_dr7_x86_64) + if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64) + return YMMRegSet; + if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64) + return llvm::None; // MPXR + if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64) + return llvm::None; // MPXC + if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64) return DBRegSet; // DBR - else - return -1; + break; default: - assert(false && "Unhandled target architecture."); - return -1; + llvm_unreachable("Unhandled target architecture."); } + + llvm_unreachable("Register does not belong to any register set"); } -Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) { +Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(RegSetKind set) { switch (set) { case GPRegSet: - return DoRegisterSet(PT_GETREGS, &m_gpr); - case FPRegSet: -#if defined(__x86_64__) - return DoRegisterSet(PT_GETFPREGS, &m_fpr); -#else - return DoRegisterSet(PT_GETXMMREGS, &m_fpr); -#endif + return DoRegisterSet(PT_GETREGS, m_gpr.data()); case DBRegSet: - return DoRegisterSet(PT_GETDBREGS, &m_dbr); - case XStateRegSet: -#ifdef HAVE_XSTATE - { - struct iovec iov = {&m_xstate, sizeof(m_xstate)}; - return DoRegisterSet(PT_GETXSTATE, &iov); - } -#else - return Status("XState is not supported by the kernel"); -#endif + return DoRegisterSet(PT_GETDBREGS, m_dbr.data()); + case FPRegSet: + case YMMRegSet: + case MPXRegSet: { + struct iovec iov = {m_xstate.data(), m_xstate.size()}; + Status ret = DoRegisterSet(PT_GETXSTATE, &iov); + assert(reinterpret_cast<xstate *>(m_xstate.data())->xs_rfbm & XCR0_X87); + return ret; + } } llvm_unreachable("NativeRegisterContextNetBSD_x86_64::ReadRegisterSet"); } -Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) { +Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(RegSetKind set) { switch (set) { case GPRegSet: - return DoRegisterSet(PT_SETREGS, &m_gpr); - case FPRegSet: -#if defined(__x86_64__) - return DoRegisterSet(PT_SETFPREGS, &m_fpr); -#else - return DoRegisterSet(PT_SETXMMREGS, &m_fpr); -#endif + return DoRegisterSet(PT_SETREGS, m_gpr.data()); case DBRegSet: - return DoRegisterSet(PT_SETDBREGS, &m_dbr); - case XStateRegSet: -#ifdef HAVE_XSTATE - { - struct iovec iov = {&m_xstate, sizeof(m_xstate)}; - return DoRegisterSet(PT_SETXSTATE, &iov); - } -#else - return Status("XState is not supported by the kernel"); -#endif + return DoRegisterSet(PT_SETDBREGS, m_dbr.data()); + case FPRegSet: + case YMMRegSet: + case MPXRegSet: { + struct iovec iov = {&m_xstate, sizeof(m_xstate)}; + return DoRegisterSet(PT_SETXSTATE, &iov); + } } llvm_unreachable("NativeRegisterContextNetBSD_x86_64::WriteRegisterSet"); } @@ -495,8 +399,8 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, return error; } - int set = GetSetForNativeRegNum(reg); - if (set == -1) { + llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { // This is likely an internal register for lldb use only and should not be // directly queried. error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", @@ -504,261 +408,40 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, return error; } - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::x86_64: - break; - case llvm::Triple::x86: - reg = RegNumX86ToX86_64(reg); - break; - default: - assert(false && "Unhandled target architecture."); - error.SetErrorString("Unhandled target architecture."); - return error; - } - + RegSetKind set = opt_set.getValue(); error = ReadRegisterSet(set); if (error.Fail()) return error; - switch (reg) { -#if defined(__x86_64__) - case lldb_rax_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RAX]; - break; - case lldb_rbx_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RBX]; - break; - case lldb_rcx_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RCX]; - break; - case lldb_rdx_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RDX]; - break; - case lldb_rdi_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RDI]; - break; - case lldb_rsi_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RSI]; - break; - case lldb_rbp_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RBP]; - break; - case lldb_rsp_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RSP]; - break; - case lldb_r8_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R8]; - break; - case lldb_r9_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R9]; - break; - case lldb_r10_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R10]; - break; - case lldb_r11_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R11]; - break; - case lldb_r12_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R12]; - break; - case lldb_r13_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R13]; - break; - case lldb_r14_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R14]; - break; - case lldb_r15_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R15]; - break; - case lldb_rip_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RIP]; - break; - case lldb_rflags_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RFLAGS]; - break; - case lldb_cs_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_CS]; - break; - case lldb_fs_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_FS]; - break; - case lldb_gs_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_GS]; - break; - case lldb_ss_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_SS]; - break; - case lldb_ds_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_DS]; - break; - case lldb_es_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_ES]; - break; -#else - case lldb_rax_x86_64: - reg_value = (uint32_t)m_gpr.r_eax; - break; - case lldb_rbx_x86_64: - reg_value = (uint32_t)m_gpr.r_ebx; - break; - case lldb_rcx_x86_64: - reg_value = (uint32_t)m_gpr.r_ecx; - break; - case lldb_rdx_x86_64: - reg_value = (uint32_t)m_gpr.r_edx; - break; - case lldb_rdi_x86_64: - reg_value = (uint32_t)m_gpr.r_edi; - break; - case lldb_rsi_x86_64: - reg_value = (uint32_t)m_gpr.r_esi; - break; - case lldb_rsp_x86_64: - reg_value = (uint32_t)m_gpr.r_esp; - break; - case lldb_rbp_x86_64: - reg_value = (uint32_t)m_gpr.r_ebp; - break; - case lldb_rip_x86_64: - reg_value = (uint32_t)m_gpr.r_eip; - break; - case lldb_rflags_x86_64: - reg_value = (uint32_t)m_gpr.r_eflags; - break; - case lldb_cs_x86_64: - reg_value = (uint32_t)m_gpr.r_cs; - break; - case lldb_fs_x86_64: - reg_value = (uint32_t)m_gpr.r_fs; - break; - case lldb_gs_x86_64: - reg_value = (uint32_t)m_gpr.r_gs; - break; - case lldb_ss_x86_64: - reg_value = (uint32_t)m_gpr.r_ss; - break; - case lldb_ds_x86_64: - reg_value = (uint32_t)m_gpr.r_ds; - break; - case lldb_es_x86_64: - reg_value = (uint32_t)m_gpr.r_es; - break; -#endif - case lldb_fctrl_x86_64: - reg_value = (uint16_t)m_fpr.fxstate.fx_cw; - break; - case lldb_fstat_x86_64: - reg_value = (uint16_t)m_fpr.fxstate.fx_sw; - break; - case lldb_ftag_x86_64: - reg_value = (uint8_t)m_fpr.fxstate.fx_tw; - break; - case lldb_fop_x86_64: - reg_value = (uint64_t)m_fpr.fxstate.fx_opcode; - break; - case lldb_fiseg_x86_64: - reg_value = (uint64_t)m_fpr.fxstate.fx_ip.fa_64; - break; - case lldb_fioff_x86_64: - reg_value = (uint32_t)m_fpr.fxstate.fx_ip.fa_32.fa_off; - break; - case lldb_foseg_x86_64: - reg_value = (uint64_t)m_fpr.fxstate.fx_dp.fa_64; - break; - case lldb_fooff_x86_64: - reg_value = (uint32_t)m_fpr.fxstate.fx_dp.fa_32.fa_off; - break; - case lldb_mxcsr_x86_64: - reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr; - break; - case lldb_mxcsrmask_x86_64: - reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr_mask; - break; - case lldb_st0_x86_64: - case lldb_st1_x86_64: - case lldb_st2_x86_64: - case lldb_st3_x86_64: - case lldb_st4_x86_64: - case lldb_st5_x86_64: - case lldb_st6_x86_64: - case lldb_st7_x86_64: - reg_value.SetBytes(&m_fpr.fxstate.fx_87_ac[reg - lldb_st0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); - break; - case lldb_mm0_x86_64: - case lldb_mm1_x86_64: - case lldb_mm2_x86_64: - case lldb_mm3_x86_64: - case lldb_mm4_x86_64: - case lldb_mm5_x86_64: - case lldb_mm6_x86_64: - case lldb_mm7_x86_64: - reg_value.SetBytes(&m_fpr.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); - break; - case lldb_xmm0_x86_64: - case lldb_xmm1_x86_64: - case lldb_xmm2_x86_64: - case lldb_xmm3_x86_64: - case lldb_xmm4_x86_64: - case lldb_xmm5_x86_64: - case lldb_xmm6_x86_64: - case lldb_xmm7_x86_64: - case lldb_xmm8_x86_64: - case lldb_xmm9_x86_64: - case lldb_xmm10_x86_64: - case lldb_xmm11_x86_64: - case lldb_xmm12_x86_64: - case lldb_xmm13_x86_64: - case lldb_xmm14_x86_64: - case lldb_xmm15_x86_64: - reg_value.SetBytes(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); + switch (set) { + case GPRegSet: + case FPRegSet: + case DBRegSet: { + void *data = GetOffsetRegSetData(set, reg_info->byte_offset); + FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_xstate.data() + + offsetof(xstate, xs_fxsave)); + if (data == &fpr->ftag) // ftag + reg_value.SetUInt16( + AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm)); + else + reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder()); break; - case lldb_ymm0_x86_64: - case lldb_ymm1_x86_64: - case lldb_ymm2_x86_64: - case lldb_ymm3_x86_64: - case lldb_ymm4_x86_64: - case lldb_ymm5_x86_64: - case lldb_ymm6_x86_64: - case lldb_ymm7_x86_64: - case lldb_ymm8_x86_64: - case lldb_ymm9_x86_64: - case lldb_ymm10_x86_64: - case lldb_ymm11_x86_64: - case lldb_ymm12_x86_64: - case lldb_ymm13_x86_64: - case lldb_ymm14_x86_64: - case lldb_ymm15_x86_64: -#ifdef HAVE_XSTATE - if (!(m_xstate.xs_rfbm & XCR0_SSE) || - !(m_xstate.xs_rfbm & XCR0_YMM_Hi128)) { - error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel", - reg_info->name); + } + case YMMRegSet: { + llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg); + if (!ymm_reg) { + error.SetErrorStringWithFormat( + "register \"%s\" not supported by CPU/kernel", reg_info->name); } else { - uint32_t reg_index = reg - lldb_ymm0_x86_64; - YMMReg ymm = XStateToYMM( - m_xstate.xs_fxsave.fx_xmm[reg_index].xmm_bytes, - m_xstate.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes); + YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi); reg_value.SetBytes(ymm.bytes, reg_info->byte_size, endian::InlHostByteOrder()); } -#else - error.SetErrorString("XState queries not supported by the kernel"); -#endif - break; - case lldb_dr0_x86_64: - case lldb_dr1_x86_64: - case lldb_dr2_x86_64: - case lldb_dr3_x86_64: - case lldb_dr4_x86_64: - case lldb_dr5_x86_64: - case lldb_dr6_x86_64: - case lldb_dr7_x86_64: - reg_value = (uint64_t)m_dbr.dr[reg - lldb_dr0_x86_64]; break; } + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } return error; } @@ -783,8 +466,8 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( return error; } - int set = GetSetForNativeRegNum(reg); - if (set == -1) { + llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { // This is likely an internal register for lldb use only and should not be // directly queried. error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", @@ -792,262 +475,54 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( return error; } - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::x86_64: - break; - case llvm::Triple::x86: - reg = RegNumX86ToX86_64(reg); - break; - default: - assert(false && "Unhandled target architecture."); - error.SetErrorString("Unhandled target architecture."); - return error; - } + RegSetKind set = opt_set.getValue(); + uint64_t new_xstate_bv = 0; error = ReadRegisterSet(set); if (error.Fail()) return error; - switch (reg) { -#if defined(__x86_64__) - case lldb_rax_x86_64: - m_gpr.regs[_REG_RAX] = reg_value.GetAsUInt64(); - break; - case lldb_rbx_x86_64: - m_gpr.regs[_REG_RBX] = reg_value.GetAsUInt64(); - break; - case lldb_rcx_x86_64: - m_gpr.regs[_REG_RCX] = reg_value.GetAsUInt64(); - break; - case lldb_rdx_x86_64: - m_gpr.regs[_REG_RDX] = reg_value.GetAsUInt64(); - break; - case lldb_rdi_x86_64: - m_gpr.regs[_REG_RDI] = reg_value.GetAsUInt64(); - break; - case lldb_rsi_x86_64: - m_gpr.regs[_REG_RSI] = reg_value.GetAsUInt64(); - break; - case lldb_rbp_x86_64: - m_gpr.regs[_REG_RBP] = reg_value.GetAsUInt64(); - break; - case lldb_rsp_x86_64: - m_gpr.regs[_REG_RSP] = reg_value.GetAsUInt64(); - break; - case lldb_r8_x86_64: - m_gpr.regs[_REG_R8] = reg_value.GetAsUInt64(); - break; - case lldb_r9_x86_64: - m_gpr.regs[_REG_R9] = reg_value.GetAsUInt64(); - break; - case lldb_r10_x86_64: - m_gpr.regs[_REG_R10] = reg_value.GetAsUInt64(); - break; - case lldb_r11_x86_64: - m_gpr.regs[_REG_R11] = reg_value.GetAsUInt64(); - break; - case lldb_r12_x86_64: - m_gpr.regs[_REG_R12] = reg_value.GetAsUInt64(); - break; - case lldb_r13_x86_64: - m_gpr.regs[_REG_R13] = reg_value.GetAsUInt64(); - break; - case lldb_r14_x86_64: - m_gpr.regs[_REG_R14] = reg_value.GetAsUInt64(); - break; - case lldb_r15_x86_64: - m_gpr.regs[_REG_R15] = reg_value.GetAsUInt64(); - break; - case lldb_rip_x86_64: - m_gpr.regs[_REG_RIP] = reg_value.GetAsUInt64(); - break; - case lldb_rflags_x86_64: - m_gpr.regs[_REG_RFLAGS] = reg_value.GetAsUInt64(); - break; - case lldb_cs_x86_64: - m_gpr.regs[_REG_CS] = reg_value.GetAsUInt64(); - break; - case lldb_fs_x86_64: - m_gpr.regs[_REG_FS] = reg_value.GetAsUInt64(); - break; - case lldb_gs_x86_64: - m_gpr.regs[_REG_GS] = reg_value.GetAsUInt64(); - break; - case lldb_ss_x86_64: - m_gpr.regs[_REG_SS] = reg_value.GetAsUInt64(); - break; - case lldb_ds_x86_64: - m_gpr.regs[_REG_DS] = reg_value.GetAsUInt64(); - break; - case lldb_es_x86_64: - m_gpr.regs[_REG_ES] = reg_value.GetAsUInt64(); - break; -#else - case lldb_rax_x86_64: - m_gpr.r_eax = reg_value.GetAsUInt32(); - break; - case lldb_rbx_x86_64: - m_gpr.r_ebx = reg_value.GetAsUInt32(); - break; - case lldb_rcx_x86_64: - m_gpr.r_ecx = reg_value.GetAsUInt32(); - break; - case lldb_rdx_x86_64: - m_gpr.r_edx = reg_value.GetAsUInt32(); - break; - case lldb_rdi_x86_64: - m_gpr.r_edi = reg_value.GetAsUInt32(); - break; - case lldb_rsi_x86_64: - m_gpr.r_esi = reg_value.GetAsUInt32(); - break; - case lldb_rsp_x86_64: - m_gpr.r_esp = reg_value.GetAsUInt32(); - break; - case lldb_rbp_x86_64: - m_gpr.r_ebp = reg_value.GetAsUInt32(); - break; - case lldb_rip_x86_64: - m_gpr.r_eip = reg_value.GetAsUInt32(); - break; - case lldb_rflags_x86_64: - m_gpr.r_eflags = reg_value.GetAsUInt32(); - break; - case lldb_cs_x86_64: - m_gpr.r_cs = reg_value.GetAsUInt32(); - break; - case lldb_fs_x86_64: - m_gpr.r_fs = reg_value.GetAsUInt32(); - break; - case lldb_gs_x86_64: - m_gpr.r_gs = reg_value.GetAsUInt32(); - break; - case lldb_ss_x86_64: - m_gpr.r_ss = reg_value.GetAsUInt32(); - break; - case lldb_ds_x86_64: - m_gpr.r_ds = reg_value.GetAsUInt32(); - break; - case lldb_es_x86_64: - m_gpr.r_es = reg_value.GetAsUInt32(); - break; -#endif - case lldb_fctrl_x86_64: - m_fpr.fxstate.fx_cw = reg_value.GetAsUInt16(); - break; - case lldb_fstat_x86_64: - m_fpr.fxstate.fx_sw = reg_value.GetAsUInt16(); - break; - case lldb_ftag_x86_64: - m_fpr.fxstate.fx_tw = reg_value.GetAsUInt8(); - break; - case lldb_fop_x86_64: - m_fpr.fxstate.fx_opcode = reg_value.GetAsUInt16(); - break; - case lldb_fiseg_x86_64: - m_fpr.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64(); - break; - case lldb_fioff_x86_64: - m_fpr.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32(); - break; - case lldb_foseg_x86_64: - m_fpr.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64(); - break; - case lldb_fooff_x86_64: - m_fpr.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32(); - break; - case lldb_mxcsr_x86_64: - m_fpr.fxstate.fx_mxcsr = reg_value.GetAsUInt32(); - break; - case lldb_mxcsrmask_x86_64: - m_fpr.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32(); - break; - case lldb_st0_x86_64: - case lldb_st1_x86_64: - case lldb_st2_x86_64: - case lldb_st3_x86_64: - case lldb_st4_x86_64: - case lldb_st5_x86_64: - case lldb_st6_x86_64: - case lldb_st7_x86_64: - ::memcpy(&m_fpr.fxstate.fx_87_ac[reg - lldb_st0_x86_64], - reg_value.GetBytes(), reg_value.GetByteSize()); - break; - case lldb_mm0_x86_64: - case lldb_mm1_x86_64: - case lldb_mm2_x86_64: - case lldb_mm3_x86_64: - case lldb_mm4_x86_64: - case lldb_mm5_x86_64: - case lldb_mm6_x86_64: - case lldb_mm7_x86_64: - ::memcpy(&m_fpr.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], + switch (set) { + case GPRegSet: + case DBRegSet: + ::memcpy(GetOffsetRegSetData(set, reg_info->byte_offset), reg_value.GetBytes(), reg_value.GetByteSize()); break; - case lldb_xmm0_x86_64: - case lldb_xmm1_x86_64: - case lldb_xmm2_x86_64: - case lldb_xmm3_x86_64: - case lldb_xmm4_x86_64: - case lldb_xmm5_x86_64: - case lldb_xmm6_x86_64: - case lldb_xmm7_x86_64: - case lldb_xmm8_x86_64: - case lldb_xmm9_x86_64: - case lldb_xmm10_x86_64: - case lldb_xmm11_x86_64: - case lldb_xmm12_x86_64: - case lldb_xmm13_x86_64: - case lldb_xmm14_x86_64: - case lldb_xmm15_x86_64: - ::memcpy(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], - reg_value.GetBytes(), reg_value.GetByteSize()); + case FPRegSet: { + void *data = GetOffsetRegSetData(set, reg_info->byte_offset); + FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_xstate.data() + + offsetof(xstate, xs_fxsave)); + if (data == &fpr->ftag) // ftag + fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16()); + else + ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize()); + if (data >= &fpr->xmm) + new_xstate_bv |= XCR0_SSE; + else if (data >= &fpr->mxcsr && data < &fpr->stmm) + new_xstate_bv |= XCR0_SSE; + else + new_xstate_bv |= XCR0_X87; break; - case lldb_ymm0_x86_64: - case lldb_ymm1_x86_64: - case lldb_ymm2_x86_64: - case lldb_ymm3_x86_64: - case lldb_ymm4_x86_64: - case lldb_ymm5_x86_64: - case lldb_ymm6_x86_64: - case lldb_ymm7_x86_64: - case lldb_ymm8_x86_64: - case lldb_ymm9_x86_64: - case lldb_ymm10_x86_64: - case lldb_ymm11_x86_64: - case lldb_ymm12_x86_64: - case lldb_ymm13_x86_64: - case lldb_ymm14_x86_64: - case lldb_ymm15_x86_64: -#ifdef HAVE_XSTATE - if (!(m_xstate.xs_rfbm & XCR0_SSE) || - !(m_xstate.xs_rfbm & XCR0_YMM_Hi128)) { - error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel", - reg_info->name); + } + case YMMRegSet: { + llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg); + if (!ymm_reg) { + error.SetErrorStringWithFormat( + "register \"%s\" not supported by CPU/kernel", reg_info->name); } else { - uint32_t reg_index = reg - lldb_ymm0_x86_64; YMMReg ymm; ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize()); - YMMToXState(ymm, - m_xstate.xs_fxsave.fx_xmm[reg_index].xmm_bytes, - m_xstate.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes); + YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi); + new_xstate_bv |= XCR0_SSE | XCR0_YMM_Hi128; } -#else - error.SetErrorString("XState not supported by the kernel"); -#endif - break; - case lldb_dr0_x86_64: - case lldb_dr1_x86_64: - case lldb_dr2_x86_64: - case lldb_dr3_x86_64: - case lldb_dr4_x86_64: - case lldb_dr5_x86_64: - case lldb_dr6_x86_64: - case lldb_dr7_x86_64: - m_dbr.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64(); break; } + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } + if (new_xstate_bv != 0) + reinterpret_cast<xstate *>(m_xstate.data())->xs_xstate_bv |= new_xstate_bv; return WriteRegisterSet(set); } @@ -1061,7 +536,7 @@ Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues( return error; uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize()); + ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize()); dst += GetRegisterInfoInterface().GetGPRSize(); return error; @@ -1094,7 +569,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( __FUNCTION__); return error; } - ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize()); + ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize()); error = WriteRegisterSet(GPRegSet); if (error.Fail()) @@ -1104,260 +579,66 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( return error; } -int NativeRegisterContextNetBSD_x86_64::GetDR(int num) const { - assert(num >= 0 && num <= 7); - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::x86: - return lldb_dr0_i386 + num; - case llvm::Triple::x86_64: - return lldb_dr0_x86_64 + num; - default: - return -1; - } -} - -Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - RegisterValue reg_value; - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(6)); - Status error = ReadRegister(reg_info, reg_value); - if (error.Fail()) { - is_hit = false; - return error; - } - - uint64_t status_bits = reg_value.GetAsUInt64(); - - is_hit = status_bits & (1 << wp_index); - - return error; -} - -Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { - bool is_hit; - Status error = IsWatchpointHit(wp_index, is_hit); - if (error.Fail()) { - wp_index = LLDB_INVALID_INDEX32; - return error; - } else if (is_hit) { - return error; - } - } - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); +llvm::Error NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom( + NativeRegisterContextNetBSD &source) { + auto &r_source = static_cast<NativeRegisterContextNetBSD_x86_64 &>(source); + // NB: This implicitly reads the whole dbreg set. + RegisterValue dr7; + Status res = r_source.ReadRegister(GetDR(7), dr7); + if (!res.Fail()) { + // copy dbregs only if any watchpoints were set + if ((dr7.GetAsUInt64() & 0xFF) == 0) + return llvm::Error::success(); - RegisterValue reg_value; - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(7)); - Status error = ReadRegister(reg_info, reg_value); - if (error.Fail()) { - is_vacant = false; - return error; + m_dbr = r_source.m_dbr; + res = WriteRegisterSet(DBRegSet); } - - uint64_t control_bits = reg_value.GetAsUInt64(); - - is_vacant = !(control_bits & (1 << (2 * wp_index + 1))); - - return error; + return res.ToError(); } -Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( - lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { - - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - // Read only watchpoints aren't supported on x86_64. Fall back to read/write - // waitchpoints instead. - // TODO: Add logic to detect when a write happens and ignore that watchpoint - // hit. - if (watch_flags == 0x2) - watch_flags = 0x3; - - if (watch_flags != 0x1 && watch_flags != 0x3) - return Status("Invalid read/write bits for watchpoint"); - - if (size != 1 && size != 2 && size != 4 && size != 8) - return Status("Invalid size for watchpoint"); - - bool is_vacant; - Status error = IsWatchpointVacant(wp_index, is_vacant); - if (error.Fail()) - return error; - if (!is_vacant) - return Status("Watchpoint index not vacant"); - - const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); - RegisterValue dr7_value; - error = ReadRegister(reg_info_dr7, dr7_value); - if (error.Fail()) - return error; - - // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 - uint64_t enable_bit = 1 << (2 * wp_index + 1); - - // set bits 16-17, 20-21, 24-25, or 28-29 - // with 0b01 for write, and 0b11 for read/write - uint64_t rw_bits = watch_flags << (16 + 4 * wp_index); - - // set bits 18-19, 22-23, 26-27, or 30-31 - // with 0b00, 0b01, 0b10, or 0b11 - // for 1, 2, 8 (if supported), or 4 bytes, respectively - uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); - - uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - - uint64_t control_bits = dr7_value.GetAsUInt64() & ~bit_mask; - - control_bits |= enable_bit | rw_bits | size_bits; - - const RegisterInfo *const reg_info_drN = - GetRegisterInfoAtIndex(GetDR(wp_index)); - RegisterValue drN_value; - error = ReadRegister(reg_info_drN, drN_value); - if (error.Fail()) - return error; - - // clear dr6 if address or bits changed (i.e. we're not reenabling the same - // watchpoint) - if (drN_value.GetAsUInt64() != addr || - (dr7_value.GetAsUInt64() & bit_mask) != (rw_bits | size_bits)) { - ClearWatchpointHit(wp_index); - - error = WriteRegister(reg_info_drN, RegisterValue(addr)); - if (error.Fail()) - return error; +uint8_t * +NativeRegisterContextNetBSD_x86_64::GetOffsetRegSetData(RegSetKind set, + size_t reg_offset) { + uint8_t *base; + switch (set) { + case GPRegSet: + base = m_gpr.data(); + break; + case FPRegSet: + base = m_xstate.data() + offsetof(xstate, xs_fxsave); + break; + case DBRegSet: + base = m_dbr.data(); + break; + case YMMRegSet: + llvm_unreachable("GetRegSetData() is unsuitable for this regset."); + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); } - - error = WriteRegister(reg_info_dr7, RegisterValue(control_bits)); - if (error.Fail()) - return error; - - error.Clear(); - return error; -} - -bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( - uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return false; - - // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0-1, 2-3, 4-5 - // or 6-7 of the debug control register (DR7) - const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); - RegisterValue reg_value; - Status error = ReadRegister(reg_info_dr7, reg_value); - if (error.Fail()) - return false; - uint64_t bit_mask = 0x3 << (2 * wp_index); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - - return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success(); + assert(reg_offset >= m_regset_offsets[set]); + return base + (reg_offset - m_regset_offsets[set]); } -Status NativeRegisterContextNetBSD_x86_64::ClearWatchpointHit(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); +llvm::Optional<NativeRegisterContextNetBSD_x86_64::YMMSplitPtr> +NativeRegisterContextNetBSD_x86_64::GetYMMSplitReg(uint32_t reg) { + auto xst = reinterpret_cast<xstate *>(m_xstate.data()); + if (!(xst->xs_rfbm & XCR0_SSE) || !(xst->xs_rfbm & XCR0_YMM_Hi128)) + return llvm::None; - // for watchpoints 0, 1, 2, or 3, respectively, check bits 0, 1, 2, or 3 of - // the debug status register (DR6) - const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6)); - RegisterValue reg_value; - Status error = ReadRegister(reg_info_dr6, reg_value); - if (error.Fail()) - return error; - - uint64_t bit_mask = 1 << wp_index; - uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegister(reg_info_dr6, RegisterValue(status_bits)); -} - -Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() { - RegisterValue reg_value; - - // clear bits {0-4} of the debug status register (DR6) - const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6)); - Status error = ReadRegister(reg_info_dr6, reg_value); - if (error.Fail()) - return error; - uint64_t bit_mask = 0xF; - uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - error = WriteRegister(reg_info_dr6, RegisterValue(status_bits)); - if (error.Fail()) - return error; - - // clear bits {0-7,16-31} of the debug control register (DR7) - const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); - error = ReadRegister(reg_info_dr7, reg_value); - if (error.Fail()) - return error; - bit_mask = 0xFF | (0xFFFF << 16); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegister(reg_info_dr7, RegisterValue(control_bits)); -} - -uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) { - bool is_vacant; - Status error = IsWatchpointVacant(wp_index, is_vacant); - if (is_vacant) { - error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); - if (error.Success()) - return wp_index; - } - if (error.Fail() && log) { - LLDB_LOGF(log, "NativeRegisterContextNetBSD_x86_64::%s Error: %s", - __FUNCTION__, error.AsCString()); - } + uint32_t reg_index; + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + reg_index = reg - lldb_ymm0_i386; + break; + case llvm::Triple::x86_64: + reg_index = reg - lldb_ymm0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); } - return LLDB_INVALID_INDEX32; -} - -lldb::addr_t -NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - RegisterValue reg_value; - const RegisterInfo *const reg_info_drN = - GetRegisterInfoAtIndex(GetDR(wp_index)); - if (ReadRegister(reg_info_drN, reg_value).Fail()) - return LLDB_INVALID_ADDRESS; - return reg_value.GetAsUInt64(); -} -uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() { - // Available debug address registers: dr0, dr1, dr2, dr3 - return 4; -} - -Status NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom( - NativeRegisterContextNetBSD &source) { - auto &r_source = static_cast<NativeRegisterContextNetBSD_x86_64&>(source); - Status res = r_source.ReadRegisterSet(DBRegSet); - if (!res.Fail()) { - // copy dbregs only if any watchpoints were set - if ((r_source.m_dbr.dr[7] & 0xFF) == 0) - return res; - - m_dbr = r_source.m_dbr; - res = WriteRegisterSet(DBRegSet); - } - return res; + return YMMSplitPtr{&xst->xs_fxsave.fx_xmm[reg_index], + &xst->xs_ymm_hi128.xs_ymm[reg_index]}; } #endif // defined(__x86_64__) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h index 6c0632f3bce8..31005952dd75 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h @@ -18,20 +18,21 @@ #include <machine/reg.h> // clang-format on +#include <array> + #include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h" #include "Plugins/Process/Utility/RegisterContext_x86.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h" #include "Plugins/Process/Utility/lldb-x86-register-enums.h" -#if defined(PT_GETXSTATE) && defined(PT_SETXSTATE) -#define HAVE_XSTATE -#endif - namespace lldb_private { namespace process_netbsd { class NativeProcessNetBSD; -class NativeRegisterContextNetBSD_x86_64 : public NativeRegisterContextNetBSD { +class NativeRegisterContextNetBSD_x86_64 + : public NativeRegisterContextNetBSD, + public NativeRegisterContextDBReg_x86 { public: NativeRegisterContextNetBSD_x86_64(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); @@ -49,54 +50,39 @@ public: Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; - - bool ClearHardwareWatchpoint(uint32_t wp_index) override; - - Status ClearWatchpointHit(uint32_t wp_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - uint32_t watch_flags, - uint32_t wp_index); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - - Status + llvm::Error CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) override; private: // Private member types. - enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet }; + enum RegSetKind { + GPRegSet, + FPRegSet, + DBRegSet, + MaxRegularRegSet = DBRegSet, + YMMRegSet, + MPXRegSet, + MaxRegSet = MPXRegSet, + }; // Private member variables. - struct reg m_gpr; -#if defined(__x86_64__) - struct fpreg m_fpr; -#else - struct xmmregs m_fpr; -#endif - struct dbreg m_dbr; -#ifdef HAVE_XSTATE - struct xstate m_xstate; -#endif - - int GetSetForNativeRegNum(int reg_num) const; - int GetDR(int num) const; - - Status ReadRegisterSet(uint32_t set); - Status WriteRegisterSet(uint32_t set); + std::array<uint8_t, sizeof(struct reg)> m_gpr; + std::array<uint8_t, sizeof(struct xstate)> m_xstate; + std::array<uint8_t, sizeof(struct dbreg)> m_dbr; + std::array<size_t, MaxRegularRegSet + 1> m_regset_offsets; + + llvm::Optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + uint8_t *GetOffsetRegSetData(RegSetKind set, size_t reg_offset); + + struct YMMSplitPtr { + void *xmm; + void *ymm_hi; + }; + llvm::Optional<YMMSplitPtr> GetYMMSplitReg(uint32_t reg); }; } // namespace process_netbsd diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index fe76fb40e0b3..1a3fd4d646ae 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -116,8 +116,6 @@ void NativeThreadNetBSD::SetStoppedByExec() { } void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { - SetStopped(); - lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); std::ostringstream ostr; @@ -126,8 +124,8 @@ void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); + SetStopped(); m_stop_description = ostr.str(); - m_stop_info.reason = StopReason::eStopReasonWatchpoint; m_stop_info.details.signal.signo = SIGTRAP; } @@ -204,7 +202,6 @@ lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, std::string &description) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - description.clear(); switch (m_state) { @@ -239,14 +236,14 @@ NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) { + assert(m_state == eStateStopped); if (!hardware) return Status("not implemented"); - if (m_state == eStateLaunching) - return Status(); Status error = RemoveWatchpoint(addr); if (error.Fail()) return error; - uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); + uint32_t wp_index = + GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); if (wp_index == LLDB_INVALID_INDEX32) return Status("Setting hardware watchpoint failed."); m_watchpoint_index_map.insert({addr, wp_index}); @@ -266,9 +263,7 @@ Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { - if (m_state == eStateLaunching) - return Status(); - + assert(m_state == eStateStopped); Status error = RemoveHardwareBreakpoint(addr); if (error.Fail()) return error; @@ -296,10 +291,11 @@ Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { return Status("Clearing hardware breakpoint failed."); } -Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { - Status s = GetRegisterContext().CopyHardwareWatchpointsFrom( +llvm::Error +NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { + llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( source.GetRegisterContext()); - if (!s.Fail()) { + if (!s) { m_watchpoint_index_map = source.m_watchpoint_index_map; m_hw_break_index_map = source.m_hw_break_index_map; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h index 89b61ef86722..d4e21bd2bdaa 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h @@ -64,7 +64,7 @@ private: void SetRunning(); void SetStepping(); - Status CopyWatchpointsFrom(NativeThreadNetBSD& source); + llvm::Error CopyWatchpointsFrom(NativeThreadNetBSD& source); // Member Variables lldb::StateType m_state; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.cpp index 579077b45bf9..c6ede61cfe1b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.cpp @@ -58,6 +58,18 @@ CrashReason GetCrashReasonForSIGSEGV(const siginfo_t &info) { #endif case SEGV_BNDERR: return CrashReason::eBoundViolation; +#ifdef __linux__ +#ifndef SEGV_MTEAERR +#define SEGV_MTEAERR 8 +#endif + case SEGV_MTEAERR: + return CrashReason::eAsyncTagCheckFault; +#ifndef SEGV_MTESERR +#define SEGV_MTESERR 9 +#endif + case SEGV_MTESERR: + return CrashReason::eSyncTagCheckFault; +#endif // __linux__ } return CrashReason::eInvalidCrashReason; @@ -166,6 +178,13 @@ std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) { case CrashReason::eBoundViolation: str = "signal SIGSEGV: bound violation"; break; + case CrashReason::eAsyncTagCheckFault: + str = "signal SIGSEGV: async tag check fault"; + break; + case CrashReason::eSyncTagCheckFault: + str = "signal SIGSEGV: sync tag check fault"; + AppendFaultAddr(str, fault_addr); + break; case CrashReason::eIllegalOpcode: str = "signal SIGILL: illegal instruction"; break; @@ -246,6 +265,12 @@ const char *CrashReasonAsString(CrashReason reason) { case CrashReason::eBoundViolation: str = "eBoundViolation"; break; + case CrashReason::eAsyncTagCheckFault: + str = "eAsyncTagCheckFault"; + break; + case CrashReason::eSyncTagCheckFault: + str = "eSyncTagCheckFault"; + break; // SIGILL crash reasons. case CrashReason::eIllegalOpcode: diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.h b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.h index 9b4784a1e68e..f5213891d976 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.h @@ -22,6 +22,8 @@ enum class CrashReason { eInvalidAddress, ePrivilegedAddress, eBoundViolation, + eAsyncTagCheckFault, + eSyncTagCheckFault, // SIGILL crash reasons. eIllegalOpcode, diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.cpp index 685d9d0824f6..c4f45f759a33 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.cpp @@ -82,6 +82,7 @@ const char *AuxVector::GetEntryName(EntryType type) const { case ENTRY_NAME(AUXV_AT_SECURE); break; case ENTRY_NAME(AUXV_AT_BASE_PLATFORM); break; case ENTRY_NAME(AUXV_AT_RANDOM); break; + case ENTRY_NAME(AUXV_AT_HWCAP2); break; case ENTRY_NAME(AUXV_AT_EXECFN); break; case ENTRY_NAME(AUXV_AT_SYSINFO); break; case ENTRY_NAME(AUXV_AT_SYSINFO_EHDR); break; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h index c8c8b1249413..07a0010e198f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h @@ -50,6 +50,7 @@ public: AUXV_AT_SECURE = 23, ///< Boolean, was exec setuid-like? AUXV_AT_BASE_PLATFORM = 24, ///< String identifying real platforms. AUXV_AT_RANDOM = 25, ///< Address of 16 random bytes. + AUXV_AT_HWCAP2 = 26, ///< Extension of AT_HWCAP. AUXV_AT_EXECFN = 31, ///< Filename of executable. AUXV_AT_SYSINFO = 32, ///< Pointer to the global system page used for system /// calls and other nice things. diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index 443638aa39f6..5463a071503c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -151,10 +151,8 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, const uint32_t msbyte = msbit / 8; const uint32_t lsbyte = lsbit / 8; - ConstString containing_reg_name(reg_name_str); - const RegisterInfo *containing_reg_info = - GetRegisterInfo(containing_reg_name); + GetRegisterInfo(reg_name_str); if (containing_reg_info) { const uint32_t max_bit = containing_reg_info->byte_size * 8; if (msbit < max_bit && lsbit < max_bit) { @@ -189,7 +187,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, } } else { printf("error: invalid concrete register \"%s\"\n", - containing_reg_name.GetCString()); + reg_name_str.c_str()); } } else { printf("error: msbit (%u) must be greater than lsbit (%u)\n", @@ -217,7 +215,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, if (composite_reg_list->GetItemAtIndexAsString( composite_idx, composite_reg_name, nullptr)) { const RegisterInfo *composite_reg_info = - GetRegisterInfo(composite_reg_name); + GetRegisterInfo(composite_reg_name.GetStringRef()); if (composite_reg_info) { composite_offset = std::min(composite_offset, composite_reg_info->byte_offset); @@ -357,7 +355,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, if (invalidate_reg_list->GetItemAtIndexAsString( idx, invalidate_reg_name)) { const RegisterInfo *invalidate_reg_info = - GetRegisterInfo(invalidate_reg_name); + GetRegisterInfo(invalidate_reg_name.GetStringRef()); if (invalidate_reg_info) { m_invalidate_regs_map[i].push_back( invalidate_reg_info->kinds[eRegisterKindLLDB]); @@ -430,9 +428,6 @@ void DynamicRegisterInfo::AddRegister(RegisterInfo ®_info, assert(set < m_set_reg_nums.size()); assert(set < m_set_names.size()); m_set_reg_nums[set].push_back(reg_num); - size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; - if (m_reg_data_byte_size < end_reg_offset) - m_reg_data_byte_size = end_reg_offset; } void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { @@ -617,8 +612,70 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { break; } } + + // At this stage call ConfigureOffsets to calculate register offsets for + // targets supporting dynamic offset calculation. It also calculates + // total byte size of register data. + ConfigureOffsets(); + + // Check if register info is reconfigurable + // AArch64 SVE register set has configurable register sizes + if (arch.GetTriple().isAArch64()) { + for (const auto ® : m_regs) { + if (strcmp(reg.name, "vg") == 0) { + m_is_reconfigurable = true; + break; + } + } + } +} + +void DynamicRegisterInfo::ConfigureOffsets() { + // We are going to create a map between remote (eRegisterKindProcessPlugin) + // and local (eRegisterKindLLDB) register numbers. This map will give us + // remote register numbers in increasing order for offset calculation. + std::map<uint32_t, uint32_t> remote_to_local_regnum_map; + for (const auto ® : m_regs) + remote_to_local_regnum_map[reg.kinds[eRegisterKindProcessPlugin]] = + reg.kinds[eRegisterKindLLDB]; + + // At this stage we manually calculate g/G packet offsets of all primary + // registers, only if target XML or qRegisterInfo packet did not send + // an offset explicitly. + uint32_t reg_offset = 0; + for (auto const ®num_pair : remote_to_local_regnum_map) { + if (m_regs[regnum_pair.second].byte_offset == LLDB_INVALID_INDEX32 && + m_regs[regnum_pair.second].value_regs == nullptr) { + m_regs[regnum_pair.second].byte_offset = reg_offset; + + reg_offset = m_regs[regnum_pair.second].byte_offset + + m_regs[regnum_pair.second].byte_size; + } + } + + // Now update all value_regs with each register info as needed + for (auto ® : m_regs) { + if (reg.value_regs != nullptr) { + // Assign a valid offset to all pseudo registers if not assigned by stub. + // Pseudo registers with value_regs list populated will share same offset + // as that of their corresponding primary register in value_regs list. + if (reg.byte_offset == LLDB_INVALID_INDEX32) { + uint32_t value_regnum = reg.value_regs[0]; + if (value_regnum != LLDB_INVALID_INDEX32) + reg.byte_offset = + GetRegisterInfoAtIndex(remote_to_local_regnum_map[value_regnum]) + ->byte_offset; + } + } + + reg_offset = reg.byte_offset + reg.byte_size; + if (m_reg_data_byte_size < reg_offset) + m_reg_data_byte_size = reg_offset; + } } +bool DynamicRegisterInfo::IsReconfigurable() { return m_is_reconfigurable; } + size_t DynamicRegisterInfo::GetNumRegisters() const { return m_regs.size(); } size_t DynamicRegisterInfo::GetNumRegisterSets() const { return m_sets.size(); } @@ -737,16 +794,10 @@ void DynamicRegisterInfo::Dump() const { } } -const lldb_private::RegisterInfo *DynamicRegisterInfo::GetRegisterInfo( - lldb_private::ConstString reg_name) const { - for (auto ®_info : m_regs) { - // We can use pointer comparison since we used a ConstString to set the - // "name" member in AddRegister() - assert(ConstString(reg_info.name).GetCString() == reg_info.name && - "reg_info.name not from a ConstString?"); - if (reg_info.name == reg_name.GetCString()) { +const lldb_private::RegisterInfo * +DynamicRegisterInfo::GetRegisterInfo(llvm::StringRef reg_name) const { + for (auto ®_info : m_regs) + if (reg_info.name == reg_name) return ®_info; - } - } return nullptr; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h index 48939375a504..fbf9db685b71 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -17,6 +17,10 @@ #include "lldb/lldb-private.h" class DynamicRegisterInfo { +protected: + DynamicRegisterInfo(DynamicRegisterInfo &) = default; + DynamicRegisterInfo &operator=(DynamicRegisterInfo &) = default; + public: DynamicRegisterInfo() = default; @@ -25,9 +29,6 @@ public: virtual ~DynamicRegisterInfo() = default; - DynamicRegisterInfo(DynamicRegisterInfo &) = delete; - void operator=(DynamicRegisterInfo &) = delete; - DynamicRegisterInfo(DynamicRegisterInfo &&info); DynamicRegisterInfo &operator=(DynamicRegisterInfo &&info); @@ -63,6 +64,11 @@ public: void Clear(); + bool IsReconfigurable(); + + const lldb_private::RegisterInfo * + GetRegisterInfo(llvm::StringRef reg_name) const; + protected: // Classes that inherit from DynamicRegisterInfo can see and modify these typedef std::vector<lldb_private::RegisterInfo> reg_collection; @@ -74,11 +80,10 @@ protected: typedef std::vector<uint8_t> dwarf_opcode; typedef std::map<uint32_t, dwarf_opcode> dynamic_reg_size_map; - const lldb_private::RegisterInfo * - GetRegisterInfo(lldb_private::ConstString reg_name) const; - void MoveFrom(DynamicRegisterInfo &&info); + void ConfigureOffsets(); + reg_collection m_regs; set_collection m_sets; set_reg_num_collection m_set_reg_nums; @@ -89,5 +94,6 @@ protected: size_t m_reg_data_byte_size = 0u; // The number of bytes required to store // all registers bool m_finalized = false; + bool m_is_reconfigurable = false; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h new file mode 100644 index 000000000000..7f6f7cf5832d --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h @@ -0,0 +1,291 @@ +//===-- LinuxPTraceDefines_arm64sve.h ------------------------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H + +#include <stdint.h> + +namespace lldb_private { +namespace sve { + +/* + * The SVE architecture leaves space for future expansion of the + * vector length beyond its initial architectural limit of 2048 bits + * (16 quadwords). + * + * See <Linux kernel source tree>/Documentation/arm64/sve.rst for a description + * of the vl/vq terminology. + */ + +const uint16_t vq_bytes = 16; /* number of bytes per quadword */ + +const uint16_t vq_min = 1; +const uint16_t vq_max = 512; + +const uint16_t vl_min = vq_min * vq_bytes; +const uint16_t vl_max = vq_max * vq_bytes; + +const uint16_t num_of_zregs = 32; +const uint16_t num_of_pregs = 16; + +inline uint16_t vl_valid(uint16_t vl) { + return (vl % vq_bytes == 0 && vl >= vl_min && vl <= vl_max); +} + +inline uint16_t vq_from_vl(uint16_t vl) { return vl / vq_bytes; } +inline uint16_t vl_from_vq(uint16_t vq) { return vq * vq_bytes; } + +/* A new signal frame record sve_context encodes the SVE Registers on signal + * delivery. sve_context struct definition may be included in asm/sigcontext.h. + * We define sve_context_size which will be used by LLDB sve helper functions. + * More information on sve_context can be found in Linux kernel source tree at + * Documentation/arm64/sve.rst. + */ + +const uint16_t sve_context_size = 16; + +/* + * If the SVE registers are currently live for the thread at signal delivery, + * sve_context.head.size >= + * SigContextSize(vq_from_vl(sve_context.vl)) + * and the register data may be accessed using the Sig*() functions. + * + * If sve_context.head.size < + * SigContextSize(vq_from_vl(sve_context.vl)), + * the SVE registers were not live for the thread and no register data + * is included: in this case, the Sig*() functions should not be + * used except for this check. + * + * The same convention applies when returning from a signal: a caller + * will need to remove or resize the sve_context block if it wants to + * make the SVE registers live when they were previously non-live or + * vice-versa. This may require the the caller to allocate fresh + * memory and/or move other context blocks in the signal frame. + * + * Changing the vector length during signal return is not permitted: + * sve_context.vl must equal the thread's current vector length when + * doing a sigreturn. + * + * + * Note: for all these functions, the "vq" argument denotes the SVE + * vector length in quadwords (i.e., units of 128 bits). + * + * The correct way to obtain vq is to use vq_from_vl(vl). The + * result is valid if and only if vl_valid(vl) is true. This is + * guaranteed for a struct sve_context written by the kernel. + * + * + * Additional functions describe the contents and layout of the payload. + * For each, Sig*Offset(args) is the start offset relative to + * the start of struct sve_context, and Sig*Size(args) is the + * size in bytes: + * + * x type description + * - ---- ----------- + * REGS the entire SVE context + * + * ZREGS __uint128_t[num_of_zregs][vq] all Z-registers + * ZREG __uint128_t[vq] individual Z-register Zn + * + * PREGS uint16_t[num_of_pregs][vq] all P-registers + * PREG uint16_t[vq] individual P-register Pn + * + * FFR uint16_t[vq] first-fault status register + * + * Additional data might be appended in the future. + */ + +inline uint16_t SigZRegSize(uint16_t vq) { return vq * vq_bytes; } +inline uint16_t SigPRegSize(uint16_t vq) { return vq * vq_bytes / 8; } +inline uint16_t SigFFRSize(uint16_t vq) { return SigPRegSize(vq); } + +inline uint32_t SigRegsOffset() { + return (sve_context_size + vq_bytes - 1) / vq_bytes * vq_bytes; +} + +inline uint32_t SigZRegsOffset() { return SigRegsOffset(); } + +inline uint32_t SigZRegOffset(uint16_t vq, uint16_t n) { + return SigRegsOffset() + SigZRegSize(vq) * n; +} + +inline uint32_t SigZRegsSize(uint16_t vq) { + return SigZRegOffset(vq, num_of_zregs) - SigRegsOffset(); +} + +inline uint32_t SigPRegsOffset(uint16_t vq) { + return SigRegsOffset() + SigZRegsSize(vq); +} + +inline uint32_t SigPRegOffset(uint16_t vq, uint16_t n) { + return SigPRegsOffset(vq) + SigPRegSize(vq) * n; +} + +inline uint32_t SigpRegsSize(uint16_t vq) { + return SigPRegOffset(vq, num_of_pregs) - SigPRegsOffset(vq); +} + +inline uint32_t SigFFROffset(uint16_t vq) { + return SigPRegsOffset(vq) + SigpRegsSize(vq); +} + +inline uint32_t SigRegsSize(uint16_t vq) { + return SigFFROffset(vq) + SigFFRSize(vq) - SigRegsOffset(); +} + +inline uint32_t SVESigContextSize(uint16_t vq) { + return SigRegsOffset() + SigRegsSize(vq); +} + +struct user_sve_header { + uint32_t size; /* total meaningful regset content in bytes */ + uint32_t max_size; /* maxmium possible size for this thread */ + uint16_t vl; /* current vector length */ + uint16_t max_vl; /* maximum possible vector length */ + uint16_t flags; + uint16_t reserved; +}; + +/* Definitions for user_sve_header.flags: */ +const uint16_t ptrace_regs_mask = 1 << 0; +const uint16_t ptrace_regs_fpsimd = 0; +const uint16_t ptrace_regs_sve = ptrace_regs_mask; + +/* + * The remainder of the SVE state follows struct user_sve_header. The + * total size of the SVE state (including header) depends on the + * metadata in the header: PTraceSize(vq, flags) gives the total size + * of the state in bytes, including the header. + * + * Refer to <asm/sigcontext.h> for details of how to pass the correct + * "vq" argument to these macros. + */ + +/* Offset from the start of struct user_sve_header to the register data */ +inline uint16_t PTraceRegsOffset() { + return (sizeof(struct user_sve_header) + vq_bytes - 1) / vq_bytes * vq_bytes; +} + +/* + * The register data content and layout depends on the value of the + * flags field. + */ + +/* + * (flags & ptrace_regs_mask) == ptrace_regs_fpsimd case: + * + * The payload starts at offset PTraceFPSIMDOffset, and is of type + * struct user_fpsimd_state. Additional data might be appended in the + * future: use PTraceFPSIMDSize(vq, flags) to compute the total size. + * PTraceFPSIMDSize(vq, flags) will never be less than + * sizeof(struct user_fpsimd_state). + */ + +const uint32_t ptrace_fpsimd_offset = PTraceRegsOffset(); + +/* Return size of struct user_fpsimd_state from asm/ptrace.h */ +inline uint32_t PTraceFPSIMDSize(uint16_t vq, uint16_t flags) { return 528; } + +/* + * (flags & ptrace_regs_mask) == ptrace_regs_sve case: + * + * The payload starts at offset PTraceSVEOffset, and is of size + * PTraceSVESize(vq, flags). + * + * Additional functions describe the contents and layout of the payload. + * For each, PTrace*X*Offset(args) is the start offset relative to + * the start of struct user_sve_header, and PTrace*X*Size(args) is + * the size in bytes: + * + * x type description + * - ---- ----------- + * ZREGS \ + * ZREG | + * PREGS | refer to <asm/sigcontext.h> + * PREG | + * FFR / + * + * FPSR uint32_t FPSR + * FPCR uint32_t FPCR + * + * Additional data might be appended in the future. + */ + +inline uint32_t PTraceZRegSize(uint16_t vq) { return SigZRegSize(vq); } + +inline uint32_t PTracePRegSize(uint16_t vq) { return SigPRegSize(vq); } + +inline uint32_t PTraceFFRSize(uint16_t vq) { return SigFFRSize(vq); } + +const uint32_t fpsr_size = sizeof(uint32_t); +const uint32_t fpcr_size = sizeof(uint32_t); + +inline uint32_t SigToPTrace(uint32_t offset) { + return offset - SigRegsOffset() + PTraceRegsOffset(); +} + +const uint32_t ptrace_sve_offset = PTraceRegsOffset(); + +inline uint32_t PTraceZRegsOffset(uint16_t vq) { + return SigToPTrace(SigZRegsOffset()); +} + +inline uint32_t PTraceZRegOffset(uint16_t vq, uint16_t n) { + return SigToPTrace(SigZRegOffset(vq, n)); +} + +inline uint32_t PTraceZRegsSize(uint16_t vq) { + return PTraceZRegOffset(vq, num_of_zregs) - SigToPTrace(SigRegsOffset()); +} + +inline uint32_t PTracePRegsOffset(uint16_t vq) { + return SigToPTrace(SigPRegsOffset(vq)); +} + +inline uint32_t PTracePRegOffset(uint16_t vq, uint16_t n) { + return SigToPTrace(SigPRegOffset(vq, n)); +} + +inline uint32_t PTracePRegsSize(uint16_t vq) { + return PTracePRegOffset(vq, num_of_pregs) - PTracePRegsOffset(vq); +} + +inline uint32_t PTraceFFROffset(uint16_t vq) { + return SigToPTrace(SigFFROffset(vq)); +} + +inline uint32_t PTraceFPSROffset(uint16_t vq) { + return (PTraceFFROffset(vq) + PTraceFFRSize(vq) + (vq_bytes - 1)) / vq_bytes * + vq_bytes; +} + +inline uint32_t PTraceFPCROffset(uint16_t vq) { + return PTraceFPSROffset(vq) + fpsr_size; +} + +/* + * Any future extension appended after FPCR must be aligned to the next + * 128-bit boundary. + */ + +inline uint32_t PTraceSVESize(uint16_t vq, uint16_t flags) { + return (PTraceFPCROffset(vq) + fpcr_size - ptrace_sve_offset + vq_bytes - 1) / + vq_bytes * vq_bytes; +} + +inline uint32_t PTraceSize(uint16_t vq, uint16_t flags) { + return (flags & ptrace_regs_mask) == ptrace_regs_sve + ? ptrace_sve_offset + PTraceSVESize(vq, flags) + : ptrace_fpsimd_offset + PTraceFPSIMDSize(vq, flags); +} + +} // namespace SVE +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp index 0c7d9ddc5ac6..947b970edf6c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp @@ -7,80 +7,93 @@ //===----------------------------------------------------------------------===// #include "LinuxProcMaps.h" -#include "llvm/ADT/StringRef.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StringExtractor.h" +#include "llvm/ADT/StringRef.h" using namespace lldb_private; -static Status +enum class MapsKind { Maps, SMaps }; + +static llvm::Expected<MemoryRegionInfo> ProcMapError(const char *msg, + MapsKind kind) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), msg, + kind == MapsKind::Maps ? "maps" : "smaps"); +} + +static llvm::Expected<MemoryRegionInfo> ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, - MemoryRegionInfo &memory_region_info) { - memory_region_info.Clear(); - + MapsKind maps_kind) { + MemoryRegionInfo region; StringExtractor line_extractor(maps_line); - + // Format: {address_start_hex}-{address_end_hex} perms offset dev inode // pathname perms: rwxp (letter is present if set, '-' if not, final // character is p=private, s=shared). - + // Parse out the starting address lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0); - + // Parse out hyphen separating start and end address from range. if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-')) - return Status( - "malformed /proc/{pid}/maps entry, missing dash between address range"); - + return ProcMapError( + "malformed /proc/{pid}/%s entry, missing dash between address range", + maps_kind); + // Parse out the ending address lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address); - + // Parse out the space after the address. if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' ')) - return Status( - "malformed /proc/{pid}/maps entry, missing space after range"); - + return ProcMapError( + "malformed /proc/{pid}/%s entry, missing space after range", maps_kind); + // Save the range. - memory_region_info.GetRange().SetRangeBase(start_address); - memory_region_info.GetRange().SetRangeEnd(end_address); - - // Any memory region in /proc/{pid}/maps is by definition mapped into the - // process. - memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); - + region.GetRange().SetRangeBase(start_address); + region.GetRange().SetRangeEnd(end_address); + + // Any memory region in /proc/{pid}/(maps|smaps) is by definition mapped + // into the process. + region.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + // Parse out each permission entry. if (line_extractor.GetBytesLeft() < 4) - return Status("malformed /proc/{pid}/maps entry, missing some portion of " - "permissions"); - + return ProcMapError( + "malformed /proc/{pid}/%s entry, missing some portion of " + "permissions", + maps_kind); + // Handle read permission. const char read_perm_char = line_extractor.GetChar(); if (read_perm_char == 'r') - memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + region.SetReadable(MemoryRegionInfo::OptionalBool::eYes); else if (read_perm_char == '-') - memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + region.SetReadable(MemoryRegionInfo::OptionalBool::eNo); else - return Status("unexpected /proc/{pid}/maps read permission char"); - + return ProcMapError("unexpected /proc/{pid}/%s read permission char", + maps_kind); + // Handle write permission. const char write_perm_char = line_extractor.GetChar(); if (write_perm_char == 'w') - memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + region.SetWritable(MemoryRegionInfo::OptionalBool::eYes); else if (write_perm_char == '-') - memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + region.SetWritable(MemoryRegionInfo::OptionalBool::eNo); else - return Status("unexpected /proc/{pid}/maps write permission char"); - + return ProcMapError("unexpected /proc/{pid}/%s write permission char", + maps_kind); + // Handle execute permission. const char exec_perm_char = line_extractor.GetChar(); if (exec_perm_char == 'x') - memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); else if (exec_perm_char == '-') - memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); else - return Status("unexpected /proc/{pid}/maps exec permission char"); - + return ProcMapError("unexpected /proc/{pid}/%s exec permission char", + maps_kind); + line_extractor.GetChar(); // Read the private bit line_extractor.SkipSpaces(); // Skip the separator line_extractor.GetHexMaxU64(false, 0); // Read the offset @@ -89,13 +102,13 @@ ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, line_extractor.GetHexMaxU64(false, 0); // Read the major device number line_extractor.SkipSpaces(); // Skip the separator line_extractor.GetU64(0, 10); // Read the inode number - + line_extractor.SkipSpaces(); const char *name = line_extractor.Peek(); if (name) - memory_region_info.SetName(name); - - return Status(); + region.SetName(name); + + return region; } void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map, @@ -104,9 +117,80 @@ void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map, llvm::StringRef line; while (!lines.empty()) { std::tie(line, lines) = lines.split('\n'); - MemoryRegionInfo region; - Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region); - if (!callback(region, error)) + if (!callback(ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::Maps))) break; } } + +void lldb_private::ParseLinuxSMapRegions(llvm::StringRef linux_smap, + LinuxMapCallback const &callback) { + // Entries in /smaps look like: + // 00400000-0048a000 r-xp 00000000 fd:03 960637 + // Size: 552 kB + // Rss: 460 kB + // <...> + // VmFlags: rd ex mr mw me dw + // 00500000-0058a000 rwxp 00000000 fd:03 960637 + // <...> + // + // Where the first line is identical to the /maps format + // and VmFlags is only printed for kernels >= 3.8. + + llvm::StringRef lines(linux_smap); + llvm::StringRef line; + llvm::Optional<MemoryRegionInfo> region; + + while (lines.size()) { + std::tie(line, lines) = lines.split('\n'); + + // A property line looks like: + // <word>: <value> + // (no spaces on the left hand side) + // A header will have a ':' but the LHS will contain spaces + llvm::StringRef name; + llvm::StringRef value; + std::tie(name, value) = line.split(':'); + + // If this line is a property line + if (!name.contains(' ')) { + if (region) { + if (name == "VmFlags") { + if (value.contains("mt")) + region->SetMemoryTagged(MemoryRegionInfo::eYes); + else + region->SetMemoryTagged(MemoryRegionInfo::eNo); + } + // Ignore anything else + } else { + // Orphaned settings line + callback(ProcMapError( + "Found a property line without a corresponding mapping " + "in /proc/{pid}/%s", + MapsKind::SMaps)); + return; + } + } else { + // Must be a new region header + if (region) { + // Save current region + callback(*region); + region.reset(); + } + + // Try to start a new region + llvm::Expected<MemoryRegionInfo> new_region = + ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::SMaps); + if (new_region) { + region = *new_region; + } else { + // Stop at first invalid region header + callback(new_region.takeError()); + return; + } + } + } + + // Catch last region + if (region) + callback(*region); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h index 363f248fd416..02f78d55c290 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h @@ -11,16 +11,16 @@ #include "lldb/lldb-forward.h" #include "llvm/ADT/StringRef.h" -#include <functional> - +#include "llvm/Support/Error.h" namespace lldb_private { -typedef std::function<bool(const lldb_private::MemoryRegionInfo &, - const lldb_private::Status &)> LinuxMapCallback; +typedef std::function<bool(llvm::Expected<MemoryRegionInfo>)> LinuxMapCallback; void ParseLinuxMapRegions(llvm::StringRef linux_map, LinuxMapCallback const &callback); +void ParseLinuxSMapRegions(llvm::StringRef linux_smap, + LinuxMapCallback const &callback); } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 4dd619e3bade..d4b0f4039da9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -14,79 +14,72 @@ LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); } void LinuxSignals::Reset() { m_signals.clear(); - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION ALIAS - // ===== =========== ======== ===== ====== - // ====================================== ====== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); - AddSignal(5, "SIGTRAP", true, true, true, - "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGBUS", false, true, true, "bus error"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); - AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(13, "SIGPIPE", false, true, true, - "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); - AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", - "SIGCLD"); - AddSignal(18, "SIGCONT", false, true, true, "process continue"); - AddSignal(19, "SIGSTOP", true, true, true, "process stop"); - AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", - "SIGPOLL"); - AddSignal(30, "SIGPWR", false, true, true, "power failure"); - AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(32, "SIG32", false, false, false, - "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, - "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, - "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill - // -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format off + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + AddSignal(1, "SIGHUP", false, true, true, "hangup"); + AddSignal(2, "SIGINT", true, true, true, "interrupt"); + AddSignal(3, "SIGQUIT", false, true, true, "quit"); + AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + AddSignal(7, "SIGBUS", false, true, true, "bus error"); + AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + AddSignal(9, "SIGKILL", false, true, true, "kill"); + AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); + AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); + AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + AddSignal(14, "SIGALRM", false, false, false, "alarm"); + AddSignal(15, "SIGTERM", false, true, true, "termination requested"); + AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); + AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + AddSignal(18, "SIGCONT", false, false, true, "process continue"); + AddSignal(19, "SIGSTOP", true, true, true, "process stop"); + AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); + AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); + AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); + AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); + AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); + AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); + AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); + AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); + AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); + AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + AddSignal(30, "SIGPWR", false, true, true, "power failure"); + AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); + AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); + AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); + AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); + AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format on } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp index 8f75844277c0..fb51c56953f8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp @@ -14,79 +14,72 @@ MipsLinuxSignals::MipsLinuxSignals() : UnixSignals() { Reset(); } void MipsLinuxSignals::Reset() { m_signals.clear(); - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION ALIAS - // ===== =========== ======== ===== ====== - // ====================================== ======== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); - AddSignal(5, "SIGTRAP", true, true, true, - "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGEMT", false, true, true, "terminate process with core dump"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGBUS", false, true, true, "bus error"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); - AddSignal(12, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(13, "SIGPIPE", false, true, true, - "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(17, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(18, "SIGCHLD", false, false, true, "child status has changed", - "SIGCLD"); - AddSignal(19, "SIGPWR", false, true, true, "power failure"); - AddSignal(20, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(21, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(22, "SIGIO", false, true, true, "input/output ready/Pollable event", - "SIGPOLL"); - AddSignal(23, "SIGSTOP", true, true, true, "process stop"); - AddSignal(24, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(25, "SIGCONT", false, true, true, "process continue"); - AddSignal(26, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(27, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(28, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(29, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(30, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(31, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(32, "SIG32", false, false, false, - "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, - "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, - "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill - // -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format off + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + AddSignal(1, "SIGHUP", false, true, true, "hangup"); + AddSignal(2, "SIGINT", true, true, true, "interrupt"); + AddSignal(3, "SIGQUIT", false, true, true, "quit"); + AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + AddSignal(7, "SIGEMT", false, true, true, "terminate process with core dump"); + AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + AddSignal(9, "SIGKILL", false, true, true, "kill"); + AddSignal(10, "SIGBUS", false, true, true, "bus error"); + AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + AddSignal(12, "SIGSYS", false, true, true, "invalid system call"); + AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + AddSignal(14, "SIGALRM", false, false, false, "alarm"); + AddSignal(15, "SIGTERM", false, true, true, "termination requested"); + AddSignal(16, "SIGUSR1", false, true, true, "user defined signal 1"); + AddSignal(17, "SIGUSR2", false, true, true, "user defined signal 2"); + AddSignal(18, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + AddSignal(19, "SIGPWR", false, true, true, "power failure"); + AddSignal(20, "SIGWINCH", false, true, true, "window size changes"); + AddSignal(21, "SIGURG", false, true, true, "urgent data on socket"); + AddSignal(22, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + AddSignal(23, "SIGSTOP", true, true, true, "process stop"); + AddSignal(24, "SIGTSTP", false, true, true, "tty stop"); + AddSignal(25, "SIGCONT", false, false, true, "process continue"); + AddSignal(26, "SIGTTIN", false, true, true, "background tty read"); + AddSignal(27, "SIGTTOU", false, true, true, "background tty write"); + AddSignal(28, "SIGVTALRM", false, true, true, "virtual time alarm"); + AddSignal(29, "SIGPROF", false, false, false, "profiling time alarm"); + AddSignal(30, "SIGXCPU", false, true, true, "CPU resource exceeded"); + AddSignal(31, "SIGXFSZ", false, true, true, "file size limit exceeded"); + AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); + AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); + AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); + AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format on } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp new file mode 100644 index 000000000000..ee5295bf6565 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp @@ -0,0 +1,182 @@ +//===-- NativeProcessSoftwareSingleStep.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 "NativeProcessSoftwareSingleStep.h" + +#include "lldb/Core/EmulateInstruction.h" +#include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Utility/RegisterValue.h" + +#include <unordered_map> + +using namespace lldb; +using namespace lldb_private; + +namespace { + +struct EmulatorBaton { + NativeProcessProtocol &m_process; + NativeRegisterContext &m_reg_context; + + // eRegisterKindDWARF -> RegsiterValue + std::unordered_map<uint32_t, RegisterValue> m_register_values; + + EmulatorBaton(NativeProcessProtocol &process, + NativeRegisterContext ®_context) + : m_process(process), m_reg_context(reg_context) {} +}; + +} // anonymous namespace + +static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + lldb::addr_t addr, void *dst, size_t length) { + EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); + + size_t bytes_read; + emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read); + return bytes_read; +} + +static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, + const RegisterInfo *reg_info, + RegisterValue ®_value) { + EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); + + auto it = emulator_baton->m_register_values.find( + reg_info->kinds[eRegisterKindDWARF]); + if (it != emulator_baton->m_register_values.end()) { + reg_value = it->second; + return true; + } + + // The emulator only fill in the dwarf regsiter numbers (and in some case the + // generic register numbers). Get the full register info from the register + // context based on the dwarf register numbers. + const RegisterInfo *full_reg_info = + emulator_baton->m_reg_context.GetRegisterInfo( + eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); + + Status error = + emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value); + if (error.Success()) + return true; + + return false; +} + +static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_value) { + EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); + emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = + reg_value; + return true; +} + +static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + lldb::addr_t addr, const void *dst, + size_t length) { + return length; +} + +static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { + const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + return regsiter_context.ReadRegisterAsUnsigned(flags_info, + LLDB_INVALID_ADDRESS); +} + +Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( + NativeThreadProtocol &thread) { + Status error; + NativeProcessProtocol &process = thread.GetProcess(); + NativeRegisterContext ®ister_context = thread.GetRegisterContext(); + const ArchSpec &arch = process.GetArchitecture(); + + std::unique_ptr<EmulateInstruction> emulator_up( + EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying, + nullptr)); + + if (emulator_up == nullptr) + return Status("Instruction emulator not found!"); + + EmulatorBaton baton(process, register_context); + emulator_up->SetBaton(&baton); + emulator_up->SetReadMemCallback(&ReadMemoryCallback); + emulator_up->SetReadRegCallback(&ReadRegisterCallback); + emulator_up->SetWriteMemCallback(&WriteMemoryCallback); + emulator_up->SetWriteRegCallback(&WriteRegisterCallback); + + if (!emulator_up->ReadInstruction()) + return Status("Read instruction failed!"); + + bool emulation_result = + emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); + + const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + + auto pc_it = + baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); + auto flags_it = + baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]); + + lldb::addr_t next_pc; + lldb::addr_t next_flags; + if (emulation_result) { + assert(pc_it != baton.m_register_values.end() && + "Emulation was successfull but PC wasn't updated"); + next_pc = pc_it->second.GetAsUInt64(); + + if (flags_it != baton.m_register_values.end()) + next_flags = flags_it->second.GetAsUInt64(); + else + next_flags = ReadFlags(register_context); + } else if (pc_it == baton.m_register_values.end()) { + // Emulate instruction failed and it haven't changed PC. Advance PC with + // the size of the current opcode because the emulation of all + // PC modifying instruction should be successful. The failure most + // likely caused by a not supported instruction which don't modify PC. + next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize(); + next_flags = ReadFlags(register_context); + } else { + // The instruction emulation failed after it modified the PC. It is an + // unknown error where we can't continue because the next instruction is + // modifying the PC but we don't know how. + return Status("Instruction emulation failed unexpectedly."); + } + + int size_hint = 0; + if (arch.GetMachine() == llvm::Triple::arm) { + if (next_flags & 0x20) { + // Thumb mode + size_hint = 2; + } else { + // Arm mode + size_hint = 4; + } + } else if (arch.IsMIPS() || arch.GetTriple().isPPC64()) + size_hint = 4; + error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false); + + // If setting the breakpoint fails because next_pc is out of the address + // space, ignore it and let the debugee segfault. + if (error.GetError() == EIO || error.GetError() == EFAULT) { + return Status(); + } else if (error.Fail()) + return error; + + m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); + + return Status(); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h new file mode 100644 index 000000000000..f9435b7a84ba --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h @@ -0,0 +1,31 @@ +//===-- NativeProcessSoftwareSingleStep.h -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeProcessSoftwareSingleStep_h +#define lldb_NativeProcessSoftwareSingleStep_h + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" + +#include <map> + +namespace lldb_private { + +class NativeProcessSoftwareSingleStep { +public: + Status SetupSoftwareSingleStepping(NativeThreadProtocol &thread); + +protected: + // List of thread ids stepping with a breakpoint with the address of + // the relevan breakpoint + std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint; +}; + +} // namespace lldb_private + +#endif // #ifndef lldb_NativeProcessSoftwareSingleStep_h diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp new file mode 100644 index 000000000000..5c05baf71764 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp @@ -0,0 +1,466 @@ +//===-- NativeRegisterContextDBReg_arm64.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 "NativeRegisterContextDBReg_arm64.h" + +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" + +using namespace lldb_private; + +// E (bit 0), used to enable breakpoint/watchpoint +constexpr uint32_t g_enable_bit = 1; +// PAC (bits 2:1): 0b10 +constexpr uint32_t g_pac_bits = (2 << 1); + +// Returns appropriate control register bits for the specified size +static constexpr inline uint64_t GetSizeBits(int size) { + // BAS (bits 12:5) hold a bit-mask of addresses to watch + // e.g. 0b00000001 means 1 byte at address + // 0b00000011 means 2 bytes (addr..addr+1) + // ... + // 0b11111111 means 8 bytes (addr..addr+7) + return ((1 << size) - 1) << 5; +} + +uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareBreakpoints() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR(log, std::move(error), + "failed to read debug registers: {0}"); + return 0; + } + + return m_max_hbp_supported; +} + +uint32_t +NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR( + log, std::move(error), + "unable to set breakpoint: failed to read debug registers: {0}"); + return LLDB_INVALID_INDEX32; + } + + uint32_t control_value = 0, bp_index = 0; + + // Check if size has a valid hardware breakpoint length. + if (size != 4) + return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware + // breakpoint + + // Check 4-byte alignment for hardware breakpoint target address. + if (addr & 0x03) + return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. + + // Setup control value + control_value = g_enable_bit | g_pac_bits | GetSizeBits(size); + + // Iterate over stored breakpoints and find a free bp_index + bp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hbp_supported; i++) { + if (!BreakpointIsEnabled(i)) + bp_index = i; // Mark last free slot + else if (m_hbp_regs[i].address == addr) + return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. + } + + if (bp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update breakpoint in local cache + m_hbp_regs[bp_index].real_addr = addr; + m_hbp_regs[bp_index].address = addr; + m_hbp_regs[bp_index].control = control_value; + + // PTRACE call to set corresponding hardware breakpoint register. + error = WriteHardwareDebugRegs(eDREGTypeBREAK); + + if (error) { + m_hbp_regs[bp_index].address = 0; + m_hbp_regs[bp_index].control &= ~1; + + LLDB_LOG_ERROR( + log, std::move(error), + "unable to set breakpoint: failed to write debug registers: {0}"); + return LLDB_INVALID_INDEX32; + } + + return bp_index; +} + +bool NativeRegisterContextDBReg_arm64::ClearHardwareBreakpoint( + uint32_t hw_idx) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + LLDB_LOG(log, "hw_idx: {0}", hw_idx); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR( + log, std::move(error), + "unable to clear breakpoint: failed to read debug registers: {0}"); + return false; + } + + if (hw_idx >= m_max_hbp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address; + uint32_t tempControl = m_hbp_regs[hw_idx].control; + + m_hbp_regs[hw_idx].control &= ~g_enable_bit; + m_hbp_regs[hw_idx].address = 0; + + // PTRACE call to clear corresponding hardware breakpoint register. + error = WriteHardwareDebugRegs(eDREGTypeBREAK); + + if (error) { + m_hbp_regs[hw_idx].control = tempControl; + m_hbp_regs[hw_idx].address = tempAddr; + + LLDB_LOG_ERROR( + log, std::move(error), + "unable to clear breakpoint: failed to write debug registers: {0}"); + return false; + } + + return true; +} + +Status NativeRegisterContextDBReg_arm64::GetHardwareBreakHitIndex( + uint32_t &bp_index, lldb::addr_t trap_addr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__); + + lldb::addr_t break_addr; + + for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { + break_addr = m_hbp_regs[bp_index].address; + + if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) { + m_hbp_regs[bp_index].hit_addr = trap_addr; + return Status(); + } + } + + bp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +Status NativeRegisterContextDBReg_arm64::ClearAllHardwareBreakpoints() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) + return Status(std::move(error)); + + for (uint32_t i = 0; i < m_max_hbp_supported; i++) { + if (BreakpointIsEnabled(i)) { + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hbp_regs[i].address; + uint32_t tempControl = m_hbp_regs[i].control; + + // Clear watchpoints in local cache + m_hbp_regs[i].control &= ~g_enable_bit; + m_hbp_regs[i].address = 0; + + // Ptrace call to update hardware debug registers + error = WriteHardwareDebugRegs(eDREGTypeBREAK); + + if (error) { + m_hbp_regs[i].control = tempControl; + m_hbp_regs[i].address = tempAddr; + + return Status(std::move(error)); + } + } + } + + return Status(); +} + +bool NativeRegisterContextDBReg_arm64::BreakpointIsEnabled(uint32_t bp_index) { + if ((m_hbp_regs[bp_index].control & g_enable_bit) != 0) + return true; + else + return false; +} + +uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareWatchpoints() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR(log, std::move(error), + "failed to read debug registers: {0}"); + return 0; + } + + return m_max_hwp_supported; +} + +uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR( + log, std::move(error), + "unable to set watchpoint: failed to read debug registers: {0}"); + return LLDB_INVALID_INDEX32; + } + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + + // Check if we are setting watchpoint other than read/write/access Also + // update watchpoint flag to match AArch64 write-read bit configuration. + switch (watch_flags) { + case 1: + watch_flags = 2; + break; + case 2: + watch_flags = 1; + break; + case 3: + break; + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 1 && size != 2 && size != 4 && size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte aligned addresses as well. + if (addr & 0x07) { + uint8_t watch_mask = (addr & 0x07) + size; + + if (watch_mask > 0x08) + return LLDB_INVALID_INDEX32; + else if (watch_mask <= 0x02) + size = 2; + else if (watch_mask <= 0x04) + size = 4; + else + size = 8; + + addr = addr & (~0x07); + } + + // Setup control value + control_value = g_enable_bit | g_pac_bits | GetSizeBits(size); + control_value |= watch_flags << 3; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if (!WatchpointIsEnabled(i)) + wp_index = i; // Mark last free slot + else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(eDREGTypeWATCH); + + if (error) { + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= ~g_enable_bit; + + LLDB_LOG_ERROR( + log, std::move(error), + "unable to set watchpoint: failed to write debug registers: {0}"); + return LLDB_INVALID_INDEX32; + } + + return wp_index; +} + +bool NativeRegisterContextDBReg_arm64::ClearHardwareWatchpoint( + uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR( + log, std::move(error), + "unable to clear watchpoint: failed to read debug registers: {0}"); + return false; + } + + if (wp_index >= m_max_hwp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + uint32_t tempControl = m_hwp_regs[wp_index].control; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= ~g_enable_bit; + m_hwp_regs[wp_index].address = 0; + + // Ptrace call to update hardware debug registers + error = WriteHardwareDebugRegs(eDREGTypeWATCH); + + if (error) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; + + LLDB_LOG_ERROR( + log, std::move(error), + "unable to clear watchpoint: failed to write debug registers: {0}"); + return false; + } + + return true; +} + +Status NativeRegisterContextDBReg_arm64::ClearAllHardwareWatchpoints() { + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) + return Status(std::move(error)); + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if (WatchpointIsEnabled(i)) { + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[i].address; + uint32_t tempControl = m_hwp_regs[i].control; + + // Clear watchpoints in local cache + m_hwp_regs[i].control &= ~g_enable_bit; + m_hwp_regs[i].address = 0; + + // Ptrace call to update hardware debug registers + error = WriteHardwareDebugRegs(eDREGTypeWATCH); + + if (error) { + m_hwp_regs[i].control = tempControl; + m_hwp_regs[i].address = tempAddr; + + return Status(std::move(error)); + } + } + } + + return Status(); +} + +uint32_t +NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { + case 0x01: + return 1; + case 0x03: + return 2; + case 0x0f: + return 4; + case 0xff: + return 8; + default: + return 0; + } +} + +bool NativeRegisterContextDBReg_arm64::WatchpointIsEnabled(uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if ((m_hwp_regs[wp_index].control & g_enable_bit) != 0) + return true; + else + return false; +} + +Status NativeRegisterContextDBReg_arm64::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) + return Status(std::move(error)); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr < watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +lldb::addr_t +NativeRegisterContextDBReg_arm64::GetWatchpointAddress(uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextDBReg_arm64::GetWatchpointHitAddress(uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + return LLDB_INVALID_ADDRESS; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h new file mode 100644 index 000000000000..12ef5571f64c --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h @@ -0,0 +1,79 @@ +//===-- NativeRegisterContextDBReg_arm64.h ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeRegisterContextDBReg_arm64_h +#define lldb_NativeRegisterContextDBReg_arm64_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" + +#include <array> + +namespace lldb_private { + +class NativeRegisterContextDBReg_arm64 + : public virtual NativeRegisterContextRegisterInfo { +public: + uint32_t NumSupportedHardwareBreakpoints() override; + + uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + bool ClearHardwareBreakpoint(uint32_t hw_idx) override; + + Status ClearAllHardwareBreakpoints() override; + + Status GetHardwareBreakHitIndex(uint32_t &bp_index, + lldb::addr_t trap_addr) override; + + bool BreakpointIsEnabled(uint32_t bp_index); + + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + bool ClearHardwareWatchpoint(uint32_t hw_index) override; + + Status ClearAllHardwareWatchpoints() override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t GetWatchpointSize(uint32_t wp_index); + + bool WatchpointIsEnabled(uint32_t wp_index); + + // Debug register type select + enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; + +protected: + // Debug register info for hardware breakpoints and watchpoints management. + struct DREG { + lldb::addr_t address; // Breakpoint/watchpoint address value. + lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception + // occurred. + lldb::addr_t real_addr; // Address value that should cause target to stop. + uint32_t control; // Breakpoint/watchpoint control value. + }; + + std::array<struct DREG, 16> m_hbp_regs; // hardware breakpoints + std::array<struct DREG, 16> m_hwp_regs; // hardware watchpoints + + uint32_t m_max_hbp_supported; + uint32_t m_max_hwp_supported; + + virtual llvm::Error ReadHardwareDebugInfo() = 0; + virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0; +}; + +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextDBReg_arm64_h diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp new file mode 100644 index 000000000000..56c1757ee89d --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp @@ -0,0 +1,276 @@ +//===-- NativeRegisterContextDBReg_x86.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 "NativeRegisterContextDBReg_x86.h" + +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" + +using namespace lldb_private; + +// Returns mask/value for status bit of wp_index in DR6 +static inline uint64_t GetStatusBit(uint32_t wp_index) { + // DR6: ...BBBB + // 3210 <- status bits for bp./wp. i; 1 if hit + return 1 << wp_index; +} + +// Returns mask/value for global enable bit of wp_index in DR7 +static inline uint64_t GetEnableBit(uint32_t wp_index) { + // DR7: ...GLGLGLGL + // 33221100 <- global/local enable for bp./wp.; 1 if enabled + // we use global bits because NetBSD kernel does not preserve local + // bits reliably; Linux seems fine with either + return 1 << (2 * wp_index + 1); +} + +// Returns mask for both enable bits of wp_index in DR7 +static inline uint64_t GetBothEnableBitMask(uint32_t wp_index) { + // DR7: ...GLGLGLGL + // 33221100 <- global/local enable for bp./wp.; 1 if enabled + return 3 << (2 * wp_index + 1); +} + +// Returns value for type bits of wp_index in DR7 +static inline uint64_t GetWatchTypeBits(uint32_t watch_flags, + uint32_t wp_index) { + // DR7: + // bit: 3322222222221111... + // 1098765432109876... + // val: SSTTSSTTSSTTSSTT... + // wp.: 3333222211110000... + // + // where T - type is 01 for write, 11 for r/w + return watch_flags << (16 + 4 * wp_index); +} + +// Returns value for size bits of wp_index in DR7 +static inline uint64_t GetWatchSizeBits(uint32_t size, uint32_t wp_index) { + // DR7: + // bit: 3322222222221111... + // 1098765432109876... + // val: SSTTSSTTSSTTSSTT... + // wp.: 3333222211110000... + // + // where S - size is: + // 00 for 1 byte + // 01 for 2 bytes + // 10 for 8 bytes + // 11 for 4 bytes + return (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); +} + +// Returns bitmask for all bits controlling wp_index in DR7 +static inline uint64_t GetWatchControlBitmask(uint32_t wp_index) { + // DR7: + // bit: 33222222222211111111110000000000 + // 10987654321098765432109876543210 + // val: SSTTSSTTSSTTSSTTxxxxxxGLGLGLGLGL + // wp.: 3333222211110000xxxxxxEE33221100 + return GetBothEnableBitMask(wp_index) | (0xF << (16 + 4 * wp_index)); +} + +// Bit mask for control bits regarding all watchpoints. +static constexpr uint64_t watchpoint_all_control_bit_mask = 0xFFFF00FF; + +const RegisterInfo *NativeRegisterContextDBReg_x86::GetDR(int num) const { + assert(num >= 0 && num <= 7); + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + return GetRegisterInfoAtIndex(lldb_dr0_i386 + num); + case llvm::Triple::x86_64: + return GetRegisterInfoAtIndex(lldb_dr0_x86_64 + num); + default: + llvm_unreachable("Unhandled target architecture."); + } +} + +Status NativeRegisterContextDBReg_x86::IsWatchpointHit(uint32_t wp_index, + bool &is_hit) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + RegisterValue dr6; + Status error = ReadRegister(GetDR(6), dr6); + if (error.Fail()) + is_hit = false; + else + is_hit = dr6.GetAsUInt64() & GetStatusBit(wp_index); + + return error; +} + +Status +NativeRegisterContextDBReg_x86::GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) { + uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); + for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { + bool is_hit; + Status error = IsWatchpointHit(wp_index, is_hit); + if (error.Fail()) { + wp_index = LLDB_INVALID_INDEX32; + return error; + } else if (is_hit) { + return error; + } + } + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +Status NativeRegisterContextDBReg_x86::IsWatchpointVacant(uint32_t wp_index, + bool &is_vacant) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + RegisterValue dr7; + Status error = ReadRegister(GetDR(7), dr7); + if (error.Fail()) + is_vacant = false; + else + is_vacant = !(dr7.GetAsUInt64() & GetEnableBit(wp_index)); + + return error; +} + +Status NativeRegisterContextDBReg_x86::SetHardwareWatchpointWithIndex( + lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { + + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + // Read only watchpoints aren't supported on x86_64. Fall back to read/write + // waitchpoints instead. + // TODO: Add logic to detect when a write happens and ignore that watchpoint + // hit. + if (watch_flags == 2) + watch_flags = 3; + + if (watch_flags != 1 && watch_flags != 3) + return Status("Invalid read/write bits for watchpoint"); + if (size != 1 && size != 2 && size != 4 && size != 8) + return Status("Invalid size for watchpoint"); + + bool is_vacant; + Status error = IsWatchpointVacant(wp_index, is_vacant); + if (error.Fail()) + return error; + if (!is_vacant) + return Status("Watchpoint index not vacant"); + + RegisterValue dr7, drN; + error = ReadRegister(GetDR(7), dr7); + if (error.Fail()) + return error; + error = ReadRegister(GetDR(wp_index), drN); + if (error.Fail()) + return error; + + uint64_t control_bits = dr7.GetAsUInt64() & ~GetWatchControlBitmask(wp_index); + control_bits |= GetEnableBit(wp_index) | + GetWatchTypeBits(watch_flags, wp_index) | + GetWatchSizeBits(size, wp_index); + + // Clear dr6 if address or bits changed (i.e. we're not reenabling the same + // watchpoint). This can not be done when clearing watchpoints since + // the gdb-remote protocol repeatedly clears and readds watchpoints on all + // program threads, effectively clearing pending events on NetBSD. + // NB: enable bits in dr7 are always 0 here since we're (re)adding it + if (drN.GetAsUInt64() != addr || + (dr7.GetAsUInt64() & GetWatchControlBitmask(wp_index)) != + (GetWatchTypeBits(watch_flags, wp_index) | + GetWatchSizeBits(size, wp_index))) { + ClearWatchpointHit(wp_index); + + // We skip update to drN if neither address nor mode changed. + error = WriteRegister(GetDR(wp_index), RegisterValue(addr)); + if (error.Fail()) + return error; + } + + error = WriteRegister(GetDR(7), RegisterValue(control_bits)); + if (error.Fail()) + return error; + + return error; +} + +bool NativeRegisterContextDBReg_x86::ClearHardwareWatchpoint( + uint32_t wp_index) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return false; + + RegisterValue dr7; + Status error = ReadRegister(GetDR(7), dr7); + if (error.Fail()) + return false; + + return WriteRegister(GetDR(7), RegisterValue(dr7.GetAsUInt64() & + ~GetBothEnableBitMask(wp_index))) + .Success(); +} + +Status NativeRegisterContextDBReg_x86::ClearWatchpointHit(uint32_t wp_index) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + RegisterValue dr6; + Status error = ReadRegister(GetDR(6), dr6); + if (error.Fail()) + return error; + + return WriteRegister( + GetDR(6), RegisterValue(dr6.GetAsUInt64() & ~GetStatusBit(wp_index))); +} + +Status NativeRegisterContextDBReg_x86::ClearAllHardwareWatchpoints() { + RegisterValue dr7; + Status error = ReadRegister(GetDR(7), dr7); + if (error.Fail()) + return error; + return WriteRegister( + GetDR(7), + RegisterValue(dr7.GetAsUInt64() & ~watchpoint_all_control_bit_mask)); +} + +uint32_t NativeRegisterContextDBReg_x86::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) { + bool is_vacant; + Status error = IsWatchpointVacant(wp_index, is_vacant); + if (is_vacant) { + error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); + if (error.Success()) + return wp_index; + } + if (error.Fail() && log) { + LLDB_LOGF(log, "NativeRegisterContextDBReg_x86::%s Error: %s", + __FUNCTION__, error.AsCString()); + } + } + return LLDB_INVALID_INDEX32; +} + +lldb::addr_t +NativeRegisterContextDBReg_x86::GetWatchpointAddress(uint32_t wp_index) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return LLDB_INVALID_ADDRESS; + RegisterValue drN; + if (ReadRegister(GetDR(wp_index), drN).Fail()) + return LLDB_INVALID_ADDRESS; + return drN.GetAsUInt64(); +} + +uint32_t NativeRegisterContextDBReg_x86::NumSupportedHardwareWatchpoints() { + // Available debug address registers: dr0, dr1, dr2, dr3 + return 4; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h new file mode 100644 index 000000000000..c0c6ce29eab5 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h @@ -0,0 +1,48 @@ +//===-- NativeRegisterContextDBReg_x86.h ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeRegisterContextDBReg_x86_h +#define lldb_NativeRegisterContextDBReg_x86_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" + +namespace lldb_private { + +class NativeRegisterContextDBReg_x86 + : public virtual NativeRegisterContextRegisterInfo { +public: + Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; + + bool ClearHardwareWatchpoint(uint32_t wp_index) override; + + Status ClearWatchpointHit(uint32_t wp_index) override; + + Status ClearAllHardwareWatchpoints() override; + + Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, + uint32_t watch_flags, + uint32_t wp_index); + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t NumSupportedHardwareWatchpoints() override; + + const RegisterInfo *GetDR(int num) const; +}; + +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextDBReg_x86_h diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp index 10d346a3cb7e..acebe9d53568 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp @@ -35,7 +35,7 @@ struct GPR { uint32_t gs; }; -struct dbreg { +struct DBG { uint32_t dr[8]; /* debug registers */ /* Index 0-3: debug address registers */ /* Index 4-5: reserved */ @@ -48,10 +48,13 @@ using FPR_i386 = FXSAVE; struct UserArea { GPR gpr; FPR_i386 i387; + DBG dbg; }; #define DR_SIZE sizeof(uint32_t) -#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(dbreg, dr[reg_index])) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, dbg) + \ + LLVM_EXTENSION offsetof(DBG, dr[reg_index])) // Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. #define DECLARE_REGISTER_INFOS_I386_STRUCT diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp index c1f390ade9b9..e0f3971c6e27 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp @@ -59,7 +59,9 @@ struct UserArea { DBG dbg; }; -#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(DBG, dr[reg_index])) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, dbg) + \ + LLVM_EXTENSION offsetof(DBG, dr[reg_index])) // Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 // structure. diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h index e7c180dbdd27..1ceca65c97c3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h @@ -19,21 +19,21 @@ public: virtual ~RegisterContextMach_arm(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg); + int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; - int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg); + int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h index 09966be60c92..da5411eb2de2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h @@ -19,17 +19,17 @@ public: virtual ~RegisterContextMach_i386(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h index 2a8a2cca2f8a..c131c8282bd2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h @@ -20,17 +20,17 @@ public: virtual ~RegisterContextMach_x86_64(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp index 617893b6b3b0..97a760396ba9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp @@ -25,88 +25,25 @@ using namespace lldb; using namespace lldb_private; -// arm general purpose registers. -const uint32_t g_gpr_regnums_arm[] = { - gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm, - gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm, - gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm, - gpr_pc_arm, gpr_cpsr_arm, - LLDB_INVALID_REGNUM // register sets need to end with this flag - -}; -static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == - k_num_gpr_registers_arm, - "g_gpr_regnums_arm has wrong number of register infos"); - -// arm floating point registers. -static const uint32_t g_fpu_regnums_arm[] = { - fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm, - fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm, - fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm, - fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm, - fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm, - fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm, - fpu_s30_arm, fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm, fpu_d1_arm, - fpu_d2_arm, fpu_d3_arm, fpu_d4_arm, fpu_d5_arm, fpu_d6_arm, - fpu_d7_arm, fpu_d8_arm, fpu_d9_arm, fpu_d10_arm, fpu_d11_arm, - fpu_d12_arm, fpu_d13_arm, fpu_d14_arm, fpu_d15_arm, fpu_d16_arm, - fpu_d17_arm, fpu_d18_arm, fpu_d19_arm, fpu_d20_arm, fpu_d21_arm, - fpu_d22_arm, fpu_d23_arm, fpu_d24_arm, fpu_d25_arm, fpu_d26_arm, - fpu_d27_arm, fpu_d28_arm, fpu_d29_arm, fpu_d30_arm, fpu_d31_arm, - fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm, - fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm, - fpu_q10_arm, fpu_q11_arm, fpu_q12_arm, fpu_q13_arm, fpu_q14_arm, - fpu_q15_arm, - LLDB_INVALID_REGNUM // register sets need to end with this flag - -}; -static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == - k_num_fpr_registers_arm, - "g_fpu_regnums_arm has wrong number of register infos"); - -// Number of register sets provided by this context. -enum { k_num_register_sets = 2 }; - -// Register sets for arm. -static const lldb_private::RegisterSet g_reg_sets_arm[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_arm, - g_gpr_regnums_arm}, - {"Floating Point Registers", "fpu", k_num_fpr_registers_arm, - g_fpu_regnums_arm}}; - bool RegisterContextPOSIX_arm::IsGPR(unsigned reg) { - return reg <= m_reg_info.last_gpr; // GPR's come first. + if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm::GPRegSet) + return true; + return false; } bool RegisterContextPOSIX_arm::IsFPR(unsigned reg) { - return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); + if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm::FPRegSet) + return true; + return false; } RegisterContextPOSIX_arm::RegisterContextPOSIX_arm( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : lldb_private::RegisterContext(thread, concrete_frame_idx) { - m_register_info_up.reset(register_info); - - switch (register_info->m_target_arch.GetMachine()) { - case llvm::Triple::arm: - m_reg_info.num_registers = k_num_registers_arm; - m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; - m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; - m_reg_info.last_gpr = k_last_gpr_arm; - m_reg_info.first_fpr = k_first_fpr_arm; - m_reg_info.last_fpr = k_last_fpr_arm; - m_reg_info.first_fpr_v = fpu_s0_arm; - m_reg_info.last_fpr_v = fpu_s31_arm; - m_reg_info.gpr_flags = gpr_cpsr_arm; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } - - ::memset(&m_fpr, 0, sizeof m_fpr); -} + lldb_private::Thread &thread, + std::unique_ptr<RegisterInfoPOSIX_arm> register_info) + : lldb_private::RegisterContext(thread, 0), + m_register_info_up(std::move(register_info)) {} RegisterContextPOSIX_arm::~RegisterContextPOSIX_arm() {} @@ -115,19 +52,15 @@ void RegisterContextPOSIX_arm::Invalidate() {} void RegisterContextPOSIX_arm::InvalidateAllRegisters() {} unsigned RegisterContextPOSIX_arm::GetRegisterOffset(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register number."); - return GetRegisterInfo()[reg].byte_offset; + return m_register_info_up->GetRegisterInfo()[reg].byte_offset; } unsigned RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register number."); - return GetRegisterInfo()[reg].byte_size; + return m_register_info_up->GetRegisterInfo()[reg].byte_size; } size_t RegisterContextPOSIX_arm::GetRegisterCount() { - size_t num_registers = - m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers; - return num_registers; + return m_register_info_up->GetRegisterCount(); } size_t RegisterContextPOSIX_arm::GetGPRSize() { @@ -143,41 +76,23 @@ const lldb_private::RegisterInfo *RegisterContextPOSIX_arm::GetRegisterInfo() { const lldb_private::RegisterInfo * RegisterContextPOSIX_arm::GetRegisterInfoAtIndex(size_t reg) { - if (reg < m_reg_info.num_registers) + if (reg < GetRegisterCount()) return &GetRegisterInfo()[reg]; - else - return nullptr; + + return nullptr; } size_t RegisterContextPOSIX_arm::GetRegisterSetCount() { - size_t sets = 0; - for (size_t set = 0; set < k_num_register_sets; ++set) { - if (IsRegisterSetAvailable(set)) - ++sets; - } - - return sets; + return m_register_info_up->GetRegisterSetCount(); } const lldb_private::RegisterSet * RegisterContextPOSIX_arm::GetRegisterSet(size_t set) { - if (IsRegisterSetAvailable(set)) { - switch (m_register_info_up->m_target_arch.GetMachine()) { - case llvm::Triple::arm: - return &g_reg_sets_arm[set]; - default: - assert(false && "Unhandled target architecture."); - return nullptr; - } - } - return nullptr; + return m_register_info_up->GetRegisterSet(set); } const char *RegisterContextPOSIX_arm::GetRegisterName(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register offset."); - return GetRegisterInfo()[reg].name; -} - -bool RegisterContextPOSIX_arm::IsRegisterSetAvailable(size_t set_index) { - return set_index < k_num_register_sets; + if (reg < GetRegisterCount()) + return GetRegisterInfo()[reg].name; + return nullptr; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h index d6967f05ed48..099c37d46f49 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h @@ -10,17 +10,15 @@ #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H #include "RegisterInfoInterface.h" -#include "lldb-arm-register-enums.h" +#include "RegisterInfoPOSIX_arm.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - class RegisterContextPOSIX_arm : public lldb_private::RegisterContext { public: - RegisterContextPOSIX_arm(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); + RegisterContextPOSIX_arm( + lldb_private::Thread &thread, + std::unique_ptr<RegisterInfoPOSIX_arm> register_info); ~RegisterContextPOSIX_arm() override; @@ -45,46 +43,7 @@ public: const char *GetRegisterName(unsigned reg); protected: - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - - uint32_t first_fpr_v; - uint32_t last_fpr_v; - - uint32_t gpr_flags; - }; - - struct QReg { - uint8_t bytes[16]; - }; - - struct FPU { - union { - uint32_t s[32]; - uint64_t d[32]; - QReg q[16]; // the 128-bit NEON registers - } floats; - uint32_t fpscr; - }; - - uint32_t m_gpr_arm[lldb_private::k_num_gpr_registers_arm]; // 32-bit general - // purpose - // registers. - RegInfo m_reg_info; - struct RegisterContextPOSIX_arm::FPU - m_fpr; // floating-point registers including extended register sets. - std::unique_ptr<lldb_private::RegisterInfoInterface> - m_register_info_up; // Register Info Interface (FreeBSD or Linux) - - // Determines if an extended register set is supported on the processor - // running the inferior process. - virtual bool IsRegisterSetAvailable(size_t set_index); + std::unique_ptr<RegisterInfoPOSIX_arm> m_register_info_up; virtual const lldb_private::RegisterInfo *GetRegisterInfo(); @@ -92,6 +51,8 @@ protected: bool IsFPR(unsigned reg); + size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm::FPU); } + virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool WriteGPR() = 0; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp index 8ef587f13e3a..3f52501c35f3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -39,14 +39,18 @@ bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg) { return false; } +bool RegisterContextPOSIX_arm64::IsSVE(unsigned reg) const { + if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm64::SVERegSet) + return true; + return false; +} + RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64( lldb_private::Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info) : lldb_private::RegisterContext(thread, 0), - m_register_info_up(std::move(register_info)) { - - ::memset(&m_fpr, 0, sizeof m_fpr); -} + m_register_info_up(std::move(register_info)) {} RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64() {} @@ -82,8 +86,8 @@ const lldb_private::RegisterInfo * RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg) { if (reg < GetRegisterCount()) return &GetRegisterInfo()[reg]; - else - return nullptr; + + return nullptr; } size_t RegisterContextPOSIX_arm64::GetRegisterSetCount() { diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h index c2d5aee7f73c..a3f07bb2823b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -11,12 +11,9 @@ #include "RegisterInfoInterface.h" #include "RegisterInfoPOSIX_arm64.h" -#include "lldb-arm64-register-enums.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - class RegisterContextPOSIX_arm64 : public lldb_private::RegisterContext { public: RegisterContextPOSIX_arm64( @@ -46,13 +43,6 @@ public: const char *GetRegisterName(unsigned reg); protected: - uint64_t m_gpr_arm64[lldb_private::k_num_gpr_registers_arm64]; // 64-bit - // general - // purpose - // registers. - - struct RegisterInfoPOSIX_arm64::FPU - m_fpr; // floating-point registers including extended register sets. std::unique_ptr<RegisterInfoPOSIX_arm64> m_register_info_up; virtual const lldb_private::RegisterInfo *GetRegisterInfo(); @@ -63,6 +53,23 @@ protected: size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm64::FPU); } + bool IsSVE(unsigned reg) const; + + bool IsSVEZ(unsigned reg) const { return m_register_info_up->IsSVEZReg(reg); } + bool IsSVEP(unsigned reg) const { return m_register_info_up->IsSVEPReg(reg); } + bool IsSVEVG(unsigned reg) const { + return m_register_info_up->IsSVERegVG(reg); + } + + uint32_t GetRegNumSVEZ0() const { + return m_register_info_up->GetRegNumSVEZ0(); + } + uint32_t GetRegNumSVEFFR() const { + return m_register_info_up->GetRegNumSVEFFR(); + } + uint32_t GetRegNumFPCR() const { return m_register_info_up->GetRegNumFPCR(); } + uint32_t GetRegNumFPSR() const { return m_register_info_up->GetRegNumFPSR(); } + virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool WriteGPR() = 0; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h index 1843a2a6aff3..b66dc3f44524 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h @@ -14,10 +14,6 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -using namespace lldb_private; - -class ProcessMonitor; - class RegisterContextPOSIX_mips64 : public lldb_private::RegisterContext { public: diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h index e2c33461c8f1..5dd8c890da6e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h @@ -14,8 +14,6 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - // Internal codes for all powerpc registers. enum { k_first_gpr_powerpc, diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h index 7df732d13ffa..7027af04f0bb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h @@ -15,8 +15,6 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - class RegisterContextPOSIX_s390x : public lldb_private::RegisterContext { public: RegisterContextPOSIX_s390x( diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index ac271a90d6a1..2c7f63503d7c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -119,20 +119,21 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - "g_gpr_regnums_x86_64 has wrong number of register infos"); static const uint32_t g_lldb_regnums_x86_64[] = { - lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, - lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, - lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64, - lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64, - lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64, - lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64, - lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64, - lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64, - lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64, - lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, - lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, - lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64, - lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64, - lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64, + lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64, + lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64, + lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64, + lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64, + lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64, + lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64, + lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64, + lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64, + lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64, + lldb_xmm14_x86_64, lldb_xmm15_x86_64, LLDB_INVALID_REGNUM // Register sets must be terminated with // LLDB_INVALID_REGNUM. }; @@ -275,6 +276,84 @@ uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = { lldb_r15_x86_64, lldb_r15d_x86_64, lldb_r15w_x86_64, lldb_r15l_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_fip[] = {lldb_fip_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_fdp[] = {lldb_fdp_x86_64, + LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_fip[] = { + lldb_fip_x86_64, lldb_fioff_x86_64, lldb_fiseg_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_fdp[] = { + lldb_fdp_x86_64, lldb_fooff_x86_64, lldb_foseg_x86_64, LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_contained_st0_32[] = {lldb_st0_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st1_32[] = {lldb_st1_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st2_32[] = {lldb_st2_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st3_32[] = {lldb_st3_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st4_32[] = {lldb_st4_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st5_32[] = {lldb_st5_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st6_32[] = {lldb_st6_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st7_32[] = {lldb_st7_i386, + LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_st0_32[] = { + lldb_st0_i386, lldb_mm0_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st1_32[] = { + lldb_st1_i386, lldb_mm1_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st2_32[] = { + lldb_st2_i386, lldb_mm2_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st3_32[] = { + lldb_st3_i386, lldb_mm3_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st4_32[] = { + lldb_st4_i386, lldb_mm4_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st5_32[] = { + lldb_st5_i386, lldb_mm5_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st6_32[] = { + lldb_st6_i386, lldb_mm6_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st7_32[] = { + lldb_st7_i386, lldb_mm7_i386, LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_contained_st0_64[] = {lldb_st0_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st1_64[] = {lldb_st1_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st2_64[] = {lldb_st2_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st3_64[] = {lldb_st3_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st4_64[] = {lldb_st4_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st5_64[] = {lldb_st5_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st6_64[] = {lldb_st6_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st7_64[] = {lldb_st7_x86_64, + LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_st0_64[] = { + lldb_st0_x86_64, lldb_mm0_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st1_64[] = { + lldb_st1_x86_64, lldb_mm1_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st2_64[] = { + lldb_st2_x86_64, lldb_mm2_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st3_64[] = { + lldb_st3_x86_64, lldb_mm3_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st4_64[] = { + lldb_st4_x86_64, lldb_mm4_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st5_64[] = { + lldb_st5_x86_64, lldb_mm5_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st6_64[] = { + lldb_st6_x86_64, lldb_mm6_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st7_64[] = { + lldb_st7_x86_64, lldb_mm7_x86_64, LLDB_INVALID_REGNUM}; + // Number of register sets provided by this context. enum { k_num_extended_register_sets = 1, k_num_register_sets = 3 }; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h index c4886ae618a2..d6672835b4a8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h @@ -15,8 +15,6 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - class RegisterContextPOSIX_x86 : public lldb_private::RegisterContext { public: RegisterContextPOSIX_x86(lldb_private::Thread &thread, @@ -108,6 +106,48 @@ public: static uint32_t g_invalidate_r14[]; static uint32_t g_invalidate_r15[]; + static uint32_t g_contained_fip[]; + static uint32_t g_contained_fdp[]; + + static uint32_t g_invalidate_fip[]; + static uint32_t g_invalidate_fdp[]; + + static uint32_t g_contained_st0_32[]; + static uint32_t g_contained_st1_32[]; + static uint32_t g_contained_st2_32[]; + static uint32_t g_contained_st3_32[]; + static uint32_t g_contained_st4_32[]; + static uint32_t g_contained_st5_32[]; + static uint32_t g_contained_st6_32[]; + static uint32_t g_contained_st7_32[]; + + static uint32_t g_invalidate_st0_32[]; + static uint32_t g_invalidate_st1_32[]; + static uint32_t g_invalidate_st2_32[]; + static uint32_t g_invalidate_st3_32[]; + static uint32_t g_invalidate_st4_32[]; + static uint32_t g_invalidate_st5_32[]; + static uint32_t g_invalidate_st6_32[]; + static uint32_t g_invalidate_st7_32[]; + + static uint32_t g_contained_st0_64[]; + static uint32_t g_contained_st1_64[]; + static uint32_t g_contained_st2_64[]; + static uint32_t g_contained_st3_64[]; + static uint32_t g_contained_st4_64[]; + static uint32_t g_contained_st5_64[]; + static uint32_t g_contained_st6_64[]; + static uint32_t g_contained_st7_64[]; + + static uint32_t g_invalidate_st0_64[]; + static uint32_t g_invalidate_st1_64[]; + static uint32_t g_invalidate_st2_64[]; + static uint32_t g_invalidate_st3_64[]; + static uint32_t g_invalidate_st4_64[]; + static uint32_t g_invalidate_st5_64[]; + static uint32_t g_invalidate_st6_64[]; + static uint32_t g_invalidate_st7_64[]; + protected: struct RegInfo { uint32_t num_registers; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp new file mode 100644 index 000000000000..b21c72bd9621 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp @@ -0,0 +1,58 @@ +//===-- RegisterContext_x86.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "RegisterContext_x86.h" + +using namespace lldb_private; + +// Convert the 8-bit abridged FPU Tag Word (as found in FXSAVE) to the full +// 16-bit FPU Tag Word (as found in FSAVE, and used by gdb protocol). This +// requires knowing the values of the ST(i) registers and the FPU Status Word. +uint16_t lldb_private::AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw, + llvm::ArrayRef<MMSReg> st_regs) { + // Tag word is using internal FPU register numbering rather than ST(i). + // Mapping to ST(i): i = FPU regno - TOP (Status Word, bits 11:13). + // Here we start with FPU reg 7 and go down. + int st = 7 - ((sw >> 11) & 7); + uint16_t tw = 0; + for (uint8_t mask = 0x80; mask != 0; mask >>= 1) { + tw <<= 2; + if (abridged_tw & mask) { + // The register is non-empty, so we need to check the value of ST(i). + uint16_t exp = + st_regs[st].comp.sign_exp & 0x7fff; // Discard the sign bit. + if (exp == 0) { + if (st_regs[st].comp.mantissa == 0) + tw |= 1; // Zero + else + tw |= 2; // Denormal + } else if (exp == 0x7fff) + tw |= 2; // Infinity or NaN + // 0 if normal number + } else + tw |= 3; // Empty register + + // Rotate ST down. + st = (st - 1) & 7; + } + + return tw; +} + +// Convert the 16-bit FPU Tag Word to the abridged 8-bit value, to be written +// into FXSAVE. +uint8_t lldb_private::FullToAbridgedTagWord(uint16_t tw) { + uint8_t abridged_tw = 0; + for (uint16_t mask = 0xc000; mask != 0; mask >>= 2) { + abridged_tw <<= 1; + // full TW uses 11 for empty registers, aTW uses 0 + if ((tw & mask) != mask) + abridged_tw |= 1; + } + return abridged_tw; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h index 27a1bad4d53f..76e004ce0ceb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h @@ -12,6 +12,7 @@ #include <cstddef> #include <cstdint> +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitmaskEnum.h" #include "llvm/Support/Compiler.h" @@ -239,10 +240,23 @@ enum { // Generic floating-point registers +LLVM_PACKED_START +struct MMSRegComp { + uint64_t mantissa; + uint16_t sign_exp; +}; + struct MMSReg { - uint8_t bytes[10]; + union { + uint8_t bytes[10]; + MMSRegComp comp; + }; uint8_t pad[6]; }; +LLVM_PACKED_END + +static_assert(sizeof(MMSRegComp) == 10, "MMSRegComp is not 10 bytes of size"); +static_assert(sizeof(MMSReg) == 16, "MMSReg is not 16 bytes of size"); struct XMMReg { uint8_t bytes[16]; // 128-bits for each XMM register @@ -369,6 +383,10 @@ inline void YMMToXState(const YMMReg& input, void* xmm_bytes, void* ymmh_bytes) ::memcpy(ymmh_bytes, input.bytes + sizeof(XMMReg), sizeof(YMMHReg)); } +uint16_t AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw, + llvm::ArrayRef<MMSReg> st_regs); +uint8_t FullToAbridgedTagWord(uint16_t tw); + } // namespace lldb_private #endif diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp index 8fc4d5282b06..17b96f944cda 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp @@ -71,9 +71,87 @@ GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { } } +// Number of register sets provided by this context. +enum { + k_num_gpr_registers = gpr_cpsr - gpr_r0 + 1, + k_num_fpr_registers = fpu_q15 - fpu_s0 + 1, + k_num_register_sets = 2 +}; + +// arm general purpose registers. +static const uint32_t g_gpr_regnums_arm[] = { + gpr_r0, gpr_r1, + gpr_r2, gpr_r3, + gpr_r4, gpr_r5, + gpr_r6, gpr_r7, + gpr_r8, gpr_r9, + gpr_r10, gpr_r11, + gpr_r12, gpr_sp, + gpr_lr, gpr_pc, + gpr_cpsr, LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == + k_num_gpr_registers, + "g_gpr_regnums_arm has wrong number of register infos"); + +// arm floating point registers. +static const uint32_t g_fpu_regnums_arm[] = { + fpu_s0, fpu_s1, + fpu_s2, fpu_s3, + fpu_s4, fpu_s5, + fpu_s6, fpu_s7, + fpu_s8, fpu_s9, + fpu_s10, fpu_s11, + fpu_s12, fpu_s13, + fpu_s14, fpu_s15, + fpu_s16, fpu_s17, + fpu_s18, fpu_s19, + fpu_s20, fpu_s21, + fpu_s22, fpu_s23, + fpu_s24, fpu_s25, + fpu_s26, fpu_s27, + fpu_s28, fpu_s29, + fpu_s30, fpu_s31, + fpu_fpscr, fpu_d0, + fpu_d1, fpu_d2, + fpu_d3, fpu_d4, + fpu_d5, fpu_d6, + fpu_d7, fpu_d8, + fpu_d9, fpu_d10, + fpu_d11, fpu_d12, + fpu_d13, fpu_d14, + fpu_d15, fpu_d16, + fpu_d17, fpu_d18, + fpu_d19, fpu_d20, + fpu_d21, fpu_d22, + fpu_d23, fpu_d24, + fpu_d25, fpu_d26, + fpu_d27, fpu_d28, + fpu_d29, fpu_d30, + fpu_d31, fpu_q0, + fpu_q1, fpu_q2, + fpu_q3, fpu_q4, + fpu_q5, fpu_q6, + fpu_q7, fpu_q8, + fpu_q9, fpu_q10, + fpu_q11, fpu_q12, + fpu_q13, fpu_q14, + fpu_q15, LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == + k_num_fpr_registers, + "g_fpu_regnums_arm has wrong number of register infos"); + +// Register sets for arm. +static const RegisterSet g_reg_sets_arm[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers, + g_gpr_regnums_arm}, + {"Floating Point Registers", "fpu", k_num_fpr_registers, + g_fpu_regnums_arm}}; + RegisterInfoPOSIX_arm::RegisterInfoPOSIX_arm( const lldb_private::ArchSpec &target_arch) - : lldb_private::RegisterInfoInterface(target_arch), + : lldb_private::RegisterInfoAndSetInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), m_register_info_count(GetRegisterInfoCount(target_arch)) {} @@ -81,11 +159,35 @@ size_t RegisterInfoPOSIX_arm::GetGPRSize() const { return sizeof(struct RegisterInfoPOSIX_arm::GPR); } +size_t RegisterInfoPOSIX_arm::GetFPRSize() const { + return sizeof(struct RegisterInfoPOSIX_arm::FPU); +} + const lldb_private::RegisterInfo * RegisterInfoPOSIX_arm::GetRegisterInfo() const { return m_register_info_p; } +size_t RegisterInfoPOSIX_arm::GetRegisterSetCount() const { + return k_num_register_sets; +} + +size_t RegisterInfoPOSIX_arm::GetRegisterSetFromRegisterIndex( + uint32_t reg_index) const { + if (reg_index <= gpr_cpsr) + return GPRegSet; + if (reg_index <= fpu_q15) + return FPRegSet; + return LLDB_INVALID_REGNUM; +} + +const lldb_private::RegisterSet * +RegisterInfoPOSIX_arm::GetRegisterSet(size_t set_index) const { + if (set_index < GetRegisterSetCount()) + return &g_reg_sets_arm[set_index]; + return nullptr; +} + uint32_t RegisterInfoPOSIX_arm::GetRegisterCount() const { return m_register_info_count; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h index 1cf896e3decf..db155d757ca8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h @@ -9,12 +9,14 @@ #ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H -#include "RegisterInfoInterface.h" +#include "RegisterInfoAndSetInterface.h" #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" -class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoInterface { +class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoAndSetInterface { public: + enum { GPRegSet = 0, FPRegSet}; + struct GPR { uint32_t r[16]; // R0-R15 uint32_t cpsr; // CPSR @@ -49,10 +51,19 @@ public: size_t GetGPRSize() const override; + size_t GetFPRSize() const override; + const lldb_private::RegisterInfo *GetRegisterInfo() const override; uint32_t GetRegisterCount() const override; + const lldb_private::RegisterSet * + GetRegisterSet(size_t reg_set) const override; + + size_t GetRegisterSetCount() const override; + + size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override; + private: const lldb_private::RegisterInfo *m_register_info_p; uint32_t m_register_info_count; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp index 4537cee42ad9..515c9f44e1e2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -25,6 +25,24 @@ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::FPU, reg) + \ sizeof(RegisterInfoPOSIX_arm64::GPR)) +// This information is based on AArch64 with SVE architecture reference manual. +// AArch64 with SVE has 32 Z and 16 P vector registers. There is also an FFR +// (First Fault) register and a VG (Vector Granule) pseudo register. + +// SVE 16-byte quad word is the basic unit of expansion in vector length. +#define SVE_QUAD_WORD_BYTES 16 + +// Vector length is the multiplier which decides the no of quad words, +// (multiples of 128-bits or 16-bytes) present in a Z register. Vector length +// is decided during execution and can change at runtime. SVE AArch64 register +// infos have modes one for each valid value of vector length. A change in +// vector length requires register context to update sizes of SVE Z, P and FFR. +// Also register context needs to update byte offsets of all registers affected +// by the change in vector length. +#define SVE_REGS_DEFAULT_OFFSET_LINUX sizeof(RegisterInfoPOSIX_arm64::GPR) + +#define SVE_OFFSET_VG SVE_REGS_DEFAULT_OFFSET_LINUX + #define EXC_OFFSET_NAME(reg) \ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::EXC, reg) + \ sizeof(RegisterInfoPOSIX_arm64::GPR) + \ @@ -51,6 +69,7 @@ // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. #define DECLARE_REGISTER_INFOS_ARM64_STRUCT #include "RegisterInfos_arm64.h" +#include "RegisterInfos_arm64_sve.h" #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT static const lldb_private::RegisterInfo * @@ -69,7 +88,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { enum { k_num_gpr_registers = gpr_w28 - gpr_x0 + 1, k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1, - k_num_register_sets = 2 + k_num_sve_registers = sve_ffr - sve_vg + 1, + k_num_register_sets = 3 }; // ARM64 general purpose registers. @@ -133,13 +153,38 @@ static const uint32_t g_fpu_regnums_arm64[] = { static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers, "g_fpu_regnums_arm64 has wrong number of register infos"); -// clang-format on + +// ARM64 SVE registers. +static const uint32_t g_sve_regnums_arm64[] = { + sve_vg, sve_z0, sve_z1, + sve_z2, sve_z3, sve_z4, + sve_z5, sve_z6, sve_z7, + sve_z8, sve_z9, sve_z10, + sve_z11, sve_z12, sve_z13, + sve_z14, sve_z15, sve_z16, + sve_z17, sve_z18, sve_z19, + sve_z20, sve_z21, sve_z22, + sve_z23, sve_z24, sve_z25, + sve_z26, sve_z27, sve_z28, + sve_z29, sve_z30, sve_z31, + sve_p0, sve_p1, sve_p2, + sve_p3, sve_p4, sve_p5, + sve_p6, sve_p7, sve_p8, + sve_p9, sve_p10, sve_p11, + sve_p12, sve_p13, sve_p14, + sve_p15, sve_ffr, LLDB_INVALID_REGNUM}; +static_assert(((sizeof g_sve_regnums_arm64 / sizeof g_sve_regnums_arm64[0]) - + 1) == k_num_sve_registers, + "g_sve_regnums_arm64 has wrong number of register infos"); + // Register sets for ARM64. static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = { {"General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums_arm64}, {"Floating Point Registers", "fpu", k_num_fpr_registers, - g_fpu_regnums_arm64}}; + g_fpu_regnums_arm64}, + {"Scalable Vector Extension Registers", "sve", k_num_sve_registers, + g_sve_regnums_arm64}}; static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { @@ -159,25 +204,13 @@ RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( : lldb_private::RegisterInfoAndSetInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), m_register_info_count(GetRegisterInfoCount(target_arch)) { - - switch (target_arch.GetMachine()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - num_registers = k_num_gpr_registers + k_num_fpr_registers; - num_gpr_registers = k_num_gpr_registers; - num_fpr_registers = k_num_fpr_registers; - last_gpr = gpr_w28; - first_fpr = fpu_v0; - last_fpr = fpu_fpcr; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } } uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const { - return num_gpr_registers + num_fpr_registers; + if (IsSVEEnabled()) + return k_num_gpr_registers + k_num_fpr_registers + k_num_sve_registers; + + return k_num_gpr_registers + k_num_fpr_registers; } size_t RegisterInfoPOSIX_arm64::GetGPRSize() const { @@ -194,22 +227,120 @@ RegisterInfoPOSIX_arm64::GetRegisterInfo() const { } size_t RegisterInfoPOSIX_arm64::GetRegisterSetCount() const { - return k_num_register_sets; + if (IsSVEEnabled()) + return k_num_register_sets; + return k_num_register_sets - 1; } size_t RegisterInfoPOSIX_arm64::GetRegisterSetFromRegisterIndex( uint32_t reg_index) const { - if (reg_index <= last_gpr) + if (reg_index <= gpr_w28) return GPRegSet; - else if (reg_index <= last_fpr) + if (reg_index <= fpu_fpcr) return FPRegSet; + if (reg_index <= sve_ffr) + return SVERegSet; return LLDB_INVALID_REGNUM; } const lldb_private::RegisterSet * RegisterInfoPOSIX_arm64::GetRegisterSet(size_t set_index) const { - if (set_index < k_num_register_sets) + if (set_index < GetRegisterSetCount()) return &g_reg_sets_arm64[set_index]; - return nullptr; } + +uint32_t +RegisterInfoPOSIX_arm64::ConfigureVectorRegisterInfos(uint32_t sve_vq) { + // sve_vq contains SVE Quad vector length in context of AArch64 SVE. + // SVE register infos if enabled cannot be disabled by selecting sve_vq = 0. + // Also if an invalid or previously set vector length is passed to this + // function then it will exit immediately with previously set vector length. + if (!VectorSizeIsValid(sve_vq) || m_vector_reg_vq == sve_vq) + return m_vector_reg_vq; + + // We cannot enable AArch64 only mode if SVE was enabled. + if (sve_vq == eVectorQuadwordAArch64 && + m_vector_reg_vq > eVectorQuadwordAArch64) + sve_vq = eVectorQuadwordAArch64SVE; + + m_vector_reg_vq = sve_vq; + + if (sve_vq == eVectorQuadwordAArch64) { + m_register_info_count = + static_cast<uint32_t>(sizeof(g_register_infos_arm64_le) / + sizeof(g_register_infos_arm64_le[0])); + m_register_info_p = g_register_infos_arm64_le; + + return m_vector_reg_vq; + } + + m_register_info_count = + static_cast<uint32_t>(sizeof(g_register_infos_arm64_sve_le) / + sizeof(g_register_infos_arm64_sve_le[0])); + + std::vector<lldb_private::RegisterInfo> ®_info_ref = + m_per_vq_reg_infos[sve_vq]; + + if (reg_info_ref.empty()) { + reg_info_ref = llvm::makeArrayRef(g_register_infos_arm64_sve_le, + m_register_info_count); + + uint32_t offset = SVE_REGS_DEFAULT_OFFSET_LINUX; + + reg_info_ref[fpu_fpsr].byte_offset = offset; + reg_info_ref[fpu_fpcr].byte_offset = offset + 4; + reg_info_ref[sve_vg].byte_offset = offset + 8; + offset += 16; + + // Update Z registers size and offset + uint32_t s_reg_base = fpu_s0; + uint32_t d_reg_base = fpu_d0; + uint32_t v_reg_base = fpu_v0; + uint32_t z_reg_base = sve_z0; + + for (uint32_t index = 0; index < 32; index++) { + reg_info_ref[s_reg_base + index].byte_offset = offset; + reg_info_ref[d_reg_base + index].byte_offset = offset; + reg_info_ref[v_reg_base + index].byte_offset = offset; + reg_info_ref[z_reg_base + index].byte_offset = offset; + + reg_info_ref[z_reg_base + index].byte_size = sve_vq * SVE_QUAD_WORD_BYTES; + offset += reg_info_ref[z_reg_base + index].byte_size; + } + + // Update P registers and FFR size and offset + for (uint32_t it = sve_p0; it <= sve_ffr; it++) { + reg_info_ref[it].byte_offset = offset; + reg_info_ref[it].byte_size = sve_vq * SVE_QUAD_WORD_BYTES / 8; + offset += reg_info_ref[it].byte_size; + } + + m_per_vq_reg_infos[sve_vq] = reg_info_ref; + } + + m_register_info_p = reg_info_ref.data(); + return m_vector_reg_vq; +} + +bool RegisterInfoPOSIX_arm64::IsSVEZReg(unsigned reg) const { + return (sve_z0 <= reg && reg <= sve_z31); +} + +bool RegisterInfoPOSIX_arm64::IsSVEPReg(unsigned reg) const { + return (sve_p0 <= reg && reg <= sve_p15); +} + +bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const { + return sve_vg == reg; +} + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPCR() const { return fpu_fpcr; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEVG() const { return sve_vg; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h index 2da6a531a6b6..2929f2009dd9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h @@ -12,13 +12,24 @@ #include "RegisterInfoAndSetInterface.h" #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" +#include <map> + +enum class SVEState { Unknown, Disabled, FPSIMD, Full }; class RegisterInfoPOSIX_arm64 : public lldb_private::RegisterInfoAndSetInterface { public: - enum { GPRegSet = 0, FPRegSet }; + enum { GPRegSet = 0, FPRegSet, SVERegSet }; + + // AArch64 Register set FP/SIMD feature configuration + enum { + eVectorQuadwordAArch64, + eVectorQuadwordAArch64SVE, + eVectorQuadwordAArch64SVEMax = 256 + }; // based on RegisterContextDarwin_arm64.h + LLVM_PACKED_START struct GPR { uint64_t x[29]; // x0-x28 uint64_t fp; // x29 @@ -27,6 +38,7 @@ public: uint64_t pc; // pc uint32_t cpsr; // cpsr }; + LLVM_PACKED_END // based on RegisterContextDarwin_arm64.h struct VReg { @@ -73,14 +85,33 @@ public: size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override; + uint32_t ConfigureVectorRegisterInfos(uint32_t sve_vq); + + bool VectorSizeIsValid(uint32_t vq) { + if (vq >= eVectorQuadwordAArch64 && vq <= eVectorQuadwordAArch64SVEMax) + return true; + return false; + } + + bool IsSVEEnabled() const { return m_vector_reg_vq > eVectorQuadwordAArch64; } + + bool IsSVEZReg(unsigned reg) const; + bool IsSVEPReg(unsigned reg) const; + bool IsSVERegVG(unsigned reg) const; + + uint32_t GetRegNumSVEZ0() const; + uint32_t GetRegNumSVEFFR() const; + uint32_t GetRegNumFPCR() const; + uint32_t GetRegNumFPSR() const; + uint32_t GetRegNumSVEVG() const; + private: - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; + typedef std::map<uint32_t, std::vector<lldb_private::RegisterInfo>> + per_vq_register_infos; + + per_vq_register_infos m_per_vq_reg_infos; - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; + uint32_t m_vector_reg_vq = eVectorQuadwordAArch64; const lldb_private::RegisterInfo *m_register_info_p; uint32_t m_register_info_count; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h new file mode 100644 index 000000000000..9551db7e8ebf --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h @@ -0,0 +1,572 @@ +//===-- RegisterInfos_arm64_sve.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +enum { + sve_vg = exc_far, + + sve_z0, + sve_z1, + sve_z2, + sve_z3, + sve_z4, + sve_z5, + sve_z6, + sve_z7, + sve_z8, + sve_z9, + sve_z10, + sve_z11, + sve_z12, + sve_z13, + sve_z14, + sve_z15, + sve_z16, + sve_z17, + sve_z18, + sve_z19, + sve_z20, + sve_z21, + sve_z22, + sve_z23, + sve_z24, + sve_z25, + sve_z26, + sve_z27, + sve_z28, + sve_z29, + sve_z30, + sve_z31, + + sve_p0, + sve_p1, + sve_p2, + sve_p3, + sve_p4, + sve_p5, + sve_p6, + sve_p7, + sve_p8, + sve_p9, + sve_p10, + sve_p11, + sve_p12, + sve_p13, + sve_p14, + sve_p15, + + sve_ffr, +}; + +#ifndef SVE_OFFSET_VG +#error SVE_OFFSET_VG must be defined before including this header file +#endif + +static uint32_t g_sve_s0_invalidates[] = {sve_z0, fpu_v0, fpu_d0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s1_invalidates[] = {sve_z1, fpu_v1, fpu_d1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s2_invalidates[] = {sve_z2, fpu_v2, fpu_d2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s3_invalidates[] = {sve_z3, fpu_v3, fpu_d3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s4_invalidates[] = {sve_z4, fpu_v4, fpu_d4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s5_invalidates[] = {sve_z5, fpu_v5, fpu_d5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s6_invalidates[] = {sve_z6, fpu_v6, fpu_d6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s7_invalidates[] = {sve_z7, fpu_v7, fpu_d7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s8_invalidates[] = {sve_z8, fpu_v8, fpu_d8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s9_invalidates[] = {sve_z9, fpu_v9, fpu_d9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s10_invalidates[] = {sve_z10, fpu_v10, fpu_d10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s11_invalidates[] = {sve_z11, fpu_v11, fpu_d11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s12_invalidates[] = {sve_z12, fpu_v12, fpu_d12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s13_invalidates[] = {sve_z13, fpu_v13, fpu_d13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s14_invalidates[] = {sve_z14, fpu_v14, fpu_d14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s15_invalidates[] = {sve_z15, fpu_v15, fpu_d15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s16_invalidates[] = {sve_z16, fpu_v16, fpu_d16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s17_invalidates[] = {sve_z17, fpu_v17, fpu_d17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s18_invalidates[] = {sve_z18, fpu_v18, fpu_d18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s19_invalidates[] = {sve_z19, fpu_v19, fpu_d19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s20_invalidates[] = {sve_z20, fpu_v20, fpu_d20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s21_invalidates[] = {sve_z21, fpu_v21, fpu_d21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s22_invalidates[] = {sve_z22, fpu_v22, fpu_d22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s23_invalidates[] = {sve_z23, fpu_v23, fpu_d23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s24_invalidates[] = {sve_z24, fpu_v24, fpu_d24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s25_invalidates[] = {sve_z25, fpu_v25, fpu_d25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s26_invalidates[] = {sve_z26, fpu_v26, fpu_d26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s27_invalidates[] = {sve_z27, fpu_v27, fpu_d27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s28_invalidates[] = {sve_z28, fpu_v28, fpu_d28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s29_invalidates[] = {sve_z29, fpu_v29, fpu_d29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s30_invalidates[] = {sve_z30, fpu_v30, fpu_d30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s31_invalidates[] = {sve_z31, fpu_v31, fpu_d31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_sve_d0_invalidates[] = {sve_z0, fpu_v0, fpu_s0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d1_invalidates[] = {sve_z1, fpu_v1, fpu_s1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d2_invalidates[] = {sve_z2, fpu_v2, fpu_s2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d3_invalidates[] = {sve_z3, fpu_v3, fpu_s3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d4_invalidates[] = {sve_z4, fpu_v4, fpu_s4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d5_invalidates[] = {sve_z5, fpu_v5, fpu_s5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d6_invalidates[] = {sve_z6, fpu_v6, fpu_s6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d7_invalidates[] = {sve_z7, fpu_v7, fpu_s7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d8_invalidates[] = {sve_z8, fpu_v8, fpu_s8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d9_invalidates[] = {sve_z9, fpu_v9, fpu_s9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d10_invalidates[] = {sve_z10, fpu_v10, fpu_s10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d11_invalidates[] = {sve_z11, fpu_v11, fpu_s11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d12_invalidates[] = {sve_z12, fpu_v12, fpu_s12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d13_invalidates[] = {sve_z13, fpu_v13, fpu_s13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d14_invalidates[] = {sve_z14, fpu_v14, fpu_s14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d15_invalidates[] = {sve_z15, fpu_v15, fpu_s15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d16_invalidates[] = {sve_z16, fpu_v16, fpu_s16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d17_invalidates[] = {sve_z17, fpu_v17, fpu_s17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d18_invalidates[] = {sve_z18, fpu_v18, fpu_s18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d19_invalidates[] = {sve_z19, fpu_v19, fpu_s19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d20_invalidates[] = {sve_z20, fpu_v20, fpu_s20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d21_invalidates[] = {sve_z21, fpu_v21, fpu_s21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d22_invalidates[] = {sve_z22, fpu_v22, fpu_s22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d23_invalidates[] = {sve_z23, fpu_v23, fpu_s23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d24_invalidates[] = {sve_z24, fpu_v24, fpu_s24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d25_invalidates[] = {sve_z25, fpu_v25, fpu_s25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d26_invalidates[] = {sve_z26, fpu_v26, fpu_s26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d27_invalidates[] = {sve_z27, fpu_v27, fpu_s27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d28_invalidates[] = {sve_z28, fpu_v28, fpu_s28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d29_invalidates[] = {sve_z29, fpu_v29, fpu_s29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d30_invalidates[] = {sve_z30, fpu_v30, fpu_s30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d31_invalidates[] = {sve_z31, fpu_v31, fpu_s31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_sve_v0_invalidates[] = {sve_z0, fpu_d0, fpu_s0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v1_invalidates[] = {sve_z1, fpu_d1, fpu_s1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v2_invalidates[] = {sve_z2, fpu_d2, fpu_s2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v3_invalidates[] = {sve_z3, fpu_d3, fpu_s3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v4_invalidates[] = {sve_z4, fpu_d4, fpu_s4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v5_invalidates[] = {sve_z5, fpu_d5, fpu_s5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v6_invalidates[] = {sve_z6, fpu_d6, fpu_s6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v7_invalidates[] = {sve_z7, fpu_d7, fpu_s7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v8_invalidates[] = {sve_z8, fpu_d8, fpu_s8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v9_invalidates[] = {sve_z9, fpu_d9, fpu_s9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v10_invalidates[] = {sve_z10, fpu_d10, fpu_s10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v11_invalidates[] = {sve_z11, fpu_d11, fpu_s11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v12_invalidates[] = {sve_z12, fpu_d12, fpu_s12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v13_invalidates[] = {sve_z13, fpu_d13, fpu_s13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v14_invalidates[] = {sve_z14, fpu_d14, fpu_s14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v15_invalidates[] = {sve_z15, fpu_d15, fpu_s15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v16_invalidates[] = {sve_z16, fpu_d16, fpu_s16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v17_invalidates[] = {sve_z17, fpu_d17, fpu_s17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v18_invalidates[] = {sve_z18, fpu_d18, fpu_s18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v19_invalidates[] = {sve_z19, fpu_d19, fpu_s19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v20_invalidates[] = {sve_z20, fpu_d20, fpu_s20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v21_invalidates[] = {sve_z21, fpu_d21, fpu_s21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v22_invalidates[] = {sve_z22, fpu_d22, fpu_s22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v23_invalidates[] = {sve_z23, fpu_d23, fpu_s23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v24_invalidates[] = {sve_z24, fpu_d24, fpu_s24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v25_invalidates[] = {sve_z25, fpu_d25, fpu_s25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v26_invalidates[] = {sve_z26, fpu_d26, fpu_s26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v27_invalidates[] = {sve_z27, fpu_d27, fpu_s27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v28_invalidates[] = {sve_z28, fpu_d28, fpu_s28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v29_invalidates[] = {sve_z29, fpu_d29, fpu_s29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v30_invalidates[] = {sve_z30, fpu_d30, fpu_s30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v31_invalidates[] = {sve_z31, fpu_d31, fpu_s31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_contained_z0[] = {sve_z0, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z1[] = {sve_z1, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z2[] = {sve_z2, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z3[] = {sve_z3, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z4[] = {sve_z4, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z5[] = {sve_z5, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z6[] = {sve_z6, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z7[] = {sve_z7, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z8[] = {sve_z8, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z9[] = {sve_z9, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z10[] = {sve_z10, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z11[] = {sve_z11, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z12[] = {sve_z12, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z13[] = {sve_z13, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z14[] = {sve_z14, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z15[] = {sve_z15, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z16[] = {sve_z16, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z17[] = {sve_z17, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z18[] = {sve_z18, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z19[] = {sve_z19, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z20[] = {sve_z20, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z21[] = {sve_z21, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z22[] = {sve_z22, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z23[] = {sve_z23, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z24[] = {sve_z24, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z25[] = {sve_z25, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z26[] = {sve_z26, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z27[] = {sve_z27, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z28[] = {sve_z28, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z29[] = {sve_z29, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z30[] = {sve_z30, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z31[] = {sve_z31, LLDB_INVALID_REGNUM}; + +#define VG_OFFSET_NAME(reg) SVE_OFFSET_VG + +#define SVE_REG_KIND(reg) MISC_KIND(reg, sve, LLDB_INVALID_REGNUM) +#define MISC_VG_KIND(lldb_kind) MISC_KIND(vg, sve, LLDB_INVALID_REGNUM) + +// Default offset SVE Z registers and all corresponding pseudo registers +// ( S, D and V registers) is zero and will be configured during execution. + +// Defines sve pseudo vector (V) register with 16-byte size +#define DEFINE_VREG_SVE(vreg, zreg) \ + { \ + #vreg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + VREG_KIND(vreg), g_contained_##zreg, g_sve_##vreg##_invalidates, \ + nullptr, 0 \ + } + +// Defines S and D pseudo registers mapping over corresponding vector register +#define DEFINE_FPU_PSEUDO_SVE(reg, size, zreg) \ + { \ + #reg, nullptr, size, 0, lldb::eEncodingIEEE754, lldb::eFormatFloat, \ + LLDB_KIND(fpu_##reg), g_contained_##zreg, g_sve_##reg##_invalidates, \ + nullptr, 0 \ + } + +// Defines a Z vector register with 16-byte default size +#define DEFINE_ZREG(reg) \ + { \ + #reg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + SVE_REG_KIND(reg), nullptr, nullptr, nullptr, 0 \ + } + +// Defines a P vector register with 2-byte default size +#define DEFINE_PREG(reg) \ + { \ + #reg, nullptr, 2, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + SVE_REG_KIND(reg), nullptr, nullptr, nullptr, 0 \ + } + +static lldb_private::RegisterInfo g_register_infos_arm64_sve_le[] = { + // clang-format off + // DEFINE_GPR64(name, GENERIC KIND) + DEFINE_GPR64(x0, LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GPR64(x1, LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GPR64(x2, LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GPR64(x3, LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GPR64(x4, LLDB_REGNUM_GENERIC_ARG5), + DEFINE_GPR64(x5, LLDB_REGNUM_GENERIC_ARG6), + DEFINE_GPR64(x6, LLDB_REGNUM_GENERIC_ARG7), + DEFINE_GPR64(x7, LLDB_REGNUM_GENERIC_ARG8), + DEFINE_GPR64(x8, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x9, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x10, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x11, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x12, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x13, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x14, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x15, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x16, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x17, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x18, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x19, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x20, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x21, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x22, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x23, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x24, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x25, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x26, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x27, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x28, LLDB_INVALID_REGNUM), + // DEFINE_GPR64(name, GENERIC KIND) + DEFINE_GPR64_ALT(fp, x29, LLDB_REGNUM_GENERIC_FP), + DEFINE_GPR64_ALT(lr, x30, LLDB_REGNUM_GENERIC_RA), + DEFINE_GPR64_ALT(sp, x31, LLDB_REGNUM_GENERIC_SP), + DEFINE_GPR64(pc, LLDB_REGNUM_GENERIC_PC), + + // DEFINE_MISC_REGS(name, size, TYPE, lldb kind) + DEFINE_MISC_REGS(cpsr, 4, GPR, gpr_cpsr), + + // DEFINE_GPR32(name, parent name) + DEFINE_GPR32(w0, x0), + DEFINE_GPR32(w1, x1), + DEFINE_GPR32(w2, x2), + DEFINE_GPR32(w3, x3), + DEFINE_GPR32(w4, x4), + DEFINE_GPR32(w5, x5), + DEFINE_GPR32(w6, x6), + DEFINE_GPR32(w7, x7), + DEFINE_GPR32(w8, x8), + DEFINE_GPR32(w9, x9), + DEFINE_GPR32(w10, x10), + DEFINE_GPR32(w11, x11), + DEFINE_GPR32(w12, x12), + DEFINE_GPR32(w13, x13), + DEFINE_GPR32(w14, x14), + DEFINE_GPR32(w15, x15), + DEFINE_GPR32(w16, x16), + DEFINE_GPR32(w17, x17), + DEFINE_GPR32(w18, x18), + DEFINE_GPR32(w19, x19), + DEFINE_GPR32(w20, x20), + DEFINE_GPR32(w21, x21), + DEFINE_GPR32(w22, x22), + DEFINE_GPR32(w23, x23), + DEFINE_GPR32(w24, x24), + DEFINE_GPR32(w25, x25), + DEFINE_GPR32(w26, x26), + DEFINE_GPR32(w27, x27), + DEFINE_GPR32(w28, x28), + + // DEFINE_VREG_SVE(v register, z register) + DEFINE_VREG_SVE(v0, z0), + DEFINE_VREG_SVE(v1, z1), + DEFINE_VREG_SVE(v2, z2), + DEFINE_VREG_SVE(v3, z3), + DEFINE_VREG_SVE(v4, z4), + DEFINE_VREG_SVE(v5, z5), + DEFINE_VREG_SVE(v6, z6), + DEFINE_VREG_SVE(v7, z7), + DEFINE_VREG_SVE(v8, z8), + DEFINE_VREG_SVE(v9, z9), + DEFINE_VREG_SVE(v10, z10), + DEFINE_VREG_SVE(v11, z11), + DEFINE_VREG_SVE(v12, z12), + DEFINE_VREG_SVE(v13, z13), + DEFINE_VREG_SVE(v14, z14), + DEFINE_VREG_SVE(v15, z15), + DEFINE_VREG_SVE(v16, z16), + DEFINE_VREG_SVE(v17, z17), + DEFINE_VREG_SVE(v18, z18), + DEFINE_VREG_SVE(v19, z19), + DEFINE_VREG_SVE(v20, z20), + DEFINE_VREG_SVE(v21, z21), + DEFINE_VREG_SVE(v22, z22), + DEFINE_VREG_SVE(v23, z23), + DEFINE_VREG_SVE(v24, z24), + DEFINE_VREG_SVE(v25, z25), + DEFINE_VREG_SVE(v26, z26), + DEFINE_VREG_SVE(v27, z27), + DEFINE_VREG_SVE(v28, z28), + DEFINE_VREG_SVE(v29, z29), + DEFINE_VREG_SVE(v30, z30), + DEFINE_VREG_SVE(v31, z31), + + // DEFINE_FPU_PSEUDO(name, size, ENDIAN OFFSET, parent register) + DEFINE_FPU_PSEUDO_SVE(s0, 4, z0), + DEFINE_FPU_PSEUDO_SVE(s1, 4, z1), + DEFINE_FPU_PSEUDO_SVE(s2, 4, z2), + DEFINE_FPU_PSEUDO_SVE(s3, 4, z3), + DEFINE_FPU_PSEUDO_SVE(s4, 4, z4), + DEFINE_FPU_PSEUDO_SVE(s5, 4, z5), + DEFINE_FPU_PSEUDO_SVE(s6, 4, z6), + DEFINE_FPU_PSEUDO_SVE(s7, 4, z7), + DEFINE_FPU_PSEUDO_SVE(s8, 4, z8), + DEFINE_FPU_PSEUDO_SVE(s9, 4, z9), + DEFINE_FPU_PSEUDO_SVE(s10, 4, z10), + DEFINE_FPU_PSEUDO_SVE(s11, 4, z11), + DEFINE_FPU_PSEUDO_SVE(s12, 4, z12), + DEFINE_FPU_PSEUDO_SVE(s13, 4, z13), + DEFINE_FPU_PSEUDO_SVE(s14, 4, z14), + DEFINE_FPU_PSEUDO_SVE(s15, 4, z15), + DEFINE_FPU_PSEUDO_SVE(s16, 4, z16), + DEFINE_FPU_PSEUDO_SVE(s17, 4, z17), + DEFINE_FPU_PSEUDO_SVE(s18, 4, z18), + DEFINE_FPU_PSEUDO_SVE(s19, 4, z19), + DEFINE_FPU_PSEUDO_SVE(s20, 4, z20), + DEFINE_FPU_PSEUDO_SVE(s21, 4, z21), + DEFINE_FPU_PSEUDO_SVE(s22, 4, z22), + DEFINE_FPU_PSEUDO_SVE(s23, 4, z23), + DEFINE_FPU_PSEUDO_SVE(s24, 4, z24), + DEFINE_FPU_PSEUDO_SVE(s25, 4, z25), + DEFINE_FPU_PSEUDO_SVE(s26, 4, z26), + DEFINE_FPU_PSEUDO_SVE(s27, 4, z27), + DEFINE_FPU_PSEUDO_SVE(s28, 4, z28), + DEFINE_FPU_PSEUDO_SVE(s29, 4, z29), + DEFINE_FPU_PSEUDO_SVE(s30, 4, z30), + DEFINE_FPU_PSEUDO_SVE(s31, 4, z31), + + DEFINE_FPU_PSEUDO_SVE(d0, 8, z0), + DEFINE_FPU_PSEUDO_SVE(d1, 8, z1), + DEFINE_FPU_PSEUDO_SVE(d2, 8, z2), + DEFINE_FPU_PSEUDO_SVE(d3, 8, z3), + DEFINE_FPU_PSEUDO_SVE(d4, 8, z4), + DEFINE_FPU_PSEUDO_SVE(d5, 8, z5), + DEFINE_FPU_PSEUDO_SVE(d6, 8, z6), + DEFINE_FPU_PSEUDO_SVE(d7, 8, z7), + DEFINE_FPU_PSEUDO_SVE(d8, 8, z8), + DEFINE_FPU_PSEUDO_SVE(d9, 8, z9), + DEFINE_FPU_PSEUDO_SVE(d10, 8, z10), + DEFINE_FPU_PSEUDO_SVE(d11, 8, z11), + DEFINE_FPU_PSEUDO_SVE(d12, 8, z12), + DEFINE_FPU_PSEUDO_SVE(d13, 8, z13), + DEFINE_FPU_PSEUDO_SVE(d14, 8, z14), + DEFINE_FPU_PSEUDO_SVE(d15, 8, z15), + DEFINE_FPU_PSEUDO_SVE(d16, 8, z16), + DEFINE_FPU_PSEUDO_SVE(d17, 8, z17), + DEFINE_FPU_PSEUDO_SVE(d18, 8, z18), + DEFINE_FPU_PSEUDO_SVE(d19, 8, z19), + DEFINE_FPU_PSEUDO_SVE(d20, 8, z20), + DEFINE_FPU_PSEUDO_SVE(d21, 8, z21), + DEFINE_FPU_PSEUDO_SVE(d22, 8, z22), + DEFINE_FPU_PSEUDO_SVE(d23, 8, z23), + DEFINE_FPU_PSEUDO_SVE(d24, 8, z24), + DEFINE_FPU_PSEUDO_SVE(d25, 8, z25), + DEFINE_FPU_PSEUDO_SVE(d26, 8, z26), + DEFINE_FPU_PSEUDO_SVE(d27, 8, z27), + DEFINE_FPU_PSEUDO_SVE(d28, 8, z28), + DEFINE_FPU_PSEUDO_SVE(d29, 8, z29), + DEFINE_FPU_PSEUDO_SVE(d30, 8, z30), + DEFINE_FPU_PSEUDO_SVE(d31, 8, z31), + + // DEFINE_MISC_REGS(name, size, TYPE, lldb kind) + DEFINE_MISC_REGS(fpsr, 4, FPU, fpu_fpsr), + DEFINE_MISC_REGS(fpcr, 4, FPU, fpu_fpcr), + + DEFINE_MISC_REGS(vg, 8, VG, sve_vg), + // DEFINE_ZREG(name) + DEFINE_ZREG(z0), + DEFINE_ZREG(z1), + DEFINE_ZREG(z2), + DEFINE_ZREG(z3), + DEFINE_ZREG(z4), + DEFINE_ZREG(z5), + DEFINE_ZREG(z6), + DEFINE_ZREG(z7), + DEFINE_ZREG(z8), + DEFINE_ZREG(z9), + DEFINE_ZREG(z10), + DEFINE_ZREG(z11), + DEFINE_ZREG(z12), + DEFINE_ZREG(z13), + DEFINE_ZREG(z14), + DEFINE_ZREG(z15), + DEFINE_ZREG(z16), + DEFINE_ZREG(z17), + DEFINE_ZREG(z18), + DEFINE_ZREG(z19), + DEFINE_ZREG(z20), + DEFINE_ZREG(z21), + DEFINE_ZREG(z22), + DEFINE_ZREG(z23), + DEFINE_ZREG(z24), + DEFINE_ZREG(z25), + DEFINE_ZREG(z26), + DEFINE_ZREG(z27), + DEFINE_ZREG(z28), + DEFINE_ZREG(z29), + DEFINE_ZREG(z30), + DEFINE_ZREG(z31), + + // DEFINE_PREG(name) + DEFINE_PREG(p0), + DEFINE_PREG(p1), + DEFINE_PREG(p2), + DEFINE_PREG(p3), + DEFINE_PREG(p4), + DEFINE_PREG(p5), + DEFINE_PREG(p6), + DEFINE_PREG(p7), + DEFINE_PREG(p8), + DEFINE_PREG(p9), + DEFINE_PREG(p10), + DEFINE_PREG(p11), + DEFINE_PREG(p12), + DEFINE_PREG(p13), + DEFINE_PREG(p14), + DEFINE_PREG(p15), + + // DEFINE FFR + DEFINE_PREG(ffr) + // clang-format on +}; + +#endif // DECLARE_REGISTER_INFOS_ARM64_SVE_STRUCT diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h index 343579cd2657..15c7cac544a1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h @@ -87,15 +87,14 @@ nullptr, nullptr, nullptr, 0 \ } -#define DEFINE_FP_MM(reg, i) \ +#define DEFINE_FP_MM(reg, i, streg) \ { \ - #reg #i, nullptr, sizeof(uint64_t), \ - LLVM_EXTENSION FPR_OFFSET( \ - stmm[i]), eEncodingUint, eFormatHex, \ - {ehframe_mm##i##_i386, dwarf_mm##i##_i386, \ - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ - lldb_mm##i##_i386 }, \ - nullptr, nullptr, nullptr, 0 \ + #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ + eEncodingUint, eFormatHex, \ + {dwarf_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, lldb_mm##i##_i386 }, \ + RegisterContextPOSIX_x86::g_contained_##streg##_32, \ + RegisterContextPOSIX_x86::g_invalidate_##streg##_32, nullptr, 0 \ } #define DEFINE_XMM(reg, i) \ @@ -251,10 +250,12 @@ static RegisterInfo g_register_infos_i386[] = { // FP registers. DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2), DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5), - DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0), - DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3), - DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6), - DEFINE_FP_MM(mm, 7), + DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), + + DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1), + DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3), + DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5), + DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7), // XMM registers DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2), diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h index 51be31f8e028..90863dfdb090 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h @@ -10,8 +10,8 @@ // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) (offsetof(GPR, regname)) -#define FPR_OFFSET(regname) (offsetof(FPR, regname)) -#define VMX_OFFSET(regname) (offsetof(VMX, regname)) +#define FPR_OFFSET(regname) (sizeof(GPR) + offsetof(FPR, regname)) +#define VMX_OFFSET(regname) (sizeof(GPR) + sizeof(FPR) + offsetof(VMX, regname)) #define GPR_SIZE(regname) (sizeof(((GPR *)NULL)->regname)) #ifdef DECLARE_REGISTER_INFOS_POWERPC_STRUCT diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h index af3027afa73c..41c04b20f391 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -88,15 +88,14 @@ nullptr, nullptr, nullptr, 0 \ } -#define DEFINE_FP_MM(reg, i) \ +#define DEFINE_FP_MM(reg, i, streg) \ { \ - #reg #i, nullptr, sizeof(uint64_t), \ - LLVM_EXTENSION FPR_OFFSET( \ - stmm[i]), eEncodingUint, eFormatHex, \ - {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, \ - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ - lldb_mm##i##_x86_64 }, \ - nullptr, nullptr, nullptr, 0 \ + #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ + eEncodingUint, eFormatHex, \ + {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, lldb_mm##i##_x86_64 }, \ + RegisterContextPOSIX_x86::g_contained_##streg##_64, \ + RegisterContextPOSIX_x86::g_invalidate_##streg##_64, nullptr, 0 \ } #define DEFINE_XMM(reg, i) \ @@ -195,6 +194,14 @@ RegisterContextPOSIX_x86::g_invalidate_##reg64, nullptr, 0 \ } +#define DEFINE_FPR_32(name, reg, kind1, kind2, kind3, kind4, reg64) \ + { \ + #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, \ + RegisterContextPOSIX_x86::g_contained_##reg64, \ + RegisterContextPOSIX_x86::g_invalidate_##reg64, nullptr, 0 \ + } + // clang-format off static RegisterInfo g_register_infos_x86_64[] = { // General purpose registers EH_Frame DWARF Generic Process Plugin @@ -251,26 +258,30 @@ static RegisterInfo g_register_infos_x86_64[] = { DEFINE_GPR_PSEUDO_8L(r12l, r12), DEFINE_GPR_PSEUDO_8L(r13l, r13), DEFINE_GPR_PSEUDO_8L(r14l, r14), DEFINE_GPR_PSEUDO_8L(r15l, r15), -// i387 Floating point registers. EH_frame DWARF Generic Process Plugin -// ====================================== =============== ================== =================== ==================== +// i387 Floating point registers. EH_frame DWARF Generic Process Plugin reg64 +// ====================================== =============== ================== =================== ==================== ===== DEFINE_FPR(fctrl, fctrl, dwarf_fctrl_x86_64, dwarf_fctrl_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fstat, fstat, dwarf_fstat_x86_64, dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_FPR_32(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip), + DEFINE_FPR_32(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip), + DEFINE_FPR(fip, ptr.x86_64.fip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_FPR_32(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp), + DEFINE_FPR_32(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp), + DEFINE_FPR(fdp, ptr.x86_64.fdp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(mxcsr, mxcsr, dwarf_mxcsr_x86_64, dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), // FP registers. DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2), DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5), - DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0), - DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3), - DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6), - DEFINE_FP_MM(mm, 7), + DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), + + DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1), + DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3), + DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5), + DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7), // XMM registers DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2), diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h index 35f1a4075d09..4d10600f4771 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h @@ -106,7 +106,7 @@ enum { lldb_bnd1_i386, lldb_bnd2_i386, lldb_bnd3_i386, - k_last_mpxr = lldb_bnd3_i386, + k_last_mpxr_i386 = lldb_bnd3_i386, k_first_mpxc_i386, lldb_bndcfgu_i386 = k_first_mpxc_i386, @@ -228,8 +228,10 @@ enum { lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, lldb_st0_x86_64, diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index aa95e92607ad..ae19367ca3ae 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -52,9 +52,10 @@ void ProcessElfCore::Terminate() { lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file) { + const FileSpec *crash_file, + bool can_connect) { lldb::ProcessSP process_sp; - if (crash_file) { + if (crash_file && !can_connect) { // Read enough data for a ELF32 header or ELF64 header Note: Here we care // about e_type field only, so it is safe to ignore possible presence of // the header extension. @@ -97,7 +98,7 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp, ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec &core_file) - : Process(target_sp, listener_sp), m_core_file(core_file) {} + : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file) {} // Destructor ProcessElfCore::~ProcessElfCore() { @@ -260,8 +261,8 @@ lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() { return m_dyld_up.get(); } -bool ProcessElfCore::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessElfCore::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { const uint32_t num_threads = GetNumThreadContexts(); if (!m_thread_data_valid) return false; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h index 6f6309799f43..d8e3cc9ae3e1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -19,7 +19,7 @@ #include <list> #include <vector> -#include "lldb/Target/Process.h" +#include "lldb/Target/PostMortemProcess.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" @@ -28,12 +28,13 @@ struct ThreadData; -class ProcessElfCore : public lldb_private::Process { +class ProcessElfCore : public lldb_private::PostMortemProcess { public: // Constructors and Destructors static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const lldb_private::FileSpec *crash_file_path); + const lldb_private::FileSpec *crash_file_path, + bool can_connect); static void Initialize(); @@ -104,8 +105,8 @@ public: protected: void Clear(); - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; private: struct NT_FILE_Entry { @@ -125,8 +126,6 @@ private: lldb::ModuleSP m_core_module_sp; lldb_private::FileSpec m_core_file; std::string m_dyld_plugin_name; - ProcessElfCore(const ProcessElfCore &) = delete; - const ProcessElfCore &operator=(const ProcessElfCore &) = delete; // True if m_thread_contexts contains valid entries bool m_thread_data_valid = false; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp index b76f26a584c0..2f71f175a00d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp @@ -16,9 +16,9 @@ using namespace lldb_private; RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm( - Thread &thread, RegisterInfoInterface *register_info, + Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm> register_info, const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes) - : RegisterContextPOSIX_arm(thread, 0, register_info) { + : RegisterContextPOSIX_arm(thread, std::move(register_info)) { m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(), gpregset.GetByteSize()); m_gpr.SetData(m_gpr_buffer); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h index f9ec08ed35fc..de343f9001e0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h @@ -18,7 +18,7 @@ class RegisterContextCorePOSIX_arm : public RegisterContextPOSIX_arm { public: RegisterContextCorePOSIX_arm( lldb_private::Thread &thread, - lldb_private::RegisterInfoInterface *register_info, + std::unique_ptr<RegisterInfoPOSIX_arm> register_info, const lldb_private::DataExtractor &gpregset, llvm::ArrayRef<lldb_private::CoreNote> notes); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp index 685567416983..129a887a550c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "RegisterContextPOSIXCore_arm64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Target/Thread.h" @@ -27,6 +28,12 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( m_fpregset = getRegset( notes, m_register_info_up->GetTargetArchitecture().GetTriple(), FPR_Desc); + + m_sveregset = + getRegset(notes, m_register_info_up->GetTargetArchitecture().GetTriple(), + AARCH64_SVE_Desc); + + ConfigureRegisterContext(); } RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() {} @@ -45,9 +52,57 @@ bool RegisterContextCorePOSIX_arm64::WriteFPR() { return false; } +const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) { + return m_sveregset.GetDataStart() + offset; +} + +void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { + if (m_sveregset.GetByteSize() > sizeof(sve::user_sve_header)) { + uint64_t sve_header_field_offset = 8; + m_sve_vector_length = m_sveregset.GetU16(&sve_header_field_offset); + sve_header_field_offset = 12; + uint16_t sve_header_flags_field = + m_sveregset.GetU16(&sve_header_field_offset); + if ((sve_header_flags_field & sve::ptrace_regs_mask) == + sve::ptrace_regs_fpsimd) + m_sve_state = SVEState::FPSIMD; + else if ((sve_header_flags_field & sve::ptrace_regs_mask) == + sve::ptrace_regs_sve) + m_sve_state = SVEState::Full; + + if (sve::vl_valid(m_sve_vector_length)) + m_register_info_up->ConfigureVectorRegisterInfos( + sve::vq_from_vl(m_sve_vector_length)); + else { + m_sve_state = SVEState::Disabled; + m_sve_vector_length = 0; + } + } else + m_sve_state = SVEState::Disabled; +} + +uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset( + const RegisterInfo *reg_info) { + // Start of Z0 data is after GPRs plus 8 bytes of vg register + uint32_t sve_reg_offset = LLDB_INVALID_INDEX32; + if (m_sve_state == SVEState::FPSIMD) { + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16; + } else if (m_sve_state == SVEState::Full) { + uint32_t sve_z0_offset = GetGPRSize() + 16; + sve_reg_offset = + sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset; + } + + return sve_reg_offset; +} + bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { - lldb::offset_t offset = reg_info->byte_offset; + Status error; + lldb::offset_t offset; + + offset = reg_info->byte_offset; if (offset + reg_info->byte_size <= GetGPRSize()) { uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); if (offset == reg_info->byte_offset + reg_info->byte_size) { @@ -60,15 +115,86 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, if (reg == LLDB_INVALID_REGNUM) return false; - offset -= GetGPRSize(); - if (IsFPR(reg) && offset + reg_info->byte_size <= GetFPUSize()) { - Status error; - value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset, - reg_info->byte_size, lldb::eByteOrderLittle, error); - return error.Success(); - } + if (IsFPR(reg)) { + if (m_sve_state == SVEState::Disabled) { + // SVE is disabled take legacy route for FPU register access + offset -= GetGPRSize(); + if (offset < m_fpregset.GetByteSize()) { + value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset, + reg_info->byte_size, lldb::eByteOrderLittle, + error); + return error.Success(); + } + } else { + // FPSR and FPCR will be located right after Z registers in + // SVEState::FPSIMD while in SVEState::Full they will be located at the + // end of register data after an alignment correction based on currently + // selected vector length. + uint32_t sve_reg_num = LLDB_INVALID_REGNUM; + if (reg == GetRegNumFPSR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length)); + else if (m_sve_state == SVEState::FPSIMD) + offset = sve::ptrace_fpsimd_offset + (32 * 16); + } else if (reg == GetRegNumFPCR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length)); + else if (m_sve_state == SVEState::FPSIMD) + offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4; + } else { + // Extract SVE Z register value register number for this reg_info + if (reg_info->value_regs && + reg_info->value_regs[0] != LLDB_INVALID_REGNUM) + sve_reg_num = reg_info->value_regs[0]; + offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); + } + + assert(sve_reg_num != LLDB_INVALID_REGNUM); + assert(offset < m_sveregset.GetByteSize()); + value.SetFromMemoryData(reg_info, GetSVEBuffer(offset), + reg_info->byte_size, lldb::eByteOrderLittle, + error); + } + } else if (IsSVE(reg)) { + if (IsSVEVG(reg)) { + value = GetSVERegVG(); + return true; + } - return false; + switch (m_sve_state) { + case SVEState::FPSIMD: { + // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just + // copy 16 bytes of v register to the start of z register. All other + // SVE register will be set to zero. + uint64_t byte_size = 1; + uint8_t zeros = 0; + const uint8_t *src = &zeros; + if (IsSVEZ(reg)) { + byte_size = 16; + offset = CalculateSVEOffset(reg_info); + assert(offset < m_sveregset.GetByteSize()); + src = GetSVEBuffer(offset); + } + value.SetFromMemoryData(reg_info, src, byte_size, lldb::eByteOrderLittle, + error); + } break; + case SVEState::Full: + offset = CalculateSVEOffset(reg_info); + assert(offset < m_sveregset.GetByteSize()); + value.SetFromMemoryData(reg_info, GetSVEBuffer(offset), + reg_info->byte_size, lldb::eByteOrderLittle, + error); + break; + case SVEState::Disabled: + default: + return false; + } + } else + return false; + + return error.Success(); } bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues( diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h index 830e0ff91e4c..a4fdc4f14328 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -9,7 +9,9 @@ #ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H #define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H +#include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" + #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" @@ -49,6 +51,18 @@ private: lldb::DataBufferSP m_gpr_buffer; lldb_private::DataExtractor m_gpr; lldb_private::DataExtractor m_fpregset; + lldb_private::DataExtractor m_sveregset; + + SVEState m_sve_state; + uint16_t m_sve_vector_length = 0; + + const uint8_t *GetSVEBuffer(uint64_t offset = 0); + + void ConfigureRegisterContext(); + + uint32_t CalculateSVEOffset(const lldb_private::RegisterInfo *reg_info); + + uint64_t GetSVERegVG() { return m_sve_vector_length / 8; } }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h index 4e08aa280817..25abd7ed54b7 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h @@ -107,6 +107,10 @@ constexpr RegsetDesc FPR_Desc[] = { {llvm::Triple::OpenBSD, llvm::Triple::UnknownArch, OPENBSD::NT_FPREGS}, }; +constexpr RegsetDesc AARCH64_SVE_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SVE}, +}; + constexpr RegsetDesc PPC_VMX_Desc[] = { {llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX}, {llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX}, diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 9083ee060f07..6c3ee9debc7c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -86,9 +86,7 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { case llvm::Triple::FreeBSD: { switch (arch.GetMachine()) { case llvm::Triple::aarch64: - break; case llvm::Triple::arm: - reg_interface = new RegisterInfoPOSIX_arm(arch); break; case llvm::Triple::ppc: reg_interface = new RegisterContextFreeBSD_powerpc32(arch); @@ -126,9 +124,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { case llvm::Triple::Linux: { switch (arch.GetMachine()) { - case llvm::Triple::arm: - reg_interface = new RegisterInfoPOSIX_arm(arch); - break; case llvm::Triple::aarch64: break; case llvm::Triple::mipsel: @@ -163,9 +158,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { switch (arch.GetMachine()) { case llvm::Triple::aarch64: break; - case llvm::Triple::arm: - reg_interface = new RegisterInfoPOSIX_arm(arch); - break; case llvm::Triple::x86: reg_interface = new RegisterContextOpenBSD_i386(arch); break; @@ -182,7 +174,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { break; } - if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64) { + if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 && + arch.GetMachine() != llvm::Triple::arm) { LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported", __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); assert(false && "Architecture or OS not supported"); @@ -196,7 +189,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { break; case llvm::Triple::arm: m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>( - *this, reg_interface, m_gpregset_data, m_notes); + *this, std::make_unique<RegisterInfoPOSIX_arm>(arch), m_gpregset_data, + m_notes); break; case llvm::Triple::mipsel: case llvm::Triple::mips: diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index bfacd41dc1a3..4981345d6a18 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -50,7 +50,7 @@ #include <compression.h> #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB #include <zlib.h> #endif @@ -284,7 +284,7 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, LLDB_LOGV(log, "Read(buffer, sizeof(buffer), timeout = {0}, " "status = {1}, error = {2}) => bytes_read = {3}", - timeout, Communication::ConnectionStatusAsCString(status), error, + timeout, Communication::ConnectionStatusAsString(status), error, bytes_read); if (bytes_read > 0) { @@ -582,7 +582,7 @@ bool GDBRemoteCommunication::DecompressPacket() { } #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr && m_compression_type == CompressionType::ZlibDeflate) { @@ -1234,7 +1234,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client, const int backlog = 5; TCPSocket listen_socket(true, child_processes_inherit); if (llvm::Error error = - listen_socket.Listen("127.0.0.1:0", backlog).ToError()) + listen_socket.Listen("localhost:0", backlog).ToError()) return error; Socket *accept_socket; @@ -1243,7 +1243,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client, llvm::SmallString<32> remote_addr; llvm::raw_svector_ostream(remote_addr) - << "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber(); + << "connect://localhost:" << listen_socket.GetLocalPortNumber(); std::unique_ptr<ConnectionFileDescriptor> conn_up( new ConnectionFileDescriptor()); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index c75d5e106cd0..d375a312ae2c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1053,7 +1053,7 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression( } #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { @@ -1529,6 +1529,22 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( std::string name; name_extractor.GetHexByteString(name); region_info.SetName(name.c_str()); + } else if (name.equals("flags")) { + region_info.SetMemoryTagged(MemoryRegionInfo::eNo); + + llvm::StringRef flags = value; + llvm::StringRef flag; + while (flags.size()) { + flags = flags.ltrim(); + std::tie(flag, flags) = flags.split(' '); + // To account for trailing whitespace + if (flag.size()) { + if (flag == "mt") { + region_info.SetMemoryTagged(MemoryRegionInfo::eYes); + break; + } + } + } } else if (name.equals("error")) { StringExtractorGDBRemote error_extractor(value); std::string error_string; @@ -1701,14 +1717,9 @@ Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) { // Set num to 0 first. num = 0; if (m_supports_watchpoint_support_info != eLazyBoolNo) { - char packet[64]; - const int packet_len = - ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); - assert(packet_len < (int)sizeof(packet)); - UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == - PacketResult::Success) { + if (SendPacketAndWaitForResponse("qWatchpointSupportInfo:", response, + false) == PacketResult::Success) { m_supports_watchpoint_support_info = eLazyBoolYes; llvm::StringRef name; llvm::StringRef value; @@ -2120,6 +2131,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { case llvm::Triple::COFF: m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub); break; + case llvm::Triple::GOFF: case llvm::Triple::Wasm: case llvm::Triple::XCOFF: LLDB_LOGF(log, "error: not supported target architecture"); @@ -2816,7 +2828,7 @@ lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() { } lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand( - const char *command, // Shouldn't be NULL + llvm::StringRef command, const FileSpec & working_dir, // Pass empty FileSpec to use the current working directory int *status_ptr, // Pass NULL if you don't want the process exit status @@ -2827,7 +2839,7 @@ lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand( const Timeout<std::micro> &timeout) { lldb_private::StreamString stream; stream.PutCString("qPlatform_shell:"); - stream.PutBytesAsRawHex8(command, strlen(command)); + stream.PutBytesAsRawHex8(command.data(), command.size()); stream.PutChar(','); uint32_t timeout_sec = UINT32_MAX; if (timeout) { @@ -2981,6 +2993,31 @@ lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize( return UINT64_MAX; } +void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory( + CompletionRequest &request, bool only_dir) { + lldb_private::StreamString stream; + stream.PutCString("qPathComplete:"); + stream.PutHex32(only_dir ? 1 : 0); + stream.PutChar(','); + stream.PutStringAsRawHex8(request.GetCursorArgumentPrefix()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + StreamString strm; + char ch = response.GetChar(); + if (ch != 'M') + return; + while (response.Peek()) { + strm.Clear(); + while ((ch = response.GetHexU8(0, false)) != '\0') + strm.PutChar(ch); + request.AddCompletion(strm.GetString()); + if (response.GetChar() != ',') + break; + } + } +} + Status GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) { @@ -3433,6 +3470,35 @@ Status GDBRemoteCommunicationClient::SendGetMetaDataPacket( return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset); } +llvm::Expected<TraceTypeInfo> +GDBRemoteCommunicationClient::SendGetSupportedTraceType() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + + StreamGDBRemote escaped_packet; + escaped_packet.PutCString("jLLDBTraceSupportedType"); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, + true) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsErrorResponse()) + return response.GetStatus().ToError(); + if (response.IsUnsupportedResponse()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "jLLDBTraceSupportedType is unsupported"); + + if (llvm::Expected<TraceTypeInfo> type = + llvm::json::parse<TraceTypeInfo>(response.Peek())) + return *type; + else + return type.takeError(); + } + LLDB_LOG(log, "failed to send packet: jLLDBTraceSupportedType"); + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "failed to send packet: jLLDBTraceSupportedType"); +} + Status GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 8df08cbde735..af3755fce774 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -22,6 +22,7 @@ #include "lldb/Utility/GDBRemote.h" #include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/TraceOptions.h" #if defined(_WIN32) #include "lldb/Host/windows/PosixApi.h" #endif @@ -375,6 +376,9 @@ public: lldb::user_id_t GetFileSize(const FileSpec &file_spec); + void AutoCompleteDiskFileOrDirectory(CompletionRequest &request, + bool only_dir); + Status GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions); @@ -396,7 +400,7 @@ public: bool GetFileExists(const FileSpec &file_spec); Status RunShellCommand( - const char *command, // Shouldn't be nullptr + llvm::StringRef command, const FileSpec &working_dir, // Pass empty FileSpec to use the current // working directory int *status_ptr, // Pass nullptr if you don't want the process exit status @@ -516,6 +520,8 @@ public: Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options); + llvm::Expected<TraceTypeInfo> SendGetSupportedTraceType(); + protected: LazyBool m_supports_not_sending_acks; LazyBool m_supports_thread_suffix; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index b78f0916b9b9..60548efc0f33 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -12,11 +12,11 @@ #include "GDBRemoteCommunicationServer.h" -#include <cstring> - #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/UnimplementedError.h" +#include <cstring> using namespace lldb; using namespace lldb_private; @@ -113,18 +113,17 @@ GDBRemoteCommunicationServer::SendErrorResponse(const Status &error) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendErrorResponse(llvm::Error error) { + assert(error); std::unique_ptr<llvm::ErrorInfoBase> EIB; - std::unique_ptr<PacketUnimplementedError> PUE; + std::unique_ptr<UnimplementedError> UE; llvm::handleAllErrors( std::move(error), - [&](std::unique_ptr<PacketUnimplementedError> E) { PUE = std::move(E); }, + [&](std::unique_ptr<UnimplementedError> E) { UE = std::move(E); }, [&](std::unique_ptr<llvm::ErrorInfoBase> E) { EIB = std::move(E); }); if (EIB) return SendErrorResponse(Status(llvm::Error(std::move(EIB)))); - if (PUE) - return SendUnimplementedResponse(PUE->message().c_str()); - return SendErrorResponse(Status("Unknown Error")); + return SendUnimplementedResponse(""); } GDBRemoteCommunication::PacketResult @@ -152,5 +151,3 @@ GDBRemoteCommunicationServer::SendOKResponse() { bool GDBRemoteCommunicationServer::HandshakeWithClient() { return GetAck() == PacketResult::Success; } - -char PacketUnimplementedError::ID; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index a7c2ea47e3ba..a1cf70f9cd1a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -27,7 +27,6 @@ class ProcessGDBRemote; class GDBRemoteCommunicationServer : public GDBRemoteCommunication { public: - using PortMap = std::map<uint16_t, lldb::pid_t>; using PacketHandler = std::function<PacketResult(StringExtractorGDBRemote &packet, Status &error, bool &interrupt, bool &quit)>; @@ -79,18 +78,6 @@ private: operator=(const GDBRemoteCommunicationServer &) = delete; }; -class PacketUnimplementedError - : public llvm::ErrorInfo<PacketUnimplementedError, llvm::StringError> { -public: - static char ID; - using llvm::ErrorInfo<PacketUnimplementedError, - llvm::StringError>::ErrorInfo; // inherit constructors - PacketUnimplementedError(const llvm::Twine &S) - : ErrorInfo(S, llvm::errc::not_supported) {} - - PacketUnimplementedError() : ErrorInfo(llvm::errc::not_supported) {} -}; - } // namespace process_gdb_remote } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 08d489851799..1ca0290eda13 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -843,7 +843,7 @@ GDBRemoteCommunicationServerCommon::Handle_qSupported( response.PutCString(";QListThreadsInStopReply+"); response.PutCString(";qEcho+"); response.PutCString(";qXfer:features:read+"); -#if defined(__linux__) || defined(__NetBSD__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__FreeBSD__) response.PutCString(";QPassSignals+"); response.PutCString(";qXfer:auxv:read+"); response.PutCString(";qXfer:libraries-svr4:read+"); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index ae2f4bd041c9..62a09a2a432c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -10,13 +10,12 @@ #include "lldb/Host/Config.h" -#include "GDBRemoteCommunicationServerLLGS.h" -#include "lldb/Utility/GDBRemote.h" #include <chrono> #include <cstring> #include <thread> +#include "GDBRemoteCommunicationServerLLGS.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Debug.h" #include "lldb/Host/File.h" @@ -32,11 +31,13 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/GDBRemote.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" +#include "lldb/Utility/UnimplementedError.h" #include "lldb/Utility/UriParser.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/JSON.h" @@ -92,6 +93,10 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_memory_read); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, &GDBRemoteCommunicationServerLLGS::Handle_M); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__M, + &GDBRemoteCommunicationServerLLGS::Handle__M); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__m, + &GDBRemoteCommunicationServerLLGS::Handle__m); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p, &GDBRemoteCommunicationServerLLGS::Handle_p); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P, @@ -155,6 +160,15 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { StringExtractorGDBRemote::eServerPacketType_vAttach, &GDBRemoteCommunicationServerLLGS::Handle_vAttach); RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vAttachWait, + &GDBRemoteCommunicationServerLLGS::Handle_vAttachWait); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qVAttachOrWaitSupported, + &GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vAttachOrWait, + &GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait); + RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_vCont, &GDBRemoteCommunicationServerLLGS::Handle_vCont); RegisterMemberFunctionHandler( @@ -186,6 +200,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead, &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupportedType, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g, &GDBRemoteCommunicationServerLLGS::Handle_g); @@ -326,6 +343,75 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { return Status(); } +Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess( + llvm::StringRef process_name, bool include_existing) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1); + + // Create the matcher used to search the process list. + ProcessInstanceInfoList exclusion_list; + ProcessInstanceInfoMatch match_info; + match_info.GetProcessInfo().GetExecutableFile().SetFile( + process_name, llvm::sys::path::Style::native); + match_info.SetNameMatchType(NameMatch::Equals); + + if (include_existing) { + LLDB_LOG(log, "including existing processes in search"); + } else { + // Create the excluded process list before polling begins. + Host::FindProcesses(match_info, exclusion_list); + LLDB_LOG(log, "placed '{0}' processes in the exclusion list.", + exclusion_list.size()); + } + + LLDB_LOG(log, "waiting for '{0}' to appear", process_name); + + auto is_in_exclusion_list = + [&exclusion_list](const ProcessInstanceInfo &info) { + for (auto &excluded : exclusion_list) { + if (excluded.GetProcessID() == info.GetProcessID()) + return true; + } + return false; + }; + + ProcessInstanceInfoList loop_process_list; + while (true) { + loop_process_list.clear(); + if (Host::FindProcesses(match_info, loop_process_list)) { + // Remove all the elements that are in the exclusion list. + llvm::erase_if(loop_process_list, is_in_exclusion_list); + + // One match! We found the desired process. + if (loop_process_list.size() == 1) { + auto matching_process_pid = loop_process_list[0].GetProcessID(); + LLDB_LOG(log, "found pid {0}", matching_process_pid); + return AttachToProcess(matching_process_pid); + } + + // Multiple matches! Return an error reporting the PIDs we found. + if (loop_process_list.size() > 1) { + StreamString error_stream; + error_stream.Format( + "Multiple executables with name: '{0}' found. Pids: ", + process_name); + for (size_t i = 0; i < loop_process_list.size() - 1; ++i) { + error_stream.Format("{0}, ", loop_process_list[i].GetProcessID()); + } + error_stream.Format("{0}.", loop_process_list.back().GetProcessID()); + + Status error; + error.SetErrorString(error_stream.GetString()); + return error; + } + } + // No matches, we have not found the process. Sleep until next poll. + LLDB_LOG(log, "sleep {0} seconds", polling_interval); + std::this_thread::sleep_for(polling_interval); + } +} + void GDBRemoteCommunicationServerLLGS::InitializeDelegate( NativeProcessProtocol *process) { assert(process && "process cannot be NULL"); @@ -495,7 +581,7 @@ static void WriteRegisterValueInHexFixedWidth( } } -static llvm::Expected<json::Object> +static llvm::Optional<json::Object> GetRegistersAsJSON(NativeThreadProtocol &thread) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); @@ -504,30 +590,16 @@ GetRegistersAsJSON(NativeThreadProtocol &thread) { json::Object register_object; #ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET - // Expedite all registers in the first register set (i.e. should be GPRs) - // that are not contained in other registers. - const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); - if (!reg_set_p) - return llvm::make_error<llvm::StringError>("failed to get registers", - llvm::inconvertibleErrorCode()); - for (const uint32_t *reg_num_p = reg_set_p->registers; - *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { - uint32_t reg_num = *reg_num_p; + const auto expedited_regs = + reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full); #else - // Expedite only a couple of registers until we figure out why sending - // registers is expensive. - static const uint32_t k_expedited_registers[] = { - LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, - LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM}; - - for (const uint32_t *generic_reg_p = k_expedited_registers; - *generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) { - uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, *generic_reg_p); - if (reg_num == LLDB_INVALID_REGNUM) - continue; // Target does not support the given register. + const auto expedited_regs = + reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Minimal); #endif + if (expedited_regs.empty()) + return llvm::None; + for (auto ®_num : expedited_regs) { const RegisterInfo *const reg_info_p = reg_ctx.GetRegisterInfoAtIndex(reg_num); if (reg_info_p == nullptr) { @@ -620,12 +692,8 @@ GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) { json::Object thread_obj; if (!abridged) { - if (llvm::Expected<json::Object> registers = - GetRegistersAsJSON(*thread)) { + if (llvm::Optional<json::Object> registers = GetRegistersAsJSON(*thread)) thread_obj.try_emplace("registers", std::move(*registers)); - } else { - return registers.takeError(); - } } thread_obj.try_emplace("tid", static_cast<int64_t>(tid)); @@ -806,46 +874,27 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( // Grab the register context. NativeRegisterContext& reg_ctx = thread->GetRegisterContext(); - // Expedite all registers in the first register set (i.e. should be GPRs) - // that are not contained in other registers. - const RegisterSet *reg_set_p; - if (reg_ctx.GetRegisterSetCount() > 0 && - ((reg_set_p = reg_ctx.GetRegisterSet(0)) != nullptr)) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s expediting registers " - "from set '%s' (registers set count: %zu)", - __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", - reg_set_p->num_registers); + const auto expedited_regs = + reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full); - for (const uint32_t *reg_num_p = reg_set_p->registers; - *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { - const RegisterInfo *const reg_info_p = - reg_ctx.GetRegisterInfoAtIndex(*reg_num_p); - if (reg_info_p == nullptr) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to get " - "register info for register set '%s', register index " - "%" PRIu32, + for (auto ®_num : expedited_regs) { + const RegisterInfo *const reg_info_p = + reg_ctx.GetRegisterInfoAtIndex(reg_num); + // Only expediate registers that are not contained in other registers. + if (reg_info_p != nullptr && reg_info_p->value_regs == nullptr) { + RegisterValue reg_value; + Status error = reg_ctx.ReadRegister(reg_info_p, reg_value); + if (error.Success()) { + response.Printf("%.02x:", reg_num); + WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p, + ®_value, lldb::eByteOrderBig); + response.PutChar(';'); + } else { + LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to read " + "register '%s' index %" PRIu32 ": %s", __FUNCTION__, - reg_set_p->name ? reg_set_p->name : "<unnamed-set>", - *reg_num_p); - } else if (reg_info_p->value_regs == nullptr) { - // Only expediate registers that are not contained in other registers. - RegisterValue reg_value; - Status error = reg_ctx.ReadRegister(reg_info_p, reg_value); - if (error.Success()) { - response.Printf("%.02x:", *reg_num_p); - WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p, - ®_value, lldb::eByteOrderBig); - response.PutChar(';'); - } else { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to read " - "register '%s' index %" PRIu32 ": %s", - __FUNCTION__, - reg_info_p->name ? reg_info_p->name : "<unnamed-register>", - *reg_num_p, error.AsCString()); - } + reg_info_p->name ? reg_info_p->name : "<unnamed-register>", + reg_num, error.AsCString()); } } } @@ -1222,6 +1271,33 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStop( } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType( + StringExtractorGDBRemote &packet) { + + // Fail if we don't have a current process. + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); + + llvm::Expected<TraceTypeInfo> supported_trace_type = + m_debugged_process_up->GetSupportedTraceType(); + if (!supported_trace_type) + return SendErrorResponse(supported_trace_type.takeError()); + + StreamGDBRemote escaped_response; + StructuredData::Dictionary json_packet; + + json_packet.AddStringItem("name", supported_trace_type->name); + json_packet.AddStringItem("description", supported_trace_type->description); + + StreamString json_string; + json_packet.Dump(json_string, false); + escaped_response.PutEscapedBytes(json_string.GetData(), + json_string.GetSize()); + return SendPacketNoLock(escaped_response.GetString()); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead( StringExtractorGDBRemote &packet) { @@ -1723,6 +1799,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateSuspended: case eStateStopped: case eStateCrashed: { + assert(m_debugged_process_up != nullptr); lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); // Make sure we set the current thread so g and p packets return the data // the gdb will expect. @@ -1789,8 +1866,10 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( response.PutChar(';'); } - response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", - reg_info->byte_size * 8, reg_info->byte_offset); + response.Printf("bitsize:%" PRIu32 ";", reg_info->byte_size * 8); + + if (!reg_context.RegisterOffsetIsDynamic()) + response.Printf("offset:%" PRIu32 ";", reg_info->byte_offset); llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info); if (!encoding.empty()) @@ -2085,7 +2164,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { StreamGDBRemote response; RegisterValue reg_value( - reg_bytes, reg_size, + makeArrayRef(reg_bytes, reg_size), m_debugged_process_up->GetArchitecture().GetByteOrder()); Status error = reg_context.WriteRegister(reg_info, reg_value); if (error.Fail()) { @@ -2321,6 +2400,84 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("_M")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short _M packet"); + + const lldb::addr_t size = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + if (size == LLDB_INVALID_ADDRESS) + return SendIllFormedResponse(packet, "Address not valid"); + if (packet.GetChar() != ',') + return SendIllFormedResponse(packet, "Bad packet"); + Permissions perms = {}; + while (packet.GetBytesLeft() > 0) { + switch (packet.GetChar()) { + case 'r': + perms |= ePermissionsReadable; + break; + case 'w': + perms |= ePermissionsWritable; + break; + case 'x': + perms |= ePermissionsExecutable; + break; + default: + return SendIllFormedResponse(packet, "Bad permissions"); + } + } + + llvm::Expected<addr_t> addr = + m_debugged_process_up->AllocateMemory(size, perms); + if (!addr) + return SendErrorResponse(addr.takeError()); + + StreamGDBRemote response; + response.PutHex64(*addr); + return SendPacketNoLock(response.GetString()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("_m")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short m packet"); + + const lldb::addr_t addr = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + if (addr == LLDB_INVALID_ADDRESS) + return SendIllFormedResponse(packet, "Address not valid"); + + if (llvm::Error Err = m_debugged_process_up->DeallocateMemory(addr)) + return SendErrorResponse(std::move(Err)); + + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -2491,6 +2648,17 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( response.PutChar(';'); } + // Flags + MemoryRegionInfo::OptionalBool memory_tagged = + region_info.GetMemoryTagged(); + if (memory_tagged != MemoryRegionInfo::eDontKnow) { + response.PutCString("flags:"); + if (memory_tagged == MemoryRegionInfo::eYes) { + response.PutCString("mt"); + } + response.PutChar(';'); + } + // Name ConstString name = region_info.GetName(); if (name) { @@ -2773,10 +2941,11 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { continue; } - response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" offset=\"%" PRIu32 - "\" regnum=\"%d\" ", - reg_info->name, reg_info->byte_size * 8, - reg_info->byte_offset, reg_index); + response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" regnum=\"%d\" ", + reg_info->name, reg_info->byte_size * 8, reg_index); + + if (!reg_context.RegisterOffsetIsDynamic()) + response.Printf("offset=\"%" PRIu32 "\" ", reg_info->byte_offset); if (reg_info->alt_name && reg_info->alt_name[0]) response.Printf("altname=\"%s\" ", reg_info->alt_name); @@ -2876,8 +3045,7 @@ GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, if (object == "features" && annex == "target.xml") return BuildTargetXml(); - return llvm::make_error<PacketUnimplementedError>( - "Xfer object not supported"); + return llvm::make_error<UnimplementedError>(); } GDBRemoteCommunication::PacketResult @@ -3099,6 +3267,72 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach( } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vAttachWait( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Consume the ';' after the identifier. + packet.SetFilePos(strlen("vAttachWait")); + + if (!packet.GetBytesLeft() || packet.GetChar() != ';') + return SendIllFormedResponse(packet, "vAttachWait missing expected ';'"); + + // Allocate the buffer for the process name from vAttachWait. + std::string process_name; + if (!packet.GetHexByteString(process_name)) + return SendIllFormedResponse(packet, + "vAttachWait failed to parse process name"); + + LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name); + + Status error = AttachWaitProcess(process_name, false); + if (error.Fail()) { + LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name, + error); + return SendErrorResponse(error); + } + + // Notify we attached by sending a stop packet. + return SendStopReasonForState(m_debugged_process_up->GetState()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported( + StringExtractorGDBRemote &packet) { + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Consume the ';' after the identifier. + packet.SetFilePos(strlen("vAttachOrWait")); + + if (!packet.GetBytesLeft() || packet.GetChar() != ';') + return SendIllFormedResponse(packet, "vAttachOrWait missing expected ';'"); + + // Allocate the buffer for the process name from vAttachWait. + std::string process_name; + if (!packet.GetHexByteString(process_name)) + return SendIllFormedResponse(packet, + "vAttachOrWait failed to parse process name"); + + LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name); + + Status error = AttachWaitProcess(process_name, true); + if (error.Fail()) { + LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name, + error); + return SendErrorResponse(error); + } + + // Notify we attached by sending a stop packet. + return SendStopReasonForState(m_debugged_process_up->GetState()); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 3ce285910c25..c51139924559 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -59,6 +59,17 @@ public: /// attach operation. Status AttachToProcess(lldb::pid_t pid); + /// Wait to attach to a process with a given name. + /// + /// This method supports waiting for the next instance of a process + /// with a given name and attaching llgs to that via the configured + /// Platform. + /// + /// \return + /// An Status object indicating the success or failure of the + /// attach operation. + Status AttachWaitProcess(llvm::StringRef process_name, bool include_existing); + // NativeProcessProtocol::NativeDelegate overrides void InitializeDelegate(NativeProcessProtocol *process) override; @@ -138,6 +149,8 @@ protected: PacketResult Handle_memory_read(StringExtractorGDBRemote &packet); PacketResult Handle_M(StringExtractorGDBRemote &packet); + PacketResult Handle__M(StringExtractorGDBRemote &packet); + PacketResult Handle__m(StringExtractorGDBRemote &packet); PacketResult Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet); @@ -162,10 +175,18 @@ protected: PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet); + PacketResult Handle_jLLDBTraceSupportedType(StringExtractorGDBRemote &packet); + PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet); PacketResult Handle_vAttach(StringExtractorGDBRemote &packet); + PacketResult Handle_vAttachWait(StringExtractorGDBRemote &packet); + + PacketResult Handle_qVAttachOrWaitSupported(StringExtractorGDBRemote &packet); + + PacketResult Handle_vAttachOrWait(StringExtractorGDBRemote &packet); + PacketResult Handle_D(StringExtractorGDBRemote &packet); PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index d14b79a03d17..3462fb7ec8b9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -26,12 +26,14 @@ #include "lldb/Host/FileAction.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Target/Platform.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/GDBRemote.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/TildeExpressionResolver.h" #include "lldb/Utility/UriParser.h" #include "lldb/Utility/StringExtractorGDBRemote.h" @@ -40,6 +42,69 @@ using namespace lldb; using namespace lldb_private::process_gdb_remote; using namespace lldb_private; +GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port, + uint16_t max_port) { + for (; min_port < max_port; ++min_port) + m_port_map[min_port] = LLDB_INVALID_PROCESS_ID; +} + +void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) { + // Do not modify existing mappings + m_port_map.insert({port, LLDB_INVALID_PROCESS_ID}); +} + +llvm::Expected<uint16_t> +GDBRemoteCommunicationServerPlatform::PortMap::GetNextAvailablePort() { + if (m_port_map.empty()) + return 0; // Bind to port zero and get a port, we didn't have any + // limitations + + for (auto &pair : m_port_map) { + if (pair.second == LLDB_INVALID_PROCESS_ID) { + pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; + return pair.first; + } + } + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No free port found in port map"); +} + +bool GDBRemoteCommunicationServerPlatform::PortMap::AssociatePortWithProcess( + uint16_t port, lldb::pid_t pid) { + auto pos = m_port_map.find(port); + if (pos != m_port_map.end()) { + pos->second = pid; + return true; + } + return false; +} + +bool GDBRemoteCommunicationServerPlatform::PortMap::FreePort(uint16_t port) { + std::map<uint16_t, lldb::pid_t>::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) { + pos->second = LLDB_INVALID_PROCESS_ID; + return true; + } + return false; +} + +bool GDBRemoteCommunicationServerPlatform::PortMap::FreePortForProcess( + lldb::pid_t pid) { + if (!m_port_map.empty()) { + for (auto &pair : m_port_map) { + if (pair.second == pid) { + pair.second = LLDB_INVALID_PROCESS_ID; + return true; + } + } + } + return false; +} + +bool GDBRemoteCommunicationServerPlatform::PortMap::empty() const { + return m_port_map.empty(); +} + // GDBRemoteCommunicationServerPlatform constructor GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( const Socket::SocketProtocol socket_protocol, const char *socket_scheme) @@ -69,6 +134,9 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( StringExtractorGDBRemote::eServerPacketType_qProcessInfo, &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qPathComplete, + &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete); + RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); RegisterMemberFunctionHandler( @@ -89,9 +157,14 @@ GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {} Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid, - uint16_t &port, std::string &socket_name) { - if (port == UINT16_MAX) - port = GetNextAvailablePort(); + llvm::Optional<uint16_t> &port, std::string &socket_name) { + if (!port) { + llvm::Expected<uint16_t> available_port = m_port_map.GetNextAvailablePort(); + if (available_port) + port = *available_port; + else + return Status(available_port.takeError()); + } // Spawn a new thread to accept the port that gets bound after binding to // port 0 (zero). @@ -106,7 +179,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(), - port); + *port); // Do not run in a new session so that it can not linger after the platform // closes. @@ -121,7 +194,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( #if !defined(__APPLE__) url << m_socket_scheme << "://"; #endif - uint16_t *port_ptr = &port; + uint16_t *port_ptr = port.getPointer(); if (m_socket_protocol == Socket::ProtocolTcp) { llvm::StringRef platform_scheme; llvm::StringRef platform_ip; @@ -132,7 +205,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( platform_port, platform_path); UNUSED_IF_ASSERT_DISABLED(ok); assert(ok); - url << platform_ip.str() << ":" << port; + url << '[' << platform_ip.str() << "]:" << *port; } else { socket_name = GetDomainSocketPath("gdbserver").GetPath(); url << socket_name; @@ -146,11 +219,11 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( if (pid != LLDB_INVALID_PROCESS_ID) { std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); m_spawned_pids.insert(pid); - if (port > 0) - AssociatePortWithProcess(port, pid); + if (*port > 0) + m_port_map.AssociatePortWithProcess(*port, pid); } else { - if (port > 0) - FreePort(port); + if (*port > 0) + m_port_map.FreePort(*port); } return error; } @@ -170,12 +243,15 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( packet.SetFilePos(::strlen("qLaunchGDBServer;")); llvm::StringRef name; llvm::StringRef value; - uint16_t port = UINT16_MAX; + llvm::Optional<uint16_t> port; while (packet.GetNameColonValue(name, value)) { if (name.equals("host")) hostname = std::string(value); - else if (name.equals("port")) - value.getAsInteger(0, port); + else if (name.equals("port")) { + // Make the Optional valid so we can use its value + port = 0; + value.getAsInteger(0, port.getValue()); + } } lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; @@ -196,8 +272,9 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( __FUNCTION__, debugserver_pid); StreamGDBRemote response; + assert(port); response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, - port + m_port_offset); + *port + m_port_offset); if (!socket_name.empty()) { response.PutCString("socket_name:"); response.PutStringAsRawHex8(socket_name); @@ -334,6 +411,38 @@ GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo( } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_qPathComplete( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qPathComplete:")); + const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1); + if (packet.GetChar() != ',') + return SendErrorResponse(85); + std::string path; + packet.GetHexByteString(path); + + StringList matches; + StandardTildeExpressionResolver resolver; + if (only_dir) + CommandCompletions::DiskDirectories(path, matches, resolver); + else + CommandCompletions::DiskFiles(path, matches, resolver); + + StreamString response; + response.PutChar('M'); + llvm::StringRef separator; + std::sort(matches.begin(), matches.end()); + for (const auto &match : matches) { + response << separator; + separator = ","; + // encode result strings into hex bytes to avoid unexpected error caused by + // special characters like '$'. + response.PutStringAsRawHex8(match.c_str()); + } + + return SendPacketNoLock(response.GetString()); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir( StringExtractorGDBRemote &packet) { @@ -416,7 +525,7 @@ GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo( bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped( lldb::pid_t pid) { std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - FreePortForProcess(pid); + m_port_map.FreePortForProcess(pid); m_spawned_pids.erase(pid); return true; } @@ -462,51 +571,6 @@ void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) { m_port_map = port_map; } -uint16_t GDBRemoteCommunicationServerPlatform::GetNextAvailablePort() { - if (m_port_map.empty()) - return 0; // Bind to port zero and get a port, we didn't have any - // limitations - - for (auto &pair : m_port_map) { - if (pair.second == LLDB_INVALID_PROCESS_ID) { - pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; - return pair.first; - } - } - return UINT16_MAX; -} - -bool GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess( - uint16_t port, lldb::pid_t pid) { - PortMap::iterator pos = m_port_map.find(port); - if (pos != m_port_map.end()) { - pos->second = pid; - return true; - } - return false; -} - -bool GDBRemoteCommunicationServerPlatform::FreePort(uint16_t port) { - PortMap::iterator pos = m_port_map.find(port); - if (pos != m_port_map.end()) { - pos->second = LLDB_INVALID_PROCESS_ID; - return true; - } - return false; -} - -bool GDBRemoteCommunicationServerPlatform::FreePortForProcess(lldb::pid_t pid) { - if (!m_port_map.empty()) { - for (auto &pair : m_port_map) { - if (pair.second == pid) { - pair.second = LLDB_INVALID_PROCESS_ID; - return true; - } - } - } - return false; -} - const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { static FileSpec g_domainsocket_dir; static llvm::once_flag g_once_flag; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index a8cacea78835..6b964da4a279 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -16,13 +16,61 @@ #include "GDBRemoteCommunicationServerCommon.h" #include "lldb/Host/Socket.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" + namespace lldb_private { namespace process_gdb_remote { class GDBRemoteCommunicationServerPlatform : public GDBRemoteCommunicationServerCommon { public: - typedef std::map<uint16_t, lldb::pid_t> PortMap; + class PortMap { + public: + // This class is used to restrict the range of ports that + // platform created debugserver/gdbserver processes will + // communicate on. + + // Construct an empty map, where empty means any port is allowed. + PortMap() = default; + + // Make a port map with a range of free ports + // from min_port to max_port-1. + PortMap(uint16_t min_port, uint16_t max_port); + + // Add a port to the map. If it is already in the map do not modify + // its mapping. (used ports remain used, new ports start as free) + void AllowPort(uint16_t port); + + // If we are using a port map where we can only use certain ports, + // get the next available port. + // + // If we are using a port map and we are out of ports, return an error. + // + // If we aren't using a port map, return 0 to indicate we should bind to + // port 0 and then figure out which port we used. + llvm::Expected<uint16_t> GetNextAvailablePort(); + + // Tie a port to a process ID. Returns false if the port is not in the port + // map. If the port is already in use it will be moved to the given pid. + // FIXME: This is and GetNextAvailablePort make create a race condition if + // the portmap is shared between processes. + bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid); + + // Free the given port. Returns false if the port is not in the map. + bool FreePort(uint16_t port); + + // Free the port associated with the given pid. Returns false if there is + // no port associated with the pid. + bool FreePortForProcess(lldb::pid_t pid); + + // Returns true if there are no ports in the map, regardless of the state + // of those ports. Meaning a map with 1 used port is not empty. + bool empty() const; + + private: + std::map<uint16_t, lldb::pid_t> m_port_map; + }; GDBRemoteCommunicationServerPlatform( const Socket::SocketProtocol socket_protocol, const char *socket_scheme); @@ -35,27 +83,14 @@ public: // a port chosen by the OS. void SetPortMap(PortMap &&port_map); - // If we are using a port map where we can only use certain ports, - // get the next available port. - // - // If we are using a port map and we are out of ports, return UINT16_MAX - // - // If we aren't using a port map, return 0 to indicate we should bind to - // port 0 and then figure out which port we used. - uint16_t GetNextAvailablePort(); - - bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid); - - bool FreePort(uint16_t port); - - bool FreePortForProcess(lldb::pid_t pid); - void SetPortOffset(uint16_t port_offset); void SetInferiorArguments(const lldb_private::Args &args); + // Set port if you want to use a specific port number. + // Otherwise port will be set to the port that was chosen for you. Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname, - lldb::pid_t &pid, uint16_t &port, + lldb::pid_t &pid, llvm::Optional<uint16_t> &port, std::string &socket_name); void SetPendingGdbServer(lldb::pid_t pid, uint16_t port, @@ -81,6 +116,8 @@ protected: PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet); + PacketResult Handle_qPathComplete(StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 1f31b45d0fa9..10006616b0c6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -31,19 +31,20 @@ using namespace lldb_private::process_gdb_remote; // GDBRemoteRegisterContext constructor GDBRemoteRegisterContext::GDBRemoteRegisterContext( ThreadGDBRemote &thread, uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once, + GDBRemoteDynamicRegisterInfoSP reg_info_sp, bool read_all_at_once, bool write_all_at_once) - : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info), - m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once), + : RegisterContext(thread, concrete_frame_idx), + m_reg_info_sp(std::move(reg_info_sp)), m_reg_valid(), m_reg_data(), + m_read_all_at_once(read_all_at_once), m_write_all_at_once(write_all_at_once) { // Resize our vector of bools to contain one bool for every register. We will // use these boolean values to know when a register value is valid in // m_reg_data. - m_reg_valid.resize(reg_info.GetNumRegisters()); + m_reg_valid.resize(m_reg_info_sp->GetNumRegisters()); // Make a heap based buffer that is big enough to store all registers DataBufferSP reg_data_sp( - new DataBufferHeap(reg_info.GetRegisterDataByteSize(), 0)); + new DataBufferHeap(m_reg_info_sp->GetRegisterDataByteSize(), 0)); m_reg_data.SetData(reg_data_sp); m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder()); } @@ -62,12 +63,12 @@ void GDBRemoteRegisterContext::SetAllRegisterValid(bool b) { } size_t GDBRemoteRegisterContext::GetRegisterCount() { - return m_reg_info.GetNumRegisters(); + return m_reg_info_sp->GetNumRegisters(); } const RegisterInfo * GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) { - RegisterInfo *reg_info = m_reg_info.GetRegisterInfoAtIndex(reg); + RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfoAtIndex(reg); if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) { const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); @@ -78,11 +79,11 @@ GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) { } size_t GDBRemoteRegisterContext::GetRegisterSetCount() { - return m_reg_info.GetNumRegisterSets(); + return m_reg_info_sp->GetNumRegisterSets(); } const RegisterSet *GDBRemoteRegisterContext::GetRegisterSet(size_t reg_set) { - return m_reg_info.GetRegisterSet(reg_set); + return m_reg_info_sp->GetRegisterSet(reg_set); } bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info, @@ -209,11 +210,12 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, SetAllRegisterValid(true); return true; } else if (buffer_sp->GetByteSize() > 0) { - const int regcount = m_reg_info.GetNumRegisters(); + const int regcount = m_reg_info_sp->GetNumRegisters(); for (int i = 0; i < regcount; i++) { - struct RegisterInfo *reginfo = m_reg_info.GetRegisterInfoAtIndex(i); - if (reginfo->byte_offset + reginfo->byte_size - <= buffer_sp->GetByteSize()) { + struct RegisterInfo *reginfo = + m_reg_info_sp->GetRegisterInfoAtIndex(i); + if (reginfo->byte_offset + reginfo->byte_size <= + buffer_sp->GetByteSize()) { m_reg_valid[i] = true; } else { m_reg_valid[i] = false; @@ -342,6 +344,15 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, if (dst == nullptr) return false; + // Code below is specific to AArch64 target in SVE state + // If vector granule (vg) register is being written then thread's + // register context reconfiguration is triggered on success. + bool do_reconfigure_arm64_sve = false; + const ArchSpec &arch = process->GetTarget().GetArchitecture(); + if (arch.IsValid() && arch.GetTriple().isAArch64()) + if (strcmp(reg_info->name, "vg") == 0) + do_reconfigure_arm64_sve = true; + if (data.CopyByteOrderedData(data_offset, // src offset reg_info->byte_size, // src length dst, // dst @@ -361,6 +372,10 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, { SetAllRegisterValid(false); + + if (do_reconfigure_arm64_sve) + AArch64SVEReconfigure(); + return true; } } else { @@ -389,6 +404,9 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, } else { // This is an actual register, write it success = SetPrimordialRegister(reg_info, gdb_comm); + + if (success && do_reconfigure_arm64_sve) + AArch64SVEReconfigure(); } // Check if writing this register will invalidate any other register @@ -506,7 +524,7 @@ bool GDBRemoteRegisterContext::ReadAllRegisterValues( // m_reg_data buffer } data_sp = std::make_shared<DataBufferHeap>( - m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); + m_reg_data.GetDataStart(), m_reg_info_sp->GetRegisterDataByteSize()); return true; } else { @@ -654,9 +672,8 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( if (m_thread.GetProcess().get()) { const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); - if (arch.IsValid() && - (arch.GetMachine() == llvm::Triple::aarch64 || - arch.GetMachine() == llvm::Triple::aarch64_32) && + if (arch.IsValid() && (arch.GetMachine() == llvm::Triple::aarch64 || + arch.GetMachine() == llvm::Triple::aarch64_32) && arch.GetTriple().getVendor() == llvm::Triple::Apple && arch.GetTriple().getOS() == llvm::Triple::IOS) { arm64_debugserver = true; @@ -708,7 +725,63 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { - return m_reg_info.ConvertRegisterKindToRegisterNumber(kind, num); + return m_reg_info_sp->ConvertRegisterKindToRegisterNumber(kind, num); +} + +bool GDBRemoteRegisterContext::AArch64SVEReconfigure() { + if (!m_reg_info_sp) + return false; + + const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("vg"); + if (!reg_info) + return false; + + uint64_t fail_value = LLDB_INVALID_ADDRESS; + uint32_t vg_reg_num = reg_info->kinds[eRegisterKindLLDB]; + uint64_t vg_reg_value = ReadRegisterAsUnsigned(vg_reg_num, fail_value); + + if (vg_reg_value != fail_value && vg_reg_value <= 32) { + const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("p0"); + if (!reg_info || vg_reg_value == reg_info->byte_size) + return false; + + if (m_reg_info_sp->UpdateARM64SVERegistersInfos(vg_reg_value)) { + // Make a heap based buffer that is big enough to store all registers + m_reg_data.SetData(std::make_shared<DataBufferHeap>( + m_reg_info_sp->GetRegisterDataByteSize(), 0)); + m_reg_data.SetByteOrder(GetByteOrder()); + + InvalidateAllRegisters(); + + return true; + } + } + + return false; +} + +bool GDBRemoteDynamicRegisterInfo::UpdateARM64SVERegistersInfos(uint64_t vg) { + // SVE Z register size is vg x 8 bytes. + uint32_t z_reg_byte_size = vg * 8; + + // SVE vector length has changed, accordingly set size of Z, P and FFR + // registers. Also invalidate register offsets it will be recalculated + // after SVE register size update. + for (auto ® : m_regs) { + if (reg.value_regs == nullptr) { + if (reg.name[0] == 'z' && isdigit(reg.name[1])) + reg.byte_size = z_reg_byte_size; + else if (reg.name[0] == 'p' && isdigit(reg.name[1])) + reg.byte_size = vg; + else if (strcmp(reg.name, "ffr") == 0) + reg.byte_size = vg; + } + reg.byte_offset = LLDB_INVALID_INDEX32; + } + + // Re-calculate register offsets + ConfigureOffsets(); + return true; } void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 015862587103..252d7b359ee8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -27,20 +27,25 @@ namespace process_gdb_remote { class ThreadGDBRemote; class ProcessGDBRemote; +class GDBRemoteDynamicRegisterInfo; -class GDBRemoteDynamicRegisterInfo : public DynamicRegisterInfo { +typedef std::shared_ptr<GDBRemoteDynamicRegisterInfo> + GDBRemoteDynamicRegisterInfoSP; + +class GDBRemoteDynamicRegisterInfo final : public DynamicRegisterInfo { public: GDBRemoteDynamicRegisterInfo() : DynamicRegisterInfo() {} ~GDBRemoteDynamicRegisterInfo() override = default; void HardcodeARMRegisters(bool from_scratch); + bool UpdateARM64SVERegistersInfos(uint64_t vg); }; class GDBRemoteRegisterContext : public RegisterContext { public: GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, + GDBRemoteDynamicRegisterInfoSP reg_info_sp, bool read_all_at_once, bool write_all_at_once); ~GDBRemoteRegisterContext() override; @@ -73,6 +78,8 @@ public: uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) override; + bool AArch64SVEReconfigure(); + protected: friend class ThreadGDBRemote; @@ -106,7 +113,7 @@ protected: m_reg_valid[reg] = valid; } - GDBRemoteDynamicRegisterInfo &m_reg_info; + GDBRemoteDynamicRegisterInfoSP m_reg_info_sp; std::vector<bool> m_reg_valid; DataExtractor m_reg_data; bool m_read_all_at_once; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index b03184b41abb..1214812b60b0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -207,7 +207,8 @@ void ProcessGDBRemote::Terminate() { lldb::ProcessSP ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp, ListenerSP listener_sp, - const FileSpec *crash_file_path) { + const FileSpec *crash_file_path, + bool can_connect) { lldb::ProcessSP process_sp; if (crash_file_path == nullptr) process_sp = std::make_shared<ProcessGDBRemote>(target_sp, listener_sp); @@ -250,7 +251,7 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, ListenerSP listener_sp) : Process(target_sp, listener_sp), m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(), - m_register_info(), + m_register_info_sp(nullptr), m_async_broadcaster(nullptr, "lldb.process.gdb-remote.async-broadcaster"), m_async_listener_sp( Listener::MakeListener("lldb.process.gdb-remote.async-listener")), @@ -369,8 +370,8 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition( m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue(); } - if (m_register_info.SetRegisterInfo(*target_definition_sp, - GetTarget().GetArchitecture()) > 0) { + if (m_register_info_sp->SetRegisterInfo( + *target_definition_sp, GetTarget().GetArchitecture()) > 0) { return true; } } @@ -397,10 +398,10 @@ static size_t SplitCommaSeparatedRegisterNumberString( } void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { - if (!force && m_register_info.GetNumRegisters() > 0) + if (!force && m_register_info_sp) return; - m_register_info.Clear(); + m_register_info_sp = std::make_shared<GDBRemoteDynamicRegisterInfo>(); // Check if qHostInfo specified a specific packet timeout for this // connection. If so then lets update our setting so the user knows what the @@ -452,7 +453,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { return; char packet[128]; - uint32_t reg_offset = 0; + uint32_t reg_offset = LLDB_INVALID_INDEX32; uint32_t reg_num = 0; for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse; @@ -565,7 +566,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { reg_info.byte_offset = reg_offset; assert(reg_info.byte_size != 0); - reg_offset += reg_info.byte_size; + reg_offset = LLDB_INVALID_INDEX32; if (!value_regs.empty()) { value_regs.push_back(LLDB_INVALID_REGNUM); reg_info.value_regs = value_regs.data(); @@ -582,7 +583,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use)) abi_sp->AugmentRegisterInfo(reg_info); - m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); + m_register_info_sp->AddRegister(reg_info, reg_name, alt_name, set_name); } else { break; // ensure exit before reg_num is incremented } @@ -591,8 +592,8 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { } } - if (m_register_info.GetNumRegisters() > 0) { - m_register_info.Finalize(GetTarget().GetArchitecture()); + if (m_register_info_sp->GetNumRegisters() > 0) { + m_register_info_sp->Finalize(GetTarget().GetArchitecture()); return; } @@ -601,21 +602,21 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { // updated debugserver down on the devices. On the other hand, if the // accumulated reg_num is positive, see if we can add composite registers to // the existing primordial ones. - bool from_scratch = (m_register_info.GetNumRegisters() == 0); + bool from_scratch = (m_register_info_sp->GetNumRegisters() == 0); if (!target_arch.IsValid()) { if (arch_to_use.IsValid() && (arch_to_use.GetMachine() == llvm::Triple::arm || arch_to_use.GetMachine() == llvm::Triple::thumb) && arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple) - m_register_info.HardcodeARMRegisters(from_scratch); + m_register_info_sp->HardcodeARMRegisters(from_scratch); } else if (target_arch.GetMachine() == llvm::Triple::arm || target_arch.GetMachine() == llvm::Triple::thumb) { - m_register_info.HardcodeARMRegisters(from_scratch); + m_register_info_sp->HardcodeARMRegisters(from_scratch); } // At this point, we can finalize our register info. - m_register_info.Finalize(GetTarget().GetArchitecture()); + m_register_info_sp->Finalize(GetTarget().GetArchitecture()); } Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) { @@ -819,8 +820,8 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, // since 'O' packets can really slow down debugging if the inferior // does a lot of output. if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) && - pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY, nullptr, 0)) { - FileSpec secondary_name{pty.GetSecondaryName(nullptr, 0)}; + !errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) { + FileSpec secondary_name(pty.GetSecondaryName()); if (!stdin_file_spec) stdin_file_spec = secondary_name; @@ -1226,6 +1227,10 @@ Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid, return m_gdb_comm.SendGetTraceConfigPacket(uid, options); } +llvm::Expected<TraceTypeInfo> ProcessGDBRemote::GetSupportedTraceType() { + return m_gdb_comm.SendGetSupportedTraceType(); +} + void ProcessGDBRemote::DidExit() { // When we exit, disconnect from the GDB server communications m_gdb_comm.Disconnect(); @@ -1599,8 +1604,8 @@ bool ProcessGDBRemote::UpdateThreadIDList() { return true; } -bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { // locker will keep a mutex locked until it goes out of scope Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_THREAD)); LLDB_LOGV(log, "pid = {0}", GetID()); @@ -1760,6 +1765,19 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData()); } + // AArch64 SVE specific code below calls AArch64SVEReconfigure to update + // SVE register sizes and offsets if value of VG register has changed + // since last stop. + const ArchSpec &arch = GetTarget().GetArchitecture(); + if (arch.IsValid() && arch.GetTriple().isAArch64()) { + GDBRemoteRegisterContext *reg_ctx_sp = + static_cast<GDBRemoteRegisterContext *>( + gdb_thread->GetRegisterContext().get()); + + if (reg_ctx_sp) + reg_ctx_sp->AArch64SVEReconfigure(); + } + thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str()); gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr); @@ -2651,7 +2669,7 @@ addr_t ProcessGDBRemote::GetImageInfoAddress() { llvm::Expected<LoadedModuleInfoList> list = GetLoadedModuleList(); if (!list) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}"); + LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}."); } else { addr = list->m_link_map; } @@ -3208,14 +3226,8 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) { break; case BreakpointSite::eExternal: { - GDBStoppointType stoppoint_type; - if (bp_site->IsHardware()) - stoppoint_type = eBreakpointHardware; - else - stoppoint_type = eBreakpointSoftware; - - if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, - bp_op_size)) + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, + addr, bp_op_size)) error.SetErrorToGenericError(); } break; } @@ -4281,14 +4293,14 @@ struct GdbServerTargetInfo { bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp, - uint32_t &cur_reg_num, uint32_t ®_offset) { + uint32_t ®_num_remote, uint32_t ®_num_local) { if (!feature_node) return false; + uint32_t reg_offset = LLDB_INVALID_INDEX32; feature_node.ForEachChildElementWithName( - "reg", - [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, - &abi_sp](const XMLNode ®_node) -> bool { + "reg", [&target_info, &dyn_reg_info, ®_num_remote, ®_num_local, + ®_offset, &abi_sp](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; ConstString reg_name; @@ -4310,8 +4322,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num - cur_reg_num, // process plugin reg num - cur_reg_num // native register number + reg_num_remote, // process plugin reg num + reg_num_local // native register number }, nullptr, nullptr, @@ -4438,7 +4450,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, reg_info.byte_offset = reg_offset; assert(reg_info.byte_size != 0); - reg_offset += reg_info.byte_size; + reg_offset = LLDB_INVALID_INDEX32; if (!value_regs.empty()) { value_regs.push_back(LLDB_INVALID_REGNUM); reg_info.value_regs = value_regs.data(); @@ -4448,7 +4460,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, reg_info.invalidate_regs = invalidate_regs.data(); } - ++cur_reg_num; + reg_num_remote = reg_info.kinds[eRegisterKindProcessPlugin] + 1; + ++reg_num_local; reg_info.name = reg_name.AsCString(); if (abi_sp) abi_sp->AugmentRegisterInfo(reg_info); @@ -4467,8 +4480,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, // for nested register definition files. It returns true if it was able // to fetch and parse an xml file. bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( - ArchSpec &arch_to_use, std::string xml_filename, uint32_t &cur_reg_num, - uint32_t ®_offset) { + ArchSpec &arch_to_use, std::string xml_filename, uint32_t ®_num_remote, + uint32_t ®_num_local) { // request the target xml file std::string raw; lldb_private::Status lldberr; @@ -4571,13 +4584,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( // ABI is also potentially incorrect. ABISP abi_to_use_sp = ABI::FindPlugin(shared_from_this(), arch_to_use); for (auto &feature_node : feature_nodes) { - ParseRegisters(feature_node, target_info, this->m_register_info, - abi_to_use_sp, cur_reg_num, reg_offset); + ParseRegisters(feature_node, target_info, *this->m_register_info_sp, + abi_to_use_sp, reg_num_remote, reg_num_local); } for (const auto &include : target_info.includes) { - GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, cur_reg_num, - reg_offset); + GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, + reg_num_remote, reg_num_local); } } } else { @@ -4597,12 +4610,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { if (!m_gdb_comm.GetQXferFeaturesReadSupported()) return false; - uint32_t cur_reg_num = 0; - uint32_t reg_offset = 0; - if (GetGDBServerRegisterInfoXMLAndProcess (arch_to_use, "target.xml", cur_reg_num, reg_offset)) - this->m_register_info.Finalize(arch_to_use); + uint32_t reg_num_remote = 0; + uint32_t reg_num_local = 0; + if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml", + reg_num_remote, reg_num_local)) + this->m_register_info_sp->Finalize(arch_to_use); - return m_register_info.GetNumRegisters() > 0; + return m_register_info_sp->GetNumRegisters() > 0; } llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() { diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index ba967727ae3b..0921bf17c4e4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -55,7 +55,8 @@ public: static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); + const FileSpec *crash_file_path, + bool can_connect); static void Initialize(); @@ -175,6 +176,8 @@ public: llvm::MutableArrayRef<uint8_t> &buffer, size_t offset = 0) override; + llvm::Expected<TraceTypeInfo> GetSupportedTraceType() override; + Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override; Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override; @@ -251,7 +254,7 @@ protected: // the last stop // packet variable std::recursive_mutex m_last_stop_packet_mutex; - GDBRemoteDynamicRegisterInfo m_register_info; + GDBRemoteDynamicRegisterInfoSP m_register_info_sp; Broadcaster m_async_broadcaster; lldb::ListenerSP m_async_listener_sp; HostThread m_async_thread; @@ -309,8 +312,8 @@ protected: void Clear(); - bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) override; + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; Status ConnectToReplayServer(); @@ -388,8 +391,8 @@ protected: bool GetGDBServerRegisterInfoXMLAndProcess(ArchSpec &arch_to_use, std::string xml_filename, - uint32_t &cur_reg_num, - uint32_t ®_offset); + uint32_t &cur_reg_remote, + uint32_t &cur_reg_local); // Query remote GDBServer for register information bool GetGDBServerRegisterInfo(ArchSpec &arch); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 6deabf8d5d71..2a9896e41085 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -42,6 +42,14 @@ ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid) Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this, process.GetID(), GetID()); + // At this point we can clone reg_info for architectures supporting + // run-time update to register sizes and offsets.. + auto &gdb_process = static_cast<ProcessGDBRemote &>(process); + if (!gdb_process.m_register_info_sp->IsReconfigurable()) + m_reg_info_sp = gdb_process.m_register_info_sp; + else + m_reg_info_sp = std::make_shared<GDBRemoteDynamicRegisterInfo>( + *gdb_process.m_register_info_sp); } ThreadGDBRemote::~ThreadGDBRemote() { @@ -307,8 +315,8 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { !pSupported || gdb_process->m_use_g_packet_for_reading; bool write_all_registers_at_once = !pSupported; reg_ctx_sp = std::make_shared<GDBRemoteRegisterContext>( - *this, concrete_frame_idx, gdb_process->m_register_info, - read_all_registers_at_once, write_all_registers_at_once); + *this, concrete_frame_idx, m_reg_info_sp, read_all_registers_at_once, + write_all_registers_at_once); } } else { reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 5ad11170fec4..b7d75021c062 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -14,6 +14,8 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/StructuredData.h" +#include "GDBRemoteRegisterContext.h" + class StringExtractor; namespace lldb_private { @@ -101,6 +103,8 @@ protected: m_queue_serial_number; // Queue info from stop reply/stop info for thread lldb_private::LazyBool m_associated_with_libdispatch_queue; + GDBRemoteDynamicRegisterInfoSP m_reg_info_sp; + bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data); bool PrivateSetRegisterValue(uint32_t reg, uint64_t regval); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index 0c7f4cbbb859..61106ebcc430 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -62,27 +62,17 @@ UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) { static_cast<CvSignature>(static_cast<uint32_t>(*signature)); if (cv_signature == CvSignature::Pdb70) { - const CvRecordPdb70 *pdb70_uuid = nullptr; + const UUID::CvRecordPdb70 *pdb70_uuid = nullptr; Status error = consumeObject(cv_record, pdb70_uuid); if (error.Fail()) return UUID(); - - CvRecordPdb70 swapped; - if (!GetArchitecture().GetTriple().isOSBinFormatELF()) { - // LLDB's UUID class treats the data as a sequence of bytes, but breakpad - // interprets it as a sequence of little-endian fields, which it converts - // to big-endian when converting to text. Swap the bytes to big endian so - // that the string representation comes out right. - swapped = *pdb70_uuid; - llvm::sys::swapByteOrder(swapped.Uuid.Data1); - llvm::sys::swapByteOrder(swapped.Uuid.Data2); - llvm::sys::swapByteOrder(swapped.Uuid.Data3); - llvm::sys::swapByteOrder(swapped.Age); - pdb70_uuid = &swapped; + if (GetArchitecture().GetTriple().isOSBinFormatELF()) { + if (pdb70_uuid->Age != 0) + return UUID::fromOptionalData(pdb70_uuid, sizeof(*pdb70_uuid)); + return UUID::fromOptionalData(&pdb70_uuid->Uuid, + sizeof(pdb70_uuid->Uuid)); } - if (pdb70_uuid->Age != 0) - return UUID::fromOptionalData(pdb70_uuid, sizeof(*pdb70_uuid)); - return UUID::fromOptionalData(&pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid)); + return UUID::fromCvRecord(*pdb70_uuid); } else if (cv_signature == CvSignature::ElfBuildId) return UUID::fromOptionalData(cv_record); @@ -267,6 +257,93 @@ llvm::ArrayRef<minidump::Module> MinidumpParser::GetModuleList() { return {}; } +static bool +CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser, + std::vector<MemoryRegionInfo> ®ions) { + auto data = parser.GetStream(StreamType::LinuxMaps); + if (data.empty()) + return false; + + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + ParseLinuxMapRegions( + llvm::toStringRef(data), + [®ions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool { + if (region) + regions.push_back(*region); + else + LLDB_LOG_ERROR(log, region.takeError(), + "Reading memory region from minidump failed: {0}"); + return true; + }); + return !regions.empty(); +} + +/// Check for the memory regions starting at \a load_addr for a contiguous +/// section that has execute permissions that matches the module path. +/// +/// When we load a breakpad generated minidump file, we might have the +/// /proc/<pid>/maps text for a process that details the memory map of the +/// process that the minidump is describing. This checks the sorted memory +/// regions for a section that has execute permissions. A sample maps files +/// might look like: +/// +/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out +/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out +/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out +/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out +/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out +/// ... +/// +/// This function should return true when given 0x00400000 and "/tmp/a.out" +/// is passed in as the path since it has a consecutive memory region for +/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us +/// differentiate if a file has been memory mapped into a process for reading +/// and breakpad ends up saving a minidump file that has two module entries for +/// a given file: one that is read only for the entire file, and then one that +/// is the real executable that is loaded into memory for execution. For memory +/// mapped files they will typically show up and r--p permissions and a range +/// matcning the entire range of the file on disk: +/// +/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out +/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so +/// +/// This function should return false when asked about 0x00800000 with +/// "/tmp/a.out" as the path. +/// +/// \param[in] path +/// The path to the module to check for in the memory regions. Only sequential +/// memory regions whose paths match this path will be considered when looking +/// for execute permissions. +/// +/// \param[in] regions +/// A sorted list of memory regions obtained from a call to +/// CreateRegionsCacheFromLinuxMaps. +/// +/// \param[in] base_of_image +/// The load address of this module from BaseOfImage in the modules list. +/// +/// \return +/// True if a contiguous region of memory belonging to the module with a +/// matching path exists that has executable permissions. Returns false if +/// \a regions is empty or if there are no regions with execute permissions +/// that match \a path. + +static bool CheckForLinuxExecutable(ConstString path, + const MemoryRegionInfos ®ions, + lldb::addr_t base_of_image) { + if (regions.empty()) + return false; + lldb::addr_t addr = base_of_image; + MemoryRegionInfo region = MinidumpParser::GetMemoryRegionInfo(regions, addr); + while (region.GetName() == path) { + if (region.GetExecutable() == MemoryRegionInfo::eYes) + return true; + addr += region.GetRange().GetByteSize(); + region = MinidumpParser::GetMemoryRegionInfo(regions, addr); + } + return false; +} + std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() { Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES); auto ExpectedModules = GetMinidumpFile().getModuleList(); @@ -276,6 +353,15 @@ std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() { return {}; } + // Create memory regions from the linux maps only. We do this to avoid issues + // with breakpad generated minidumps where if someone has mmap'ed a shared + // library into memory to accesss its data in the object file, we can get a + // minidump with two mappings for a binary: one whose base image points to a + // memory region that is read + execute and one that is read only. + MemoryRegionInfos linux_regions; + if (CreateRegionsCacheFromLinuxMaps(*this, linux_regions)) + llvm::sort(linux_regions); + // map module_name -> filtered_modules index typedef llvm::StringMap<size_t> MapType; MapType module_name_to_filtered_index; @@ -304,10 +390,29 @@ std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() { // "filtered_modules.size()" above. filtered_modules.push_back(&module); } else { + // We have a duplicate module entry. Check the linux regions to see if + // either module is not really a mapped executable. If one but not the + // other is a real mapped executable, prefer the executable one. This + // can happen when a process mmap's in the file for an executable in + // order to read bytes from the executable file. A memory region mapping + // will exist for the mmap'ed version and for the loaded executable, but + // only one will have a consecutive region that is executable in the + // memory regions. + auto dup_module = filtered_modules[iter->second]; + ConstString name(*ExpectedName); + bool is_executable = + CheckForLinuxExecutable(name, linux_regions, module.BaseOfImage); + bool dup_is_executable = + CheckForLinuxExecutable(name, linux_regions, dup_module->BaseOfImage); + + if (is_executable != dup_is_executable) { + if (is_executable) + filtered_modules[iter->second] = &module; + continue; + } // This module has been seen. Modules are sometimes mentioned multiple // times when they are mapped discontiguously, so find the module with // the lowest "base_of_image" and use that as the filtered module. - auto dup_module = filtered_modules[iter->second]; if (module.BaseOfImage < dup_module->BaseOfImage) filtered_modules[iter->second] = &module; } @@ -412,22 +517,6 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr, } static bool -CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser, - std::vector<MemoryRegionInfo> ®ions) { - auto data = parser.GetStream(StreamType::LinuxMaps); - if (data.empty()) - return false; - ParseLinuxMapRegions(llvm::toStringRef(data), - [&](const lldb_private::MemoryRegionInfo ®ion, - const lldb_private::Status &status) -> bool { - if (status.Success()) - regions.push_back(region); - return true; - }); - return !regions.empty(); -} - -static bool CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser, std::vector<MemoryRegionInfo> ®ions) { Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES); @@ -500,10 +589,10 @@ CreateRegionsCacheFromMemory64List(MinidumpParser &parser, uint64_t base_rva; std::tie(memory64_list, base_rva) = MinidumpMemoryDescriptor64::ParseMemory64List(data); - + if (memory64_list.empty()) return false; - + regions.reserve(memory64_list.size()); for (const auto &memory_desc : memory64_list) { if (memory_desc.data_size == 0) @@ -597,3 +686,30 @@ MinidumpParser::GetStreamTypeAsString(StreamType stream_type) { } return "unknown stream type"; } + +MemoryRegionInfo +MinidumpParser::GetMemoryRegionInfo(const MemoryRegionInfos ®ions, + lldb::addr_t load_addr) { + MemoryRegionInfo region; + auto pos = llvm::upper_bound(regions, load_addr); + if (pos != regions.begin() && + std::prev(pos)->GetRange().Contains(load_addr)) { + return *std::prev(pos); + } + + if (pos == regions.begin()) + region.GetRange().SetRangeBase(0); + else + region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd()); + + if (pos == regions.end()) + region.GetRange().SetRangeEnd(UINT64_MAX); + else + region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); + + region.SetReadable(MemoryRegionInfo::eNo); + region.SetWritable(MemoryRegionInfo::eNo); + region.SetExecutable(MemoryRegionInfo::eNo); + region.SetMapped(MemoryRegionInfo::eNo); + return region; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h index c4d7612b5f8d..ff7134ff1815 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h @@ -96,6 +96,9 @@ public: llvm::object::MinidumpFile &GetMinidumpFile() { return *m_file; } + static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos ®ions, + lldb::addr_t load_addr); + private: MinidumpParser(lldb::DataBufferSP data_sp, std::unique_ptr<llvm::object::MinidumpFile> file); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h index a7ac65120e2b..c05fcfef05a6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h @@ -40,21 +40,6 @@ enum class CvSignature : uint32_t { ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps) }; -// Reference: -// https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html -struct CvRecordPdb70 { - struct { - llvm::support::ulittle32_t Data1; - llvm::support::ulittle16_t Data2; - llvm::support::ulittle16_t Data3; - uint8_t Data4[8]; - } Uuid; - llvm::support::ulittle32_t Age; - // char PDBFileName[]; -}; -static_assert(sizeof(CvRecordPdb70) == 20, - "sizeof CvRecordPdb70 is not correct!"); - enum class MinidumpMiscInfoFlags : uint32_t { ProcessID = (1 << 0), ProcessTimes = (1 << 1), diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index 1041f63aa2e2..05a48acc2f7a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -200,8 +200,9 @@ const char *ProcessMinidump::GetPluginDescriptionStatic() { lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file) { - if (!crash_file) + const FileSpec *crash_file, + bool can_connect) { + if (!crash_file || can_connect) return nullptr; lldb::ProcessSP process_sp; @@ -234,7 +235,7 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec &core_file, DataBufferSP core_data) - : Process(target_sp, listener_sp), m_core_file(core_file), + : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file), m_core_data(std::move(core_data)), m_is_wow64(false) {} ProcessMinidump::~ProcessMinidump() { @@ -404,32 +405,6 @@ ArchSpec ProcessMinidump::GetArchitecture() { return ArchSpec(triple); } -static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos ®ions, - lldb::addr_t load_addr) { - MemoryRegionInfo region; - auto pos = llvm::upper_bound(regions, load_addr); - if (pos != regions.begin() && - std::prev(pos)->GetRange().Contains(load_addr)) { - return *std::prev(pos); - } - - if (pos == regions.begin()) - region.GetRange().SetRangeBase(0); - else - region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd()); - - if (pos == regions.end()) - region.GetRange().SetRangeEnd(UINT64_MAX); - else - region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); - - region.SetReadable(MemoryRegionInfo::eNo); - region.SetWritable(MemoryRegionInfo::eNo); - region.SetExecutable(MemoryRegionInfo::eNo); - region.SetMapped(MemoryRegionInfo::eNo); - return region; -} - void ProcessMinidump::BuildMemoryRegions() { if (m_memory_regions) return; @@ -454,7 +429,7 @@ void ProcessMinidump::BuildMemoryRegions() { MemoryRegionInfo::RangeType section_range(load_addr, section_sp->GetByteSize()); MemoryRegionInfo region = - ::GetMemoryRegionInfo(*m_memory_regions, load_addr); + MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr); if (region.GetMapped() != MemoryRegionInfo::eYes && region.GetRange().GetRangeBase() <= section_range.GetRangeBase() && section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) { @@ -475,7 +450,7 @@ void ProcessMinidump::BuildMemoryRegions() { Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion) { BuildMemoryRegions(); - region = ::GetMemoryRegionInfo(*m_memory_regions, load_addr); + region = MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr); return Status(); } @@ -487,8 +462,8 @@ Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos ®ion_list) { void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); } -bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessMinidump::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { for (const minidump::Thread &thread : m_thread_list) { LocationDescriptor context_location = thread.Context; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index bfdace7ea33e..27b0da0047a5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -12,7 +12,7 @@ #include "MinidumpParser.h" #include "MinidumpTypes.h" -#include "lldb/Target/Process.h" +#include "lldb/Target/PostMortemProcess.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" @@ -26,11 +26,12 @@ namespace lldb_private { namespace minidump { -class ProcessMinidump : public Process { +class ProcessMinidump : public PostMortemProcess { public: static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); + const FileSpec *crash_file_path, + bool can_connect); static void Initialize(); @@ -97,8 +98,8 @@ public: protected: void Clear(); - bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) override; + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; void ReadModuleList(); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp index acd6128d84c5..f14e2732f6eb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp @@ -9,16 +9,66 @@ #include "Lua.h" #include "lldb/Host/FileSystem.h" #include "lldb/Utility/FileSpec.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" using namespace lldb_private; using namespace lldb; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" + +// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has +// C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is +// incompatible with C +#if _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4190) +#endif + +extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction( + lua_State *L, lldb::StackFrameSP stop_frame_sp, + lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl); + +#if _MSC_VER +#pragma warning (pop) +#endif + +#pragma clang diagnostic pop + +static int lldb_print(lua_State *L) { + int n = lua_gettop(L); + lua_getglobal(L, "io"); + lua_getfield(L, -1, "stdout"); + lua_getfield(L, -1, "write"); + for (int i = 1; i <= n; i++) { + lua_pushvalue(L, -1); // write() + lua_pushvalue(L, -3); // io.stdout + luaL_tolstring(L, i, nullptr); + lua_pushstring(L, i != n ? "\t" : "\n"); + lua_call(L, 3, 0); + } + return 0; +} + +Lua::Lua() : m_lua_state(luaL_newstate()) { + assert(m_lua_state); + luaL_openlibs(m_lua_state); + luaopen_lldb(m_lua_state); + lua_pushcfunction(m_lua_state, lldb_print); + lua_setglobal(m_lua_state, "print"); +} + +Lua::~Lua() { + assert(m_lua_state); + lua_close(m_lua_state); +} + llvm::Error Lua::Run(llvm::StringRef buffer) { int error = luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") || lua_pcall(m_lua_state, 0, 0, 0); - if (!error) + if (error == LUA_OK) return llvm::Error::success(); llvm::Error e = llvm::make_error<llvm::StringError>( @@ -29,6 +79,57 @@ llvm::Error Lua::Run(llvm::StringRef buffer) { return e; } +llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) { + lua_pushlightuserdata(m_lua_state, baton); + const char *fmt_str = "return function(frame, bp_loc, ...) {0} end"; + std::string func_str = llvm::formatv(fmt_str, body).str(); + if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { + llvm::Error e = llvm::make_error<llvm::StringError>( + llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(m_lua_state, 2); + return e; + } + lua_settable(m_lua_state, LUA_REGISTRYINDEX); + return llvm::Error::success(); +} + +llvm::Expected<bool> +Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, + lldb::BreakpointLocationSP bp_loc_sp, + StructuredData::ObjectSP extra_args_sp) { + + lua_pushlightuserdata(m_lua_state, baton); + lua_gettable(m_lua_state, LUA_REGISTRYINDEX); + auto *extra_args_impl = [&]() -> StructuredDataImpl * { + if (extra_args_sp == nullptr) + return nullptr; + auto *extra_args_impl = new StructuredDataImpl(); + extra_args_impl->SetObjectSP(extra_args_sp); + return extra_args_impl; + }(); + return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp, + bp_loc_sp, extra_args_impl); +} + +llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) { + int error = + luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer"); + if (error == LUA_OK) { + // Pop buffer + lua_pop(m_lua_state, 1); + return llvm::Error::success(); + } + + llvm::Error e = llvm::make_error<llvm::StringError>( + llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(m_lua_state, 1); + return e; +} + llvm::Error Lua::LoadModule(llvm::StringRef filename) { FileSpec file(filename); if (!FileSystem::Instance().Exists(file)) { @@ -44,7 +145,7 @@ llvm::Error Lua::LoadModule(llvm::StringRef filename) { int error = luaL_loadfile(m_lua_state, filename.data()) || lua_pcall(m_lua_state, 0, 1, 0); - if (error) { + if (error != LUA_OK) { llvm::Error e = llvm::make_error<llvm::StringError>( llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), llvm::inconvertibleErrorCode()); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h index 300115aac8a7..873440f0aab3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h @@ -9,6 +9,9 @@ #ifndef liblldb_Lua_h_ #define liblldb_Lua_h_ +#include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBFrame.h" +#include "lldb/Core/StructuredDataImpl.h" #include "lldb/lldb-types.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -25,19 +28,17 @@ int luaopen_lldb(lua_State *L); class Lua { public: - Lua() : m_lua_state(luaL_newstate()) { - assert(m_lua_state); - luaL_openlibs(m_lua_state); - luaopen_lldb(m_lua_state); - } - - ~Lua() { - assert(m_lua_state); - luaL_openlibs(m_lua_state); - } + Lua(); + ~Lua(); llvm::Error Run(llvm::StringRef buffer); + llvm::Error RegisterBreakpointCallback(void *baton, const char *body); + llvm::Expected<bool> + CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, + lldb::BreakpointLocationSP bp_loc_sp, + StructuredData::ObjectSP extra_args_sp); llvm::Error LoadModule(llvm::StringRef filename); + llvm::Error CheckSyntax(llvm::StringRef buffer); llvm::Error ChangeIO(FILE *out, FILE *err); private: diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp index 8cbeac4563c3..920e334f51aa 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp @@ -8,29 +8,42 @@ #include "ScriptInterpreterLua.h" #include "Lua.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamFile.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/ExecutionContext.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/Timer.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FormatAdapters.h" +#include <memory> +#include <vector> using namespace lldb; using namespace lldb_private; LLDB_PLUGIN_DEFINE(ScriptInterpreterLua) +enum ActiveIOHandler { + eIOHandlerNone, + eIOHandlerBreakpoint, + eIOHandlerWatchpoint +}; + class IOHandlerLuaInterpreter : public IOHandlerDelegate, public IOHandlerEditline { public: IOHandlerLuaInterpreter(Debugger &debugger, - ScriptInterpreterLua &script_interpreter) + ScriptInterpreterLua &script_interpreter, + ActiveIOHandler active_io_handler = eIOHandlerNone) : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua", ">>> ", "..> ", true, debugger.GetUseColor(), 0, *this, nullptr), - m_script_interpreter(script_interpreter) { + m_script_interpreter(script_interpreter), + m_active_io_handler(active_io_handler) { llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( debugger.GetOutputFile().GetStream(), debugger.GetErrorFile().GetStream())); @@ -41,20 +54,79 @@ public: llvm::cantFail(m_script_interpreter.LeaveSession()); } - void IOHandlerInputComplete(IOHandler &io_handler, - std::string &data) override { - if (llvm::StringRef(data).rtrim() == "quit") { - io_handler.SetIsDone(true); + void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { + const char *instructions = nullptr; + switch (m_active_io_handler) { + case eIOHandlerNone: + case eIOHandlerWatchpoint: + break; + case eIOHandlerBreakpoint: + instructions = "Enter your Lua command(s). Type 'quit' to end.\n" + "The commands are compiled as the body of the following " + "Lua function\n" + "function (frame, bp_loc, ...) end\n"; + SetPrompt(llvm::StringRef("..> ")); + break; + } + if (instructions == nullptr) return; + if (interactive) + *io_handler.GetOutputStreamFileSP() << instructions; + } + + bool IOHandlerIsInputComplete(IOHandler &io_handler, + StringList &lines) override { + size_t last = lines.GetSize() - 1; + if (IsQuitCommand(lines.GetStringAtIndex(last))) { + if (m_active_io_handler == eIOHandlerBreakpoint) + lines.DeleteStringAtIndex(last); + return true; + } + StreamString str; + lines.Join("\n", str); + if (llvm::Error E = + m_script_interpreter.GetLua().CheckSyntax(str.GetString())) { + std::string error_str = toString(std::move(E)); + // Lua always errors out to incomplete code with '<eof>' + return error_str.find("<eof>") == std::string::npos; } + // The breakpoint handler only exits with a explicit 'quit' + return m_active_io_handler != eIOHandlerBreakpoint; + } - if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) { - *GetOutputStreamFileSP() << llvm::toString(std::move(error)); + void IOHandlerInputComplete(IOHandler &io_handler, + std::string &data) override { + switch (m_active_io_handler) { + case eIOHandlerBreakpoint: { + auto *bp_options_vec = static_cast<std::vector<BreakpointOptions *> *>( + io_handler.GetUserData()); + for (auto *bp_options : *bp_options_vec) { + Status error = m_script_interpreter.SetBreakpointCommandCallback( + bp_options, data.c_str()); + if (error.Fail()) + *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n'; + } + io_handler.SetIsDone(true); + } break; + case eIOHandlerWatchpoint: + io_handler.SetIsDone(true); + break; + case eIOHandlerNone: + if (IsQuitCommand(data)) { + io_handler.SetIsDone(true); + return; + } + if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) + *io_handler.GetErrorStreamFileSP() << toString(std::move(error)); + break; } } private: ScriptInterpreterLua &m_script_interpreter; + ActiveIOHandler m_active_io_handler; + + bool IsQuitCommand(llvm::StringRef cmd) { return cmd.rtrim() == "quit"; } }; ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger) @@ -107,8 +179,7 @@ bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, } void ScriptInterpreterLua::ExecuteInterpreterLoop() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); // At the moment, the only time the debugger does not have an input file // handle is when this is called directly from lua, in which case it is @@ -124,7 +195,7 @@ void ScriptInterpreterLua::ExecuteInterpreterLoop() { bool ScriptInterpreterLua::LoadScriptingModule( const char *filename, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp) { + StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) { FileSystem::Instance().Collect(filename); if (llvm::Error e = m_lua->LoadModule(filename)) { @@ -174,6 +245,74 @@ llvm::Error ScriptInterpreterLua::LeaveSession() { return m_lua->Run(str); } +bool ScriptInterpreterLua::BreakpointCallbackFunction( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + assert(context); + + ExecutionContext exe_ctx(context->exe_ctx_ref); + Target *target = exe_ctx.GetTargetPtr(); + if (target == nullptr) + return true; + + StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); + BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id); + BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id)); + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( + debugger.GetScriptInterpreter(true, eScriptLanguageLua)); + Lua &lua = lua_interpreter->GetLua(); + + CommandDataLua *bp_option_data = static_cast<CommandDataLua *>(baton); + llvm::Expected<bool> BoolOrErr = lua.CallBreakpointCallback( + baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp); + if (llvm::Error E = BoolOrErr.takeError()) { + debugger.GetErrorStream() << toString(std::move(E)); + return true; + } + + return *BoolOrErr; +} + +void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback( + std::vector<BreakpointOptions *> &bp_options_vec, + CommandReturnObject &result) { + IOHandlerSP io_handler_sp( + new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint)); + io_handler_sp->SetUserData(&bp_options_vec); + m_debugger.RunIOHandlerAsync(io_handler_sp); +} + +Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction( + BreakpointOptions *bp_options, const char *function_name, + StructuredData::ObjectSP extra_args_sp) { + const char *fmt_str = "return {0}(frame, bp_loc, ...)"; + std::string oneliner = llvm::formatv(fmt_str, function_name).str(); + return RegisterBreakpointCallback(bp_options, oneliner.c_str(), + extra_args_sp); +} + +Status ScriptInterpreterLua::SetBreakpointCommandCallback( + BreakpointOptions *bp_options, const char *command_body_text) { + return RegisterBreakpointCallback(bp_options, command_body_text, {}); +} + +Status ScriptInterpreterLua::RegisterBreakpointCallback( + BreakpointOptions *bp_options, const char *command_body_text, + StructuredData::ObjectSP extra_args_sp) { + Status error; + auto data_up = std::make_unique<CommandDataLua>(extra_args_sp); + error = m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text); + if (error.Fail()) + return error; + auto baton_sp = + std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up)); + bp_options->SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction, + baton_sp); + return error; +} + lldb::ScriptInterpreterSP ScriptInterpreterLua::CreateInstance(Debugger &debugger) { return std::make_shared<ScriptInterpreterLua>(debugger); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h index bcc6ab24f6d0..1130ceee3c20 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h @@ -9,12 +9,27 @@ #ifndef liblldb_ScriptInterpreterLua_h_ #define liblldb_ScriptInterpreterLua_h_ +#include "lldb/Core/StructuredDataImpl.h" #include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-enumerations.h" namespace lldb_private { class Lua; class ScriptInterpreterLua : public ScriptInterpreter { public: + class CommandDataLua : public BreakpointOptions::CommandData { + public: + CommandDataLua() : BreakpointOptions::CommandData() { + interpreter = lldb::eScriptLanguageLua; + } + CommandDataLua(StructuredData::ObjectSP extra_args_sp) + : BreakpointOptions::CommandData(), m_extra_args_sp(extra_args_sp) { + interpreter = lldb::eScriptLanguageLua; + } + StructuredData::ObjectSP m_extra_args_sp; + }; + ScriptInterpreterLua(Debugger &debugger); ~ScriptInterpreterLua() override; @@ -25,10 +40,10 @@ public: void ExecuteInterpreterLoop() override; - bool - LoadScriptingModule(const char *filename, bool init_session, - lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr) override; + bool LoadScriptingModule(const char *filename, bool init_session, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp = nullptr, + FileSpec extra_search_dir = {}) override; // Static Functions static void Initialize(); @@ -41,6 +56,11 @@ public: static const char *GetPluginDescriptionStatic(); + static bool BreakpointCallbackFunction(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + // PluginInterface protocol lldb_private::ConstString GetPluginName() override; @@ -51,9 +71,24 @@ public: llvm::Error EnterSession(lldb::user_id_t debugger_id); llvm::Error LeaveSession(); + void CollectDataForBreakpointCommandCallback( + std::vector<BreakpointOptions *> &bp_options_vec, + CommandReturnObject &result) override; + + Status SetBreakpointCommandCallback(BreakpointOptions *bp_options, + const char *command_body_text) override; + + Status SetBreakpointCommandCallbackFunction( + BreakpointOptions *bp_options, const char *function_name, + StructuredData::ObjectSP extra_args_sp) override; + private: std::unique_ptr<Lua> m_lua; bool m_session_is_active = false; + + Status RegisterBreakpointCallback(BreakpointOptions *bp_options, + const char *command_body_text, + StructuredData::ObjectSP extra_args_sp); }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 6f040fdef09b..7c49502f1b57 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -451,7 +451,11 @@ Expected<llvm::StringRef> PythonString::AsUTF8() const { size_t PythonString::GetSize() const { if (IsValid()) { #if PY_MAJOR_VERSION >= 3 +#if PY_MINOR_VERSION >= 3 + return PyUnicode_GetLength(m_py_obj); +#else return PyUnicode_GetSize(m_py_obj); +#endif #else return PyString_Size(m_py_obj); #endif diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 9f56b4fa60a5..6b53bd3a2edc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/lldb-enumerations.h" #if LLDB_ENABLE_PYTHON @@ -32,6 +33,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" +#include "lldb/Utility/ReproducerInstrumentation.h" #include "lldb/Utility/Timer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -127,6 +129,16 @@ extern "C" unsigned int LLDBSwigPythonCallBreakpointResolver(void *implementor, const char *method_name, lldb_private::SymbolContext *sym_ctx); +extern "C" void *LLDBSwigPythonCreateScriptedStopHook( + TargetSP target_sp, const char *python_class_name, + const char *session_dictionary_name, lldb_private::StructuredDataImpl *args, + lldb_private::Status &error); + +extern "C" bool +LLDBSwigPythonStopHookCallHandleStop(void *implementor, + lldb::ExecutionContextRefSP exc_ctx, + lldb::StreamSP stream); + extern "C" size_t LLDBSwigPython_CalculateNumChildren(void *implementor, uint32_t max); @@ -204,6 +216,12 @@ extern "C" void * LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting, const lldb::TargetSP &target_sp); +static ScriptInterpreterPythonImpl *GetPythonInterpreter(Debugger &debugger) { + ScriptInterpreter *script_interpreter = + debugger.GetScriptInterpreter(true, lldb::eScriptLanguagePython); + return static_cast<ScriptInterpreterPythonImpl *>(script_interpreter); +} + static bool g_initialized = false; namespace { @@ -420,6 +438,7 @@ ScriptInterpreterPythonImpl::Locker::Locker( : ScriptInterpreterLocker(), m_teardown_session((on_leave & TearDownSession) == TearDownSession), m_python_interpreter(py_interpreter) { + repro::Recorder::PrivateThread(); DoAcquireLock(); if ((on_entry & InitSession) == InitSession) { if (!DoInitSession(on_entry, in, out, err)) { @@ -982,8 +1001,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( } void ScriptInterpreterPythonImpl::ExecuteInterpreterLoop() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); Debugger &debugger = m_debugger; @@ -1815,11 +1833,10 @@ StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan( return {}; Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - static_cast<ScriptInterpreterPythonImpl *>(script_interpreter); + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return {}; void *ret_val; @@ -1919,11 +1936,10 @@ ScriptInterpreterPythonImpl::CreateScriptedBreakpointResolver( return StructuredData::GenericSP(); Debugger &debugger = bkpt_sp->GetTarget().GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - static_cast<ScriptInterpreterPythonImpl *>(script_interpreter); + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return StructuredData::GenericSP(); void *ret_val; @@ -1979,6 +1995,59 @@ ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( return lldb::eSearchDepthModule; } +StructuredData::GenericSP ScriptInterpreterPythonImpl::CreateScriptedStopHook( + TargetSP target_sp, const char *class_name, StructuredDataImpl *args_data, + Status &error) { + + if (!target_sp) { + error.SetErrorString("No target for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + if (class_name == nullptr || class_name[0] == '\0') { + error.SetErrorString("No class name for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + ScriptInterpreterPythonImpl *python_interpreter = + GetPythonInterpreter(m_debugger); + + if (!python_interpreter) { + error.SetErrorString("No script interpreter for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + void *ret_val; + + { + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + ret_val = LLDBSwigPythonCreateScriptedStopHook( + target_sp, class_name, python_interpreter->m_dictionary_name.c_str(), + args_data, error); + } + + return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); +} + +bool ScriptInterpreterPythonImpl::ScriptedStopHookHandleStop( + StructuredData::GenericSP implementor_sp, ExecutionContext &exc_ctx, + lldb::StreamSP stream_sp) { + assert(implementor_sp && + "can't call a stop hook with an invalid implementor"); + assert(stream_sp && "can't call a stop hook with an invalid stream"); + + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + lldb::ExecutionContextRefSP exc_ctx_ref_sp(new ExecutionContextRef(exc_ctx)); + + bool ret_val = LLDBSwigPythonStopHookCallHandleStop( + implementor_sp->GetValue(), exc_ctx_ref_sp, stream_sp); + return ret_val; +} + StructuredData::ObjectSP ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { @@ -2039,11 +2108,10 @@ ScriptInterpreterPythonImpl::CreateSyntheticScriptedProvider( return StructuredData::ObjectSP(); Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - (ScriptInterpreterPythonImpl *)script_interpreter; + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return StructuredData::ObjectSP(); void *ret_val = nullptr; @@ -2151,8 +2219,7 @@ bool ScriptInterpreterPythonImpl::GetScriptedSummary( StructuredData::ObjectSP &callee_wrapper_sp, const TypeSummaryOptions &options, std::string &retval) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (!valobj.get()) { retval.assign("<no object>"); @@ -2210,11 +2277,10 @@ bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction( return true; Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - (ScriptInterpreterPythonImpl *)script_interpreter; + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return true; if (python_function_name && python_function_name[0]) { @@ -2276,11 +2342,10 @@ bool ScriptInterpreterPythonImpl::WatchpointCallbackFunction( return true; Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - (ScriptInterpreterPythonImpl *)script_interpreter; + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return true; if (python_function_name && python_function_name[0]) { @@ -2669,7 +2734,10 @@ uint64_t replace_all(std::string &str, const std::string &oldStr, bool ScriptInterpreterPythonImpl::LoadScriptingModule( const char *pathname, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp) { + StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) { + namespace fs = llvm::sys::fs; + namespace path = llvm::sys::path; + if (!pathname || !pathname[0]) { error.SetErrorString("invalid pathname"); return false; @@ -2677,24 +2745,55 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this(); - { - FileSpec target_file(pathname); - FileSystem::Instance().Resolve(target_file); - FileSystem::Instance().Collect(target_file); - std::string basename(target_file.GetFilename().GetCString()); + // Before executing Python code, lock the GIL. + Locker py_lock(this, + Locker::AcquireLock | + (init_session ? Locker::InitSession : 0) | Locker::NoSTDIN, + Locker::FreeAcquiredLock | + (init_session ? Locker::TearDownSession : 0)); + + auto ExtendSysPath = [this](std::string directory) -> llvm::Error { + if (directory.empty()) { + return llvm::make_error<llvm::StringError>( + "invalid directory name", llvm::inconvertibleErrorCode()); + } + + replace_all(directory, "\\", "\\\\"); + replace_all(directory, "'", "\\'"); + // Make sure that Python has "directory" in the search path. StreamString command_stream; + command_stream.Printf("if not (sys.path.__contains__('%s')):\n " + "sys.path.insert(1,'%s');\n\n", + directory.c_str(), directory.c_str()); + bool syspath_retval = + ExecuteMultipleLines(command_stream.GetData(), + ScriptInterpreter::ExecuteScriptOptions() + .SetEnableIO(false) + .SetSetLLDBGlobals(false)) + .Success(); + if (!syspath_retval) { + return llvm::make_error<llvm::StringError>( + "Python sys.path handling failed", llvm::inconvertibleErrorCode()); + } + + return llvm::Error::success(); + }; + + std::string module_name(pathname); + + if (extra_search_dir) { + if (llvm::Error e = ExtendSysPath(extra_search_dir.GetPath())) { + error = std::move(e); + return false; + } + } else { + FileSpec module_file(pathname); + FileSystem::Instance().Resolve(module_file); + FileSystem::Instance().Collect(module_file); - // Before executing Python code, lock the GIL. - Locker py_lock(this, - Locker::AcquireLock | - (init_session ? Locker::InitSession : 0) | - Locker::NoSTDIN, - Locker::FreeAcquiredLock | - (init_session ? Locker::TearDownSession : 0)); - namespace fs = llvm::sys::fs; fs::file_status st; - std::error_code ec = status(target_file.GetPath(), st); + std::error_code ec = status(module_file.GetPath(), st); if (ec || st.type() == fs::file_type::status_error || st.type() == fs::file_type::type_unknown || @@ -2705,113 +2804,98 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( error.SetErrorString("invalid pathname"); return false; } - basename = pathname; // not a filename, probably a package of some sort, - // let it go through + // Not a filename, probably a package of some sort, let it go through. } else if (is_directory(st) || is_regular_file(st)) { - if (target_file.GetDirectory().IsEmpty()) { + if (module_file.GetDirectory().IsEmpty()) { error.SetErrorString("invalid directory name"); return false; } - - std::string directory = target_file.GetDirectory().GetCString(); - replace_all(directory, "\\", "\\\\"); - replace_all(directory, "'", "\\'"); - - // now make sure that Python has "directory" in the search path - StreamString command_stream; - command_stream.Printf("if not (sys.path.__contains__('%s')):\n " - "sys.path.insert(1,'%s');\n\n", - directory.c_str(), directory.c_str()); - bool syspath_retval = - ExecuteMultipleLines(command_stream.GetData(), - ScriptInterpreter::ExecuteScriptOptions() - .SetEnableIO(false) - .SetSetLLDBGlobals(false)) - .Success(); - if (!syspath_retval) { - error.SetErrorString("Python sys.path handling failed"); + if (llvm::Error e = + ExtendSysPath(module_file.GetDirectory().GetCString())) { + error = std::move(e); return false; } - - // strip .py or .pyc extension - ConstString extension = target_file.GetFileNameExtension(); - if (extension) { - if (llvm::StringRef(extension.GetCString()) == ".py") - basename.resize(basename.length() - 3); - else if (llvm::StringRef(extension.GetCString()) == ".pyc") - basename.resize(basename.length() - 4); - } + module_name = module_file.GetFilename().GetCString(); } else { error.SetErrorString("no known way to import this module specification"); return false; } + } - // check if the module is already import-ed - command_stream.Clear(); - command_stream.Printf("sys.modules.__contains__('%s')", basename.c_str()); - bool does_contain = false; - // this call will succeed if the module was ever imported in any Debugger - // in the lifetime of the process in which this LLDB framework is living - bool was_imported_globally = - (ExecuteOneLineWithReturn( - command_stream.GetData(), - ScriptInterpreterPythonImpl::eScriptReturnTypeBool, &does_contain, - ScriptInterpreter::ExecuteScriptOptions() - .SetEnableIO(false) - .SetSetLLDBGlobals(false)) && - does_contain); - // this call will fail if the module was not imported in this Debugger - // before - command_stream.Clear(); - command_stream.Printf("sys.getrefcount(%s)", basename.c_str()); - bool was_imported_locally = GetSessionDictionary() - .GetItemForKey(PythonString(basename)) - .IsAllocated(); - - bool was_imported = (was_imported_globally || was_imported_locally); - - // now actually do the import - command_stream.Clear(); - - if (was_imported) { - if (!was_imported_locally) - command_stream.Printf("import %s ; reload_module(%s)", basename.c_str(), - basename.c_str()); - else - command_stream.Printf("reload_module(%s)", basename.c_str()); - } else - command_stream.Printf("import %s", basename.c_str()); - - error = ExecuteMultipleLines(command_stream.GetData(), - ScriptInterpreter::ExecuteScriptOptions() - .SetEnableIO(false) - .SetSetLLDBGlobals(false)); - if (error.Fail()) - return false; + // Strip .py or .pyc extension + llvm::StringRef extension = llvm::sys::path::extension(module_name); + if (!extension.empty()) { + if (extension == ".py") + module_name.resize(module_name.length() - 3); + else if (extension == ".pyc") + module_name.resize(module_name.length() - 4); + } - // if we are here, everything worked - // call __lldb_init_module(debugger,dict) - if (!LLDBSwigPythonCallModuleInit(basename.c_str(), - m_dictionary_name.c_str(), debugger_sp)) { - error.SetErrorString("calling __lldb_init_module failed"); - return false; - } + // check if the module is already import-ed + StreamString command_stream; + command_stream.Clear(); + command_stream.Printf("sys.modules.__contains__('%s')", module_name.c_str()); + bool does_contain = false; + // this call will succeed if the module was ever imported in any Debugger + // in the lifetime of the process in which this LLDB framework is living + bool was_imported_globally = + (ExecuteOneLineWithReturn( + command_stream.GetData(), + ScriptInterpreterPythonImpl::eScriptReturnTypeBool, &does_contain, + ScriptInterpreter::ExecuteScriptOptions() + .SetEnableIO(false) + .SetSetLLDBGlobals(false)) && + does_contain); + // this call will fail if the module was not imported in this Debugger + // before + command_stream.Clear(); + command_stream.Printf("sys.getrefcount(%s)", module_name.c_str()); + bool was_imported_locally = GetSessionDictionary() + .GetItemForKey(PythonString(module_name)) + .IsAllocated(); + + bool was_imported = (was_imported_globally || was_imported_locally); + + // now actually do the import + command_stream.Clear(); + + if (was_imported) { + if (!was_imported_locally) + command_stream.Printf("import %s ; reload_module(%s)", + module_name.c_str(), module_name.c_str()); + else + command_stream.Printf("reload_module(%s)", module_name.c_str()); + } else + command_stream.Printf("import %s", module_name.c_str()); + + error = ExecuteMultipleLines(command_stream.GetData(), + ScriptInterpreter::ExecuteScriptOptions() + .SetEnableIO(false) + .SetSetLLDBGlobals(false)); + if (error.Fail()) + return false; - if (module_sp) { - // everything went just great, now set the module object - command_stream.Clear(); - command_stream.Printf("%s", basename.c_str()); - void *module_pyobj = nullptr; - if (ExecuteOneLineWithReturn( - command_stream.GetData(), - ScriptInterpreter::eScriptReturnTypeOpaqueObject, - &module_pyobj) && - module_pyobj) - *module_sp = std::make_shared<StructuredPythonObject>(module_pyobj); - } + // if we are here, everything worked + // call __lldb_init_module(debugger,dict) + if (!LLDBSwigPythonCallModuleInit(module_name.c_str(), + m_dictionary_name.c_str(), debugger_sp)) { + error.SetErrorString("calling __lldb_init_module failed"); + return false; + } - return true; + if (module_sp) { + // everything went just great, now set the module object + command_stream.Clear(); + command_stream.Printf("%s", module_name.c_str()); + void *module_pyobj = nullptr; + if (ExecuteOneLineWithReturn( + command_stream.GetData(), + ScriptInterpreter::eScriptReturnTypeOpaqueObject, &module_pyobj) && + module_pyobj) + *module_sp = std::make_shared<StructuredPythonObject>(module_pyobj); } + + return true; } bool ScriptInterpreterPythonImpl::IsReservedWord(const char *word) { @@ -3154,8 +3238,7 @@ void ScriptInterpreterPythonImpl::InitializePrivate() { g_initialized = true; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); // RAII-based initialization which correctly handles multiple-initialization, // version- specific differences among Python 2 and Python 3, and saving and diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 22b2c8152eac..45dad4217005 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -106,6 +106,14 @@ public: StructuredData::GenericSP implementor_sp) override; StructuredData::GenericSP + CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, + StructuredDataImpl *args_data, Status &error) override; + + bool ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp, + ExecutionContext &exc_ctx, + lldb::StreamSP stream_sp) override; + + StructuredData::GenericSP CreateFrameRecognizer(const char *class_name) override; lldb::ValueObjectListSP @@ -223,10 +231,10 @@ public: bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value, std::string &output, Status &error) override; - bool - LoadScriptingModule(const char *filename, bool init_session, - lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr) override; + bool LoadScriptingModule(const char *filename, bool init_session, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp = nullptr, + FileSpec extra_search_dir = {}) override; bool IsReservedWord(const char *word) override; diff --git a/contrib/llvm-project/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/contrib/llvm-project/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp index 5ceaf886b812..f669e5873d2d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp @@ -666,7 +666,7 @@ private: // regex {search-regex} // Parse action. - auto action_end_pos = rule_text.find(" "); + auto action_end_pos = rule_text.find(' '); if (action_end_pos == std::string::npos) { error.SetErrorStringWithFormat("could not parse filter rule " "action from \"%s\"", diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp index eeec7296747e..07e5b284eab8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -326,7 +326,8 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { } const SectionList &list = *module.GetSectionList(); - llvm::DenseMap<addr_t, Symbol> symbols; + llvm::DenseSet<addr_t> found_symbol_addresses; + std::vector<Symbol> symbols; auto add_symbol = [&](addr_t address, llvm::Optional<addr_t> size, llvm::StringRef name) { address += base; @@ -338,8 +339,12 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { name, address); return; } - symbols.try_emplace( - address, /*symID*/ 0, Mangled(name), eSymbolTypeCode, + // Keep track of what addresses were already added so far and only add + // the symbol with the first address. + if (!found_symbol_addresses.insert(address).second) + return; + symbols.emplace_back( + /*symID*/ 0, Mangled(name), eSymbolTypeCode, /*is_global*/ true, /*is_debug*/ false, /*is_trampoline*/ false, /*is_artificial*/ false, AddressRange(section_sp, address - section_sp->GetFileAddress(), @@ -359,8 +364,8 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line); } - for (auto &KV : symbols) - symtab.AddSymbol(std::move(KV.second)); + for (Symbol &symbol : symbols) + symtab.AddSymbol(std::move(symbol)); symtab.CalculateSymbolSizes(); } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp index 33ab11a3ca40..60b6b726f6c0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -42,8 +42,8 @@ std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create( if (!apple_objc_table_up->IsValid()) apple_objc_table_up.reset(); - if (apple_names_table_up || apple_names_table_up || apple_types_table_up || - apple_objc_table_up) + if (apple_names_table_up || apple_namespaces_table_up || + apple_types_table_up || apple_objc_table_up) return std::make_unique<AppleDWARFIndex>( module, std::move(apple_names_table_up), std::move(apple_namespaces_table_up), std::move(apple_types_table_up), diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 2d1db66e7fd9..188a667ca564 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -209,11 +209,12 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, GetClangASTImporter().RequireCompleteType(ClangUtil::GetQualType(type)); SymbolFileDWARF *dwarf = die.GetDWARF(); - TypeSP type_sp(new Type( - die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(), - nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, - &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward, - TypePayloadClang(GetOwningClangModule(die)))); + TypeSP type_sp(new Type(die.GetID(), dwarf, pcm_type_sp->GetName(), + pcm_type_sp->GetByteSize(nullptr), nullptr, + LLDB_INVALID_UID, Type::eEncodingInvalid, + &pcm_type_sp->GetDeclaration(), type, + Type::ResolveState::Forward, + TypePayloadClang(GetOwningClangModule(die)))); dwarf->GetTypeList().Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); @@ -229,31 +230,73 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, return type_sp; } -static void CompleteExternalTagDeclType(TypeSystemClang &ast, - ClangASTImporter &ast_importer, - clang::DeclContext *decl_ctx, - DWARFDIE die, - const char *type_name_cstr) { +static void ForcefullyCompleteType(CompilerType type) { + bool started = TypeSystemClang::StartTagDeclarationDefinition(type); + lldbassert(started && "Unable to start a class type definition."); + TypeSystemClang::CompleteTagDeclarationDefinition(type); + const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type); + auto &ts = llvm::cast<TypeSystemClang>(*type.GetTypeSystem()); + ts.GetMetadata(td)->SetIsForcefullyCompleted(); +} + +/// Complete a type from debug info, or mark it as forcefully completed if +/// there is no definition of the type in the current Module. Call this function +/// in contexts where the usual C++ rules require a type to be complete (base +/// class, member, etc.). +static void RequireCompleteType(CompilerType type) { + // Technically, enums can be incomplete too, but we don't handle those as they + // are emitted even under -flimit-debug-info. + if (!TypeSystemClang::IsCXXClassType(type)) + return; + + if (type.GetCompleteType()) + return; + + // No complete definition in this module. Mark the class as complete to + // satisfy local ast invariants, but make a note of the fact that + // it is not _really_ complete so we can later search for a definition in a + // different module. + // Since we provide layout assistance, layouts of types containing this class + // will be correct even if we are not able to find the definition elsewhere. + ForcefullyCompleteType(type); +} + +/// This function serves a similar purpose as RequireCompleteType above, but it +/// avoids completing the type if it is not immediately necessary. It only +/// ensures we _can_ complete the type later. +static void PrepareContextToReceiveMembers(TypeSystemClang &ast, + ClangASTImporter &ast_importer, + clang::DeclContext *decl_ctx, + DWARFDIE die, + const char *type_name_cstr) { auto *tag_decl_ctx = clang::dyn_cast<clang::TagDecl>(decl_ctx); if (!tag_decl_ctx) + return; // Non-tag context are always ready. + + // We have already completed the type, or we have found its definition and are + // ready to complete it later (cf. ParseStructureLikeDIE). + if (tag_decl_ctx->isCompleteDefinition() || tag_decl_ctx->isBeingDefined()) return; + // We reach this point of the tag was present in the debug info as a + // declaration only. If it was imported from another AST context (in the + // gmodules case), we can complete the type by doing a full import. + // If this type was not imported from an external AST, there's nothing to do. CompilerType type = ast.GetTypeForDecl(tag_decl_ctx); - if (!type || !ast_importer.CanImport(type)) - return; - - auto qual_type = ClangUtil::GetQualType(type); - if (!ast_importer.RequireCompleteType(qual_type)) { + if (type && ast_importer.CanImport(type)) { + auto qual_type = ClangUtil::GetQualType(type); + if (ast_importer.RequireCompleteType(qual_type)) + return; die.GetDWARF()->GetObjectFile()->GetModule()->ReportError( "Unable to complete the Decl context for DIE '%s' at offset " "0x%8.8x.\nPlease file a bug report.", type_name_cstr ? type_name_cstr : "", die.GetOffset()); - // We need to make the type look complete otherwise, we might crash in - // Clang when adding children. - if (TypeSystemClang::StartTagDeclarationDefinition(type)) - TypeSystemClang::CompleteTagDeclarationDefinition(type); } + + // We don't have a type definition and/or the import failed. We must + // forcefully complete the type to avoid crashes. + ForcefullyCompleteType(type); } ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { @@ -298,7 +341,9 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { break; case DW_AT_decl_file: - decl.SetFile(die.GetCU()->GetFile(form_value.Unsigned())); + // die.GetCU() can differ if DW_AT_specification uses DW_FORM_ref_addr. + decl.SetFile( + attributes.CompileUnitAtIndex(i)->GetFile(form_value.Unsigned())); break; case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); @@ -513,42 +558,51 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, TypeSP type_sp; CompilerType clang_type; - if (tag == DW_TAG_typedef && attrs.type.IsValid()) { - // Try to parse a typedef from the (DWARF embedded in the) Clang - // module file first as modules can contain typedef'ed - // structures that have no names like: - // - // typedef struct { int a; } Foo; - // - // In this case we will have a structure with no name and a - // typedef named "Foo" that points to this unnamed - // structure. The name in the typedef is the only identifier for - // the struct, so always try to get typedefs from Clang modules - // if possible. - // - // The type_sp returned will be empty if the typedef doesn't - // exist in a module file, so it is cheap to call this function - // just to check. - // - // If we don't do this we end up creating a TypeSP that says - // this is a typedef to type 0x123 (the DW_AT_type value would - // be 0x123 in the DW_TAG_typedef), and this is the unnamed - // structure type. We will have a hard time tracking down an - // unnammed structure type in the module debug info, so we make - // sure we don't get into this situation by always resolving - // typedefs from the module. - const DWARFDIE encoding_die = attrs.type.Reference(); - - // First make sure that the die that this is typedef'ed to _is_ - // just a declaration (DW_AT_declaration == 1), not a full - // definition since template types can't be represented in - // modules since only concrete instances of templates are ever - // emitted and modules won't contain those - if (encoding_die && - encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { - type_sp = ParseTypeFromClangModule(sc, die, log); - if (type_sp) - return type_sp; + if (tag == DW_TAG_typedef) { + // DeclContext will be populated when the clang type is materialized in + // Type::ResolveCompilerType. + PrepareContextToReceiveMembers( + m_ast, GetClangASTImporter(), + GetClangDeclContextContainingDIE(die, nullptr), die, + attrs.name.GetCString()); + + if (attrs.type.IsValid()) { + // Try to parse a typedef from the (DWARF embedded in the) Clang + // module file first as modules can contain typedef'ed + // structures that have no names like: + // + // typedef struct { int a; } Foo; + // + // In this case we will have a structure with no name and a + // typedef named "Foo" that points to this unnamed + // structure. The name in the typedef is the only identifier for + // the struct, so always try to get typedefs from Clang modules + // if possible. + // + // The type_sp returned will be empty if the typedef doesn't + // exist in a module file, so it is cheap to call this function + // just to check. + // + // If we don't do this we end up creating a TypeSP that says + // this is a typedef to type 0x123 (the DW_AT_type value would + // be 0x123 in the DW_TAG_typedef), and this is the unnamed + // structure type. We will have a hard time tracking down an + // unnammed structure type in the module debug info, so we make + // sure we don't get into this situation by always resolving + // typedefs from the module. + const DWARFDIE encoding_die = attrs.type.Reference(); + + // First make sure that the die that this is typedef'ed to _is_ + // just a declaration (DW_AT_declaration == 1), not a full + // definition since template types can't be represented in + // modules since only concrete instances of templates are ever + // emitted and modules won't contain those + if (encoding_die && + encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { + type_sp = ParseTypeFromClangModule(sc, die, log); + if (type_sp) + return type_sp; + } } } @@ -810,7 +864,7 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, bool is_signed = false; enumerator_clang_type.IsIntegerType(is_signed); ParseChildEnumerators(clang_type, is_signed, - type_sp->GetByteSize().getValueOr(0), die); + type_sp->GetByteSize(nullptr).getValueOr(0), die); } TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); } else { @@ -1172,7 +1226,7 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, } if (!function_decl) { - const char *name = attrs.name.GetCString(); + llvm::StringRef name = attrs.name.GetStringRef(); // We currently generate function templates with template parameters in // their name. In order to get closer to the AST that clang generates @@ -1196,12 +1250,12 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - GetOwningClangModule(die), attrs.name.GetCString(), clang_type, + GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type, attrs.storage, attrs.is_inline); clang::FunctionTemplateDecl *func_template_decl = m_ast.CreateFunctionTemplateDecl( containing_decl_ctx, GetOwningClangModule(die), - template_function_decl, name, template_param_infos); + template_function_decl, template_param_infos); m_ast.CreateFunctionTemplateSpecializationInfo( template_function_decl, func_template_decl, template_param_infos); } @@ -1261,9 +1315,9 @@ TypeSP DWARFASTParserClang::ParseArrayType(const DWARFDIE &die, attrs.bit_stride = array_info->bit_stride; } if (attrs.byte_stride == 0 && attrs.bit_stride == 0) - attrs.byte_stride = element_type->GetByteSize().getValueOr(0); + attrs.byte_stride = element_type->GetByteSize(nullptr).getValueOr(0); CompilerType array_element_type = element_type->GetForwardCompilerType(); - CompleteType(array_element_type); + RequireCompleteType(array_element_type); uint64_t array_element_bit_stride = attrs.byte_stride * 8 + attrs.bit_stride; @@ -1318,28 +1372,6 @@ TypeSP DWARFASTParserClang::ParsePointerToMemberType( return nullptr; } -void DWARFASTParserClang::CompleteType(CompilerType type) { - // Technically, enums can be incomplete too, but we don't handle those as they - // are emitted even under -flimit-debug-info. - if (!TypeSystemClang::IsCXXClassType(type)) - return; - - if (type.GetCompleteType()) - return; - - // No complete definition in this module. Mark the class as complete to - // satisfy local ast invariants, but make a note of the fact that - // it is not _really_ complete so we can later search for a definition in a - // different module. - // Since we provide layout assistance, layouts of types containing this class - // will be correct even if we are not able to find the definition elsewhere. - bool started = TypeSystemClang::StartTagDeclarationDefinition(type); - lldbassert(started && "Unable to start a class type definition."); - TypeSystemClang::CompleteTagDeclarationDefinition(type); - const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type); - m_ast.GetMetadata(td)->SetIsForcefullyCompleted(); -} - TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( const SymbolContext &sc, const DWARFDIE &die, TypeSP type_sp) { if (!type_sp) @@ -1559,13 +1591,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); - // If your decl context is a record that was imported from another - // AST context (in the gmodules case), we need to make sure the type - // backing the Decl is complete before adding children to it. This is - // not an issue in the non-gmodules case because the debug info will - // always contain a full definition of parent types in that case. - CompleteExternalTagDeclType(m_ast, GetClangASTImporter(), decl_ctx, die, - attrs.name.GetCString()); + PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(), decl_ctx, die, + attrs.name.GetCString()); if (attrs.accessibility == eAccessNone && decl_ctx) { // Check the decl context that contains this class/struct/union. If @@ -1640,33 +1667,6 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, dwarf->GetUniqueDWARFASTTypeMap().Insert(unique_typename, *unique_ast_entry_up); - if (attrs.is_forward_declaration && die.HasChildren()) { - // Check to see if the DIE actually has a definition, some version of - // GCC will - // emit DIEs with DW_AT_declaration set to true, but yet still have - // subprogram, members, or inheritance, so we can't trust it - DWARFDIE child_die = die.GetFirstChild(); - while (child_die) { - switch (child_die.Tag()) { - case DW_TAG_inheritance: - case DW_TAG_subprogram: - case DW_TAG_member: - case DW_TAG_APPLE_property: - case DW_TAG_class_type: - case DW_TAG_structure_type: - case DW_TAG_enumeration_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - child_die.Clear(); - attrs.is_forward_declaration = false; - break; - default: - child_die = child_die.GetSibling(); - break; - } - } - } - if (!attrs.is_forward_declaration) { // Always start the definition for a class type so that if the class // has child classes or types that require the class to be created @@ -1944,8 +1944,6 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( break; } } - if (template_param_infos.args.empty()) - return false; return template_param_infos.args.size() == template_param_infos.names.size(); } @@ -2042,7 +2040,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); if (type_source_info) - CompleteType(m_ast.GetType(type_source_info->getType())); + RequireCompleteType(m_ast.GetType(type_source_info->getType())); } m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), @@ -2057,7 +2055,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, if (!layout_info.field_offsets.empty() || !layout_info.base_offsets.empty() || !layout_info.vbase_offsets.empty()) { if (type) - layout_info.bit_size = type->GetByteSize().getValueOr(0) * 8; + layout_info.bit_size = type->GetByteSize(nullptr).getValueOr(0) * 8; if (layout_info.bit_size == 0) layout_info.bit_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; @@ -2079,7 +2077,7 @@ bool DWARFASTParserClang::CompleteEnumType(const DWARFDIE &die, bool is_signed = false; clang_type.IsIntegerType(is_signed); ParseChildEnumerators(clang_type, is_signed, - type->GetByteSize().getValueOr(0), die); + type->GetByteSize(nullptr).getValueOr(0), die); } TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); } @@ -2567,7 +2565,7 @@ void DWARFASTParserClang::ParseSingleMember( this_field_info.bit_offset = data_bit_offset; } else { if (!byte_size) - byte_size = member_type->GetByteSize(); + byte_size = member_type->GetByteSize(nullptr); ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); if (objfile->GetByteOrder() == eByteOrderLittle) { @@ -2578,10 +2576,18 @@ void DWARFASTParserClang::ParseSingleMember( } } - if ((this_field_info.bit_offset >= parent_bit_size) || - (last_field_info.IsBitfield() && - !last_field_info.NextBitfieldOffsetIsValid( - this_field_info.bit_offset))) { + // The ObjC runtime knows the byte offset but we still need to provide + // the bit-offset in the layout. It just means something different then + // what it does in C and C++. So we skip this check for ObjC types. + // + // We also skip this for fields of a union since they will all have a + // zero offset. + if (!TypeSystemClang::IsObjCObjectOrInterfaceType(class_clang_type) && + !(parent_die.Tag() == DW_TAG_union_type && this_field_info.bit_offset == 0) && + ((this_field_info.bit_offset >= parent_bit_size) || + (last_field_info.IsBitfield() && + !last_field_info.NextBitfieldOffsetIsValid( + this_field_info.bit_offset)))) { ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); objfile->GetModule()->ReportWarning( "0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid " @@ -2707,7 +2713,7 @@ void DWARFASTParserClang::ParseSingleMember( } } - CompleteType(member_clang_type); + RequireCompleteType(member_clang_type); field_decl = TypeSystemClang::AddFieldToRecordType( class_clang_type, name, member_clang_type, accessibility, @@ -3043,88 +3049,85 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die, for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) { const dw_tag_t tag = die.Tag(); - switch (tag) { - case DW_TAG_subrange_type: { - DWARFAttributes attributes; - const size_t num_child_attributes = die.GetAttributes(attributes); - if (num_child_attributes > 0) { - uint64_t num_elements = 0; - uint64_t lower_bound = 0; - uint64_t upper_bound = 0; - bool upper_bound_valid = false; - uint32_t i; - for (i = 0; i < num_child_attributes; ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - break; + if (tag != DW_TAG_subrange_type) + continue; - case DW_AT_count: - if (DWARFDIE var_die = die.GetReferencedDIE(DW_AT_count)) { - if (var_die.Tag() == DW_TAG_variable) - if (exe_ctx) { - if (auto frame = exe_ctx->GetFrameSP()) { - Status error; - lldb::VariableSP var_sp; - auto valobj_sp = frame->GetValueForVariableExpressionPath( - var_die.GetName(), eNoDynamicValues, 0, var_sp, - error); - if (valobj_sp) { - num_elements = valobj_sp->GetValueAsUnsigned(0); - break; - } + DWARFAttributes attributes; + const size_t num_child_attributes = die.GetAttributes(attributes); + if (num_child_attributes > 0) { + uint64_t num_elements = 0; + uint64_t lower_bound = 0; + uint64_t upper_bound = 0; + bool upper_bound_valid = false; + uint32_t i; + for (i = 0; i < num_child_attributes; ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + case DW_AT_name: + break; + + case DW_AT_count: + if (DWARFDIE var_die = die.GetReferencedDIE(DW_AT_count)) { + if (var_die.Tag() == DW_TAG_variable) + if (exe_ctx) { + if (auto frame = exe_ctx->GetFrameSP()) { + Status error; + lldb::VariableSP var_sp; + auto valobj_sp = frame->GetValueForVariableExpressionPath( + var_die.GetName(), eNoDynamicValues, 0, var_sp, + error); + if (valobj_sp) { + num_elements = valobj_sp->GetValueAsUnsigned(0); + break; } } - } else - num_elements = form_value.Unsigned(); - break; + } + } else + num_elements = form_value.Unsigned(); + break; - case DW_AT_bit_stride: - array_info.bit_stride = form_value.Unsigned(); - break; + case DW_AT_bit_stride: + array_info.bit_stride = form_value.Unsigned(); + break; - case DW_AT_byte_stride: - array_info.byte_stride = form_value.Unsigned(); - break; + case DW_AT_byte_stride: + array_info.byte_stride = form_value.Unsigned(); + break; - case DW_AT_lower_bound: - lower_bound = form_value.Unsigned(); - break; + case DW_AT_lower_bound: + lower_bound = form_value.Unsigned(); + break; - case DW_AT_upper_bound: - upper_bound_valid = true; - upper_bound = form_value.Unsigned(); - break; + case DW_AT_upper_bound: + upper_bound_valid = true; + upper_bound = form_value.Unsigned(); + break; - default: - case DW_AT_abstract_origin: - case DW_AT_accessibility: - case DW_AT_allocated: - case DW_AT_associated: - case DW_AT_data_location: - case DW_AT_declaration: - case DW_AT_description: - case DW_AT_sibling: - case DW_AT_threads_scaled: - case DW_AT_type: - case DW_AT_visibility: - break; - } + default: + case DW_AT_abstract_origin: + case DW_AT_accessibility: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_data_location: + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_sibling: + case DW_AT_threads_scaled: + case DW_AT_type: + case DW_AT_visibility: + break; } } + } - if (num_elements == 0) { - if (upper_bound_valid && upper_bound >= lower_bound) - num_elements = upper_bound - lower_bound + 1; - } - - array_info.element_orders.push_back(num_elements); + if (num_elements == 0) { + if (upper_bound_valid && upper_bound >= lower_bound) + num_elements = upper_bound - lower_bound + 1; } - } break; - default: - break; + + array_info.element_orders.push_back(num_elements); } } return array_info; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 2ef49abc1da1..e13716b95c1c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -217,12 +217,6 @@ private: ParsedDWARFTypeAttributes &attrs); lldb::TypeSP ParsePointerToMemberType(const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs); - - /// Complete a type from debug info, or mark it as forcefully completed if - /// there is no of the type in the current Module. Call this function in - /// contexts where the usual C++ rules require a type to be complete (base - /// class, member, etc.). - void CompleteType(lldb_private::CompilerType type); }; /// Parsed form of all attributes that are relevant for type reconstruction. diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp index 6c72d9e26221..ef98d7e33a90 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -25,7 +25,7 @@ uint32_t DWARFAttributes::FindAttributeIndex(dw_attr_t attr) const { return UINT32_MAX; } -void DWARFAttributes::Append(const DWARFUnit *cu, dw_offset_t attr_die_offset, +void DWARFAttributes::Append(DWARFUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form) { AttributeValue attr_value = { cu, attr_die_offset, {attr, form, DWARFFormValue::ValueType()}}; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h index 9948969f108f..8c21404610d7 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h @@ -52,11 +52,9 @@ public: DWARFAttributes(); ~DWARFAttributes(); - void Append(const DWARFUnit *cu, dw_offset_t attr_die_offset, - dw_attr_t attr, dw_form_t form); - const DWARFUnit *CompileUnitAtIndex(uint32_t i) const { - return m_infos[i].cu; - } + void Append(DWARFUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, + dw_form_t form); + DWARFUnit *CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; } dw_offset_t DIEOffsetAtIndex(uint32_t i) const { return m_infos[i].die_offset; } @@ -73,8 +71,8 @@ public: protected: struct AttributeValue { - const DWARFUnit *cu; // Keep the compile unit with each attribute in - // case we have DW_FORM_ref_addr values + DWARFUnit *cu; // Keep the compile unit with each attribute in + // case we have DW_FORM_ref_addr values dw_offset_t die_offset; DWARFAttribute attr; }; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index f54fe0662aa2..9ca160b474fc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -99,3 +99,18 @@ void DWARFCompileUnit::BuildAddressRangeTable( } } } + +DWARFCompileUnit &DWARFCompileUnit::GetNonSkeletonUnit() { + return llvm::cast<DWARFCompileUnit>(DWARFUnit::GetNonSkeletonUnit()); +} + +DWARFDIE DWARFCompileUnit::LookupAddress(const dw_addr_t address) { + if (DIE()) { + const DWARFDebugAranges &func_aranges = GetFunctionAranges(); + + // Re-check the aranges auto pointer contents in case it was created above + if (!func_aranges.IsEmpty()) + return GetDIE(func_aranges.FindAddress(address)); + } + return DWARFDIE(); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 3ec161f7dd51..ab3017ba0ffc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -20,6 +20,10 @@ public: static bool classof(const DWARFUnit *unit) { return !unit->IsTypeUnit(); } + DWARFCompileUnit &GetNonSkeletonUnit(); + + DWARFDIE LookupAddress(const dw_addr_t address); + private: DWARFCompileUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index 7dc52c1e2df0..9f190fbcee87 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -39,7 +39,7 @@ DWARFDebugAranges::extract(const DWARFDataExtractor &debug_aranges_data) { Range range; while (debug_aranges_data.ValidOffset(offset)) { llvm::Error error = set.extract(debug_aranges_data, &offset); - if (!error) + if (error) return error; const uint32_t num_descriptors = set.NumDescriptors(); @@ -78,8 +78,7 @@ void DWARFDebugAranges::AppendRange(dw_offset_t offset, dw_addr_t low_pc, } void DWARFDebugAranges::Sort(bool minimize) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, + LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, static_cast<void *>(this)); m_aranges.Sort(); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 874978bf1398..8d393b295443 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -199,4 +199,3 @@ DWARFDebugInfo::GetDIE(const DIERef &die_ref) { return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset()); return DWARFDIE(); // Not found } - diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index f6425a889da8..421298802645 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -399,7 +399,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( // specification or abstract origin attributes and including those in the // results. Any duplicate attributes will have the first instance take // precedence (this can happen for declaration attributes). -size_t DWARFDebugInfoEntry::GetAttributes(const DWARFUnit *cu, +size_t DWARFDebugInfoEntry::GetAttributes(DWARFUnit *cu, DWARFAttributes &attributes, Recurse recurse, uint32_t curr_depth) const { @@ -687,13 +687,15 @@ const char *DWARFDebugInfoEntry::GetPubname(const DWARFUnit *cu) const { /// table, except that the actual DIE offset for the function is placed in the /// table instead of the compile unit offset. void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( - const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { + DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { if (m_tag) { if (m_tag == DW_TAG_subprogram) { - dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; - dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; - if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) { - debug_aranges->AppendRange(GetOffset(), lo_pc, hi_pc); + DWARFRangeList ranges; + GetAttributeAddressRanges(cu, ranges, + /*check_hi_lo_pc=*/true); + for (const auto &r : ranges) { + debug_aranges->AppendRange(GetOffset(), r.GetRangeBase(), + r.GetRangeEnd()); } } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 3019e1767f18..0ba56a0a4161 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -42,14 +42,14 @@ public: bool operator==(const DWARFDebugInfoEntry &rhs) const; bool operator!=(const DWARFDebugInfoEntry &rhs) const; - void BuildFunctionAddressRangeTable(const DWARFUnit *cu, + void BuildFunctionAddressRangeTable(DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; bool Extract(const lldb_private::DWARFDataExtractor &data, const DWARFUnit *cu, lldb::offset_t *offset_ptr); using Recurse = DWARFBaseDIE::Recurse; - size_t GetAttributes(const DWARFUnit *cu, DWARFAttributes &attrs, + size_t GetAttributes(DWARFUnit *cu, DWARFAttributes &attrs, Recurse recurse = Recurse::yes) const { return GetAttributes(cu, attrs, recurse, 0 /* curr_depth */); } @@ -180,8 +180,8 @@ protected: dw_tag_t m_tag = llvm::dwarf::DW_TAG_null; private: - size_t GetAttributes(const DWARFUnit *cu, DWARFAttributes &attrs, - Recurse recurse, uint32_t curr_depth) const; + size_t GetAttributes(DWARFUnit *cu, DWARFAttributes &attrs, Recurse recurse, + uint32_t curr_depth) const; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index b401352c693d..fe6a55520978 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -42,6 +42,7 @@ public: DWARFFormValue(const DWARFUnit *unit) : m_unit(unit) {} DWARFFormValue(const DWARFUnit *unit, dw_form_t form) : m_unit(unit), m_form(form) {} + const DWARFUnit *GetUnit() const { return m_unit; } void SetUnit(const DWARFUnit *unit) { m_unit = unit; } dw_form_t Form() const { return m_form; } dw_form_t& FormRef() { return m_form; } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index dfa40759a7ff..a761dd3daac4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -34,7 +34,8 @@ DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo) : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs), - m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo) {} + m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo), + m_dwo_id(header.GetDWOId()) {} DWARFUnit::~DWARFUnit() = default; @@ -49,9 +50,7 @@ void DWARFUnit::ExtractUnitDIEIfNeeded() { if (m_first_die) return; // Already parsed - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", - GetOffset()); + LLDB_SCOPED_TIMERF("%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", GetOffset()); // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. @@ -145,9 +144,7 @@ DWARFUnit::ScopedExtractDIEs &DWARFUnit::ScopedExtractDIEs::operator=( void DWARFUnit::ExtractDIEsRWLocked() { llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", - GetOffset()); + LLDB_SCOPED_TIMERF("%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", GetOffset()); // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. @@ -288,6 +285,11 @@ void DWARFUnit::SetDwoStrOffsetsBase() { SetStrOffsetsBase(baseOffset); } +uint64_t DWARFUnit::GetDWOId() { + ExtractUnitDIEIfNeeded(); + return m_dwo_id; +} + // m_die_array_mutex must be already held as read/write. void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { llvm::Optional<uint64_t> addr_base, gnu_addr_base, ranges_base, @@ -341,6 +343,9 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { case DW_AT_GNU_ranges_base: gnu_ranges_base = form_value.Unsigned(); break; + case DW_AT_GNU_dwo_id: + m_dwo_id = form_value.Unsigned(); + break; } } @@ -354,9 +359,8 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { if (!dwo_symbol_file) return; - uint64_t main_dwo_id = - cu_die.GetAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, 0); - DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(main_dwo_id); + DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(m_dwo_id); + if (!dwo_cu) return; // Can't fetch the compile unit from the dwo file. dwo_cu->SetUserData(this); @@ -392,17 +396,6 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { m_dwo = std::shared_ptr<DWARFUnit>(std::move(dwo_symbol_file), dwo_cu); } -DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { - if (DIE()) { - const DWARFDebugAranges &func_aranges = GetFunctionAranges(); - - // Re-check the aranges auto pointer contents in case it was created above - if (!func_aranges.IsEmpty()) - return GetDIE(func_aranges.FindAddress(address)); - } - return DWARFDIE(); -} - size_t DWARFUnit::GetDebugInfoSize() const { return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); } @@ -536,21 +529,23 @@ static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, // DIE from this compile unit. Otherwise we grab the DIE from the DWARF file. DWARFDIE DWARFUnit::GetDIE(dw_offset_t die_offset) { - if (die_offset != DW_INVALID_OFFSET) { - if (ContainsDIEOffset(die_offset)) { - ExtractDIEsIfNeeded(); - DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); - DWARFDebugInfoEntry::const_iterator pos = - lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset); - if (pos != end) { - if (die_offset == (*pos).GetOffset()) - return DWARFDIE(this, &(*pos)); - } - } else - GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( - "GetDIE for DIE 0x%" PRIx32 " is outside of its CU 0x%" PRIx32, - die_offset, GetOffset()); + if (die_offset == DW_INVALID_OFFSET) + return DWARFDIE(); // Not found + + if (!ContainsDIEOffset(die_offset)) { + GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "GetDIE for DIE 0x%" PRIx32 " is outside of its CU 0x%" PRIx32, + die_offset, GetOffset()); + return DWARFDIE(); // Not found } + + ExtractDIEsIfNeeded(); + DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); + DWARFDebugInfoEntry::const_iterator pos = + lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset); + + if (pos != end && die_offset == (*pos).GetOffset()) + return DWARFDIE(this, &(*pos)); return DWARFDIE(); // Not found } @@ -801,7 +796,8 @@ DWARFUnitHeader::extract(const DWARFDataExtractor &data, header.m_unit_type = data.GetU8(offset_ptr); header.m_addr_size = data.GetU8(offset_ptr); header.m_abbr_offset = data.GetDWARFOffset(offset_ptr); - if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton) + if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton || + header.m_unit_type == llvm::dwarf::DW_UT_split_compile) header.m_dwo_id = data.GetU64(offset_ptr); } else { header.m_abbr_offset = data.GetDWARFOffset(offset_ptr); @@ -946,7 +942,7 @@ DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { llvm::Expected<llvm::DWARFAddressRangesVector> llvm_ranges = range_list_or_error->getAbsoluteRanges( llvm::object::SectionedAddress{GetBaseAddress()}, - [&](uint32_t index) { + GetAddressByteSize(), [&](uint32_t index) { uint32_t index_size = GetAddressByteSize(); dw_offset_t addr_base = GetAddrBase(); lldb::offset_t offset = addr_base + index * index_size; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index affad286a490..5739c36bbacb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -65,6 +65,7 @@ public: } uint64_t GetTypeHash() const { return m_type_hash; } dw_offset_t GetTypeOffset() const { return m_type_offset; } + uint64_t GetDWOId() const { return m_dwo_id; } bool IsTypeUnit() const { return m_unit_type == DW_UT_type || m_unit_type == DW_UT_split_type; } @@ -88,6 +89,7 @@ public: virtual ~DWARFUnit(); bool IsDWOUnit() { return m_is_dwo; } + uint64_t GetDWOId(); void ExtractUnitDIEIfNeeded(); void ExtractDIEsIfNeeded(); @@ -105,7 +107,6 @@ public: }; ScopedExtractDIEs ExtractDIEsScoped(); - DWARFDIE LookupAddress(const dw_addr_t address); bool Verify(lldb_private::Stream *s) const; virtual void Dump(lldb_private::Stream *s) const = 0; /// Get the data that contains the DIE information for this unit. @@ -167,7 +168,7 @@ public: void SetBaseAddress(dw_addr_t base_addr); - DWARFBaseDIE GetUnitDIEOnly() { return DWARFDIE(this, GetUnitDIEPtrOnly()); } + DWARFBaseDIE GetUnitDIEOnly() { return {this, GetUnitDIEPtrOnly()}; } DWARFDIE DIE() { return DWARFDIE(this, DIEPtr()); } @@ -237,7 +238,9 @@ public: llvm::Optional<uint64_t> GetRnglistOffset(uint32_t Index) const { if (!m_rnglist_table) return llvm::None; - if (llvm::Optional<uint64_t> off = m_rnglist_table->getOffsetEntry(Index)) + if (llvm::Optional<uint64_t> off = m_rnglist_table->getOffsetEntry( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), + Index)) return *off + m_ranges_base; return llvm::None; } @@ -246,7 +249,8 @@ public: if (!m_loclist_table_header) return llvm::None; - llvm::Optional<uint64_t> Offset = m_loclist_table_header->getOffsetEntry(Index); + llvm::Optional<uint64_t> Offset = m_loclist_table_header->getOffsetEntry( + m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVM(), Index); if (!Offset) return llvm::None; return *Offset + m_loclists_base; @@ -331,6 +335,8 @@ protected: const DIERef::Section m_section; bool m_is_dwo; + /// Value of DW_AT_GNU_dwo_id (v4) or dwo_id from CU header (v5). + uint64_t m_dwo_id; private: void ParseProducerInfo(); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 7bf4b52bc783..dda599baffeb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -28,8 +28,7 @@ void ManualDWARFIndex::Index() { SymbolFileDWARF &main_dwarf = *m_dwarf; m_dwarf = nullptr; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%p", static_cast<void *>(&main_dwarf)); + LLDB_SCOPED_TIMERF("%p", static_cast<void *>(&main_dwarf)); DWARFDebugInfo &main_info = main_dwarf.DebugInfo(); SymbolFileDWARFDwo *dwp_dwarf = main_dwarf.GetDwpSymbolFile().get(); @@ -73,7 +72,7 @@ void ManualDWARFIndex::Index() { // Share one thread pool across operations to avoid the overhead of // recreating the threads. - llvm::ThreadPool pool; + llvm::ThreadPool pool(llvm::optimal_concurrency(units_to_index.size())); // Create a task runner that extracts dies for each DWARF unit in a // separate thread. diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 0b7e31ae2d1d..3656c7333f27 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -35,6 +35,7 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/CompileUnit.h" @@ -372,24 +373,23 @@ void SymbolFileDWARF::GetTypes(SymbolContextScope *sc_scope, TypeSet type_set; CompileUnit *comp_unit = nullptr; - DWARFUnit *dwarf_cu = nullptr; if (sc_scope) comp_unit = sc_scope->CalculateSymbolContextCompileUnit(); - if (comp_unit) { - dwarf_cu = GetDWARFCompileUnit(comp_unit); - if (!dwarf_cu) + const auto &get = [&](DWARFUnit *unit) { + if (!unit) return; - GetTypes(dwarf_cu->DIE(), dwarf_cu->GetOffset(), - dwarf_cu->GetNextUnitOffset(), type_mask, type_set); + unit = &unit->GetNonSkeletonUnit(); + GetTypes(unit->DIE(), unit->GetOffset(), unit->GetNextUnitOffset(), + type_mask, type_set); + }; + if (comp_unit) { + get(GetDWARFCompileUnit(comp_unit)); } else { DWARFDebugInfo &info = DebugInfo(); const size_t num_cus = info.GetNumUnits(); - for (size_t cu_idx = 0; cu_idx < num_cus; ++cu_idx) { - dwarf_cu = info.GetUnitAtIndex(cu_idx); - if (dwarf_cu) - GetTypes(dwarf_cu->DIE(), 0, UINT32_MAX, type_mask, type_set); - } + for (size_t cu_idx = 0; cu_idx < num_cus; ++cu_idx) + get(info.GetUnitAtIndex(cu_idx)); } std::set<CompilerType> compiler_type_set; @@ -624,16 +624,14 @@ DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { DWARFDebugInfo &SymbolFileDWARF::DebugInfo() { llvm::call_once(m_info_once_flag, [&] { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, + LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, static_cast<void *>(this)); m_info = std::make_unique<DWARFDebugInfo>(*this, m_context); }); return *m_info; } -DWARFUnit * -SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { +DWARFCompileUnit *SymbolFileDWARF::GetDWARFCompileUnit(CompileUnit *comp_unit) { if (!comp_unit) return nullptr; @@ -641,13 +639,14 @@ SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(comp_unit->GetID()); if (dwarf_cu && dwarf_cu->GetUserData() == nullptr) dwarf_cu->SetUserData(comp_unit); - return dwarf_cu; + + // It must be DWARFCompileUnit when it created a CompileUnit. + return llvm::cast_or_null<DWARFCompileUnit>(dwarf_cu); } DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { if (!m_ranges) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, + LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, static_cast<void *>(this)); if (m_context.getOrLoadRangesData().GetByteSize() > 0) @@ -829,8 +828,7 @@ XcodeSDK SymbolFileDWARF::ParseXcodeSDK(CompileUnit &comp_unit) { } size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolFileDWARF::ParseFunctions"); + LLDB_SCOPED_TIMER(); std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (!dwarf_cu) @@ -1267,9 +1265,10 @@ user_id_t SymbolFileDWARF::GetUID(DIERef ref) { if (GetDebugMapSymfile()) return GetID() | ref.die_offset(); - return user_id_t(GetDwoNum().getValueOr(0x7fffffff)) << 32 | - ref.die_offset() | - (lldb::user_id_t(ref.section() == DIERef::Section::DebugTypes) << 63); + lldbassert(GetDwoNum().getValueOr(0) <= 0x3fffffff); + return user_id_t(GetDwoNum().getValueOr(0)) << 32 | ref.die_offset() | + lldb::user_id_t(GetDwoNum().hasValue()) << 62 | + lldb::user_id_t(ref.section() == DIERef::Section::DebugTypes) << 63; } llvm::Optional<SymbolFileDWARF::DecodedUID> @@ -1297,9 +1296,10 @@ SymbolFileDWARF::DecodeUID(lldb::user_id_t uid) { DIERef::Section section = uid >> 63 ? DIERef::Section::DebugTypes : DIERef::Section::DebugInfo; - llvm::Optional<uint32_t> dwo_num = uid >> 32 & 0x7fffffff; - if (*dwo_num == 0x7fffffff) - dwo_num = llvm::None; + llvm::Optional<uint32_t> dwo_num; + bool dwo_valid = uid >> 62 & 1; + if (dwo_valid) + dwo_num = uid >> 32 & 0x3fffffff; return DecodedUID{*this, {dwo_num, section, die_offset}}; } @@ -1599,8 +1599,7 @@ static uint64_t GetDWOId(DWARFCompileUnit &dwarf_cu, llvm::Optional<uint64_t> SymbolFileDWARF::GetDWOId() { if (GetNumCompileUnits() == 1) { if (auto comp_unit = GetCompileUnitAtIndex(0)) - if (DWARFCompileUnit *cu = llvm::dyn_cast_or_null<DWARFCompileUnit>( - GetDWARFCompileUnit(comp_unit.get()))) + if (DWARFCompileUnit *cu = GetDWARFCompileUnit(comp_unit.get())) if (DWARFDebugInfoEntry *cu_die = cu->DIE().GetDIE()) if (uint64_t dwo_id = ::GetDWOId(*cu, *cu_die)) return dwo_id; @@ -1791,7 +1790,7 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() { lldb::addr_t byte_size = 1; if (var_sp->GetType()) byte_size = - var_sp->GetType()->GetByteSize().getValueOr(0); + var_sp->GetType()->GetByteSize(nullptr).getValueOr(0); m_global_aranges_up->Append(GlobalVariableMap::Entry( file_addr, byte_size, var_sp.get())); } @@ -1811,7 +1810,8 @@ void SymbolFileDWARF::ResolveFunctionAndBlock(lldb::addr_t file_vm_addr, bool lookup_block, SymbolContext &sc) { assert(sc.comp_unit); - DWARFUnit &cu = GetDWARFCompileUnit(sc.comp_unit)->GetNonSkeletonUnit(); + DWARFCompileUnit &cu = + GetDWARFCompileUnit(sc.comp_unit)->GetNonSkeletonUnit(); DWARFDIE function_die = cu.LookupAddress(file_vm_addr); DWARFDIE block_die; if (function_die) { @@ -1837,9 +1837,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, SymbolContextItem resolve_scope, SymbolContext &sc) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "SymbolFileDWARF::" + LLDB_SCOPED_TIMERF("SymbolFileDWARF::" "ResolveSymbolContext (so_addr = { " "section = %p, offset = 0x%" PRIx64 " }, resolve_scope = 0x%8.8x)", @@ -2275,8 +2273,7 @@ void SymbolFileDWARF::FindFunctions(ConstString name, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (name = '%s')", + LLDB_SCOPED_TIMERF("SymbolFileDWARF::FindFunctions (name = '%s')", name.AsCString()); // eFunctionNameTypeAuto should be pre-resolved by a call to @@ -2330,8 +2327,7 @@ void SymbolFileDWARF::FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (regex = '%s')", + LLDB_SCOPED_TIMERF("SymbolFileDWARF::FindFunctions (regex = '%s')", regex.GetText().str().c_str()); Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); @@ -3045,8 +3041,12 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { if (sc.function) { DWARFDIE function_die = GetDIE(sc.function->GetID()); - const dw_addr_t func_lo_pc = function_die.GetAttributeValueAsAddress( - DW_AT_low_pc, LLDB_INVALID_ADDRESS); + dw_addr_t func_lo_pc = LLDB_INVALID_ADDRESS; + DWARFRangeList ranges; + if (function_die.GetDIE()->GetAttributeAddressRanges( + function_die.GetCU(), ranges, + /*check_hi_lo_pc=*/true)) + func_lo_pc = ranges.GetMinRangeBase(0); if (func_lo_pc != LLDB_INVALID_ADDRESS) { const size_t num_variables = ParseVariables( sc, function_die.GetFirstChild(), func_lo_pc, true, true); @@ -3091,385 +3091,348 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, if (die.GetDWARF() != this) return die.GetDWARF()->ParseVariableDIE(sc, die, func_low_pc); - VariableSP var_sp; if (!die) - return var_sp; + return nullptr; - var_sp = GetDIEToVariable()[die.GetDIE()]; - if (var_sp) + if (VariableSP var_sp = GetDIEToVariable()[die.GetDIE()]) return var_sp; // Already been parsed! const dw_tag_t tag = die.Tag(); ModuleSP module = GetObjectFile()->GetModule(); - if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) || - (tag == DW_TAG_formal_parameter && sc.function)) { - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - DWARFDIE spec_die; - if (num_attributes > 0) { - const char *name = nullptr; - const char *mangled = nullptr; - Declaration decl; - uint32_t i; - DWARFFormValue type_die_form; - DWARFExpression location; - bool is_external = false; - bool is_artificial = false; - bool location_is_const_value_data = false; - bool has_explicit_location = false; - DWARFFormValue const_value; - Variable::RangeList scope_ranges; - // AccessType accessibility = eAccessNone; - - for (i = 0; i < num_attributes; ++i) { - dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_decl_file: - decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex( - form_value.Unsigned())); - break; - case DW_AT_decl_line: - decl.SetLine(form_value.Unsigned()); - break; - case DW_AT_decl_column: - decl.SetColumn(form_value.Unsigned()); - break; - case DW_AT_name: - name = form_value.AsCString(); - break; - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - mangled = form_value.AsCString(); - break; - case DW_AT_type: - type_die_form = form_value; - break; - case DW_AT_external: - is_external = form_value.Boolean(); - break; - case DW_AT_const_value: - // If we have already found a DW_AT_location attribute, ignore this - // attribute. - if (!has_explicit_location) { - location_is_const_value_data = true; - // The constant value will be either a block, a data value or a - // string. - auto debug_info_data = die.GetData(); - if (DWARFFormValue::IsBlockForm(form_value.Form())) { - // Retrieve the value as a block expression. - uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); - location = DWARFExpression( - module, - DataExtractor(debug_info_data, block_offset, block_length), - die.GetCU()); - } else if (DWARFFormValue::IsDataForm(form_value.Form())) { - // Retrieve the value as a data expression. - uint32_t data_offset = attributes.DIEOffsetAtIndex(i); - if (auto data_length = form_value.GetFixedSize()) - location = DWARFExpression( - module, - DataExtractor(debug_info_data, data_offset, *data_length), - die.GetCU()); - else { - const uint8_t *data_pointer = form_value.BlockData(); - if (data_pointer) { - form_value.Unsigned(); - } else if (DWARFFormValue::IsDataForm(form_value.Form())) { - // we need to get the byte size of the type later after we - // create the variable - const_value = form_value; - } - } - } else { - // Retrieve the value as a string expression. - if (form_value.Form() == DW_FORM_strp) { - uint32_t data_offset = attributes.DIEOffsetAtIndex(i); - if (auto data_length = form_value.GetFixedSize()) - location = DWARFExpression(module, - DataExtractor(debug_info_data, - data_offset, - *data_length), - die.GetCU()); - } else { - const char *str = form_value.AsCString(); - uint32_t string_offset = - str - (const char *)debug_info_data.GetDataStart(); - uint32_t string_length = strlen(str) + 1; - location = DWARFExpression(module, - DataExtractor(debug_info_data, - string_offset, - string_length), - die.GetCU()); - } - } - } - break; - case DW_AT_location: { - location_is_const_value_data = false; - has_explicit_location = true; - if (DWARFFormValue::IsBlockForm(form_value.Form())) { - auto data = die.GetData(); - - uint32_t block_offset = - form_value.BlockData() - data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); - location = DWARFExpression( - module, DataExtractor(data, block_offset, block_length), - die.GetCU()); - } else { - DataExtractor data = die.GetCU()->GetLocationData(); - dw_offset_t offset = form_value.Unsigned(); - if (form_value.Form() == DW_FORM_loclistx) - offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); - if (data.ValidOffset(offset)) { - data = DataExtractor(data, offset, data.GetByteSize() - offset); - location = DWARFExpression(module, data, die.GetCU()); - assert(func_low_pc != LLDB_INVALID_ADDRESS); - location.SetLocationListAddresses( - attributes.CompileUnitAtIndex(i)->GetBaseAddress(), - func_low_pc); - } - } - } break; - case DW_AT_specification: - spec_die = form_value.Reference(); - break; - case DW_AT_start_scope: - // TODO: Implement this. - break; - case DW_AT_artificial: - is_artificial = form_value.Boolean(); - break; - case DW_AT_accessibility: - break; // accessibility = - // DW_ACCESS_to_AccessType(form_value.Unsigned()); break; - case DW_AT_declaration: - case DW_AT_description: - case DW_AT_endianity: - case DW_AT_segment: - case DW_AT_visibility: - default: - case DW_AT_abstract_origin: - case DW_AT_sibling: - break; - } - } - } + if (tag != DW_TAG_variable && tag != DW_TAG_constant && + (tag != DW_TAG_formal_parameter || !sc.function)) + return nullptr; + + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + DWARFDIE spec_die; + VariableSP var_sp; + const char *name = nullptr; + const char *mangled = nullptr; + Declaration decl; + DWARFFormValue type_die_form; + DWARFExpression location; + bool is_external = false; + bool is_artificial = false; + DWARFFormValue const_value_form, location_form; + Variable::RangeList scope_ranges; + + for (size_t i = 0; i < num_attributes; ++i) { + dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + + if (!attributes.ExtractFormValueAtIndex(i, form_value)) + continue; + switch (attr) { + case DW_AT_decl_file: + decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex( + form_value.Unsigned())); + break; + case DW_AT_decl_line: + decl.SetLine(form_value.Unsigned()); + break; + case DW_AT_decl_column: + decl.SetColumn(form_value.Unsigned()); + break; + case DW_AT_name: + name = form_value.AsCString(); + break; + case DW_AT_linkage_name: + case DW_AT_MIPS_linkage_name: + mangled = form_value.AsCString(); + break; + case DW_AT_type: + type_die_form = form_value; + break; + case DW_AT_external: + is_external = form_value.Boolean(); + break; + case DW_AT_const_value: + const_value_form = form_value; + break; + case DW_AT_location: + location_form = form_value; + break; + case DW_AT_specification: + spec_die = form_value.Reference(); + break; + case DW_AT_start_scope: + // TODO: Implement this. + break; + case DW_AT_artificial: + is_artificial = form_value.Boolean(); + break; + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_endianity: + case DW_AT_segment: + case DW_AT_visibility: + default: + case DW_AT_abstract_origin: + case DW_AT_sibling: + break; + } + } - const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); - const dw_tag_t parent_tag = die.GetParent().Tag(); - bool is_static_member = - (parent_tag == DW_TAG_compile_unit || - parent_tag == DW_TAG_partial_unit) && - (parent_context_die.Tag() == DW_TAG_class_type || - parent_context_die.Tag() == DW_TAG_structure_type); - - ValueType scope = eValueTypeInvalid; - - const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die); - SymbolContextScope *symbol_context_scope = nullptr; - - bool has_explicit_mangled = mangled != nullptr; - if (!mangled) { - // LLDB relies on the mangled name (DW_TAG_linkage_name or - // DW_AT_MIPS_linkage_name) to generate fully qualified names - // of global variables with commands like "frame var j". For - // example, if j were an int variable holding a value 4 and - // declared in a namespace B which in turn is contained in a - // namespace A, the command "frame var j" returns - // "(int) A::B::j = 4". - // If the compiler does not emit a linkage name, we should be - // able to generate a fully qualified name from the - // declaration context. - if ((parent_tag == DW_TAG_compile_unit || - parent_tag == DW_TAG_partial_unit) && - Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU()))) - mangled = GetDWARFDeclContext(die) - .GetQualifiedNameAsConstString() - .GetCString(); + // Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g. + // for static constexpr member variables -- DW_AT_const_value will be + // present in the class declaration and DW_AT_location in the DIE defining + // the member. + bool location_is_const_value_data = false; + bool has_explicit_location = false; + bool use_type_size_for_value = false; + if (location_form.IsValid()) { + has_explicit_location = true; + if (DWARFFormValue::IsBlockForm(location_form.Form())) { + const DWARFDataExtractor &data = die.GetData(); + + uint32_t block_offset = location_form.BlockData() - data.GetDataStart(); + uint32_t block_length = location_form.Unsigned(); + location = DWARFExpression( + module, DataExtractor(data, block_offset, block_length), die.GetCU()); + } else { + DataExtractor data = die.GetCU()->GetLocationData(); + dw_offset_t offset = location_form.Unsigned(); + if (location_form.Form() == DW_FORM_loclistx) + offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); + if (data.ValidOffset(offset)) { + data = DataExtractor(data, offset, data.GetByteSize() - offset); + location = DWARFExpression(module, data, die.GetCU()); + assert(func_low_pc != LLDB_INVALID_ADDRESS); + location.SetLocationListAddresses( + location_form.GetUnit()->GetBaseAddress(), func_low_pc); } + } + } else if (const_value_form.IsValid()) { + location_is_const_value_data = true; + // The constant value will be either a block, a data value or a + // string. + const DWARFDataExtractor &debug_info_data = die.GetData(); + if (DWARFFormValue::IsBlockForm(const_value_form.Form())) { + // Retrieve the value as a block expression. + uint32_t block_offset = + const_value_form.BlockData() - debug_info_data.GetDataStart(); + uint32_t block_length = const_value_form.Unsigned(); + location = DWARFExpression( + module, DataExtractor(debug_info_data, block_offset, block_length), + die.GetCU()); + } else if (DWARFFormValue::IsDataForm(const_value_form.Form())) { + // Constant value size does not have to match the size of the + // variable. We will fetch the size of the type after we create + // it. + use_type_size_for_value = true; + } else if (const char *str = const_value_form.AsCString()) { + uint32_t string_length = strlen(str) + 1; + location = DWARFExpression( + module, + DataExtractor(str, string_length, die.GetCU()->GetByteOrder(), + die.GetCU()->GetAddressByteSize()), + die.GetCU()); + } + } - if (tag == DW_TAG_formal_parameter) - scope = eValueTypeVariableArgument; - else { - // DWARF doesn't specify if a DW_TAG_variable is a local, global - // or static variable, so we have to do a little digging: - // 1) DW_AT_linkage_name implies static lifetime (but may be missing) - // 2) An empty DW_AT_location is an (optimized-out) static lifetime var. - // 3) DW_AT_location containing a DW_OP_addr implies static lifetime. - // Clang likes to combine small global variables into the same symbol - // with locations like: DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus - // so we need to look through the whole expression. - bool is_static_lifetime = - has_explicit_mangled || - (has_explicit_location && !location.IsValid()); - // Check if the location has a DW_OP_addr with any address value... - lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS; - if (!location_is_const_value_data) { - bool op_error = false; - location_DW_OP_addr = location.GetLocation_DW_OP_addr(0, op_error); - if (op_error) { - StreamString strm; - location.DumpLocationForAddress(&strm, eDescriptionLevelFull, 0, 0, - nullptr); - GetObjectFile()->GetModule()->ReportError( - "0x%8.8x: %s has an invalid location: %s", die.GetOffset(), - die.GetTagAsCString(), strm.GetData()); - } - if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) - is_static_lifetime = true; - } - SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); - if (debug_map_symfile) - // Set the module of the expression to the linked module - // instead of the oject file so the relocated address can be - // found there. - location.SetModule(debug_map_symfile->GetObjectFile()->GetModule()); - - if (is_static_lifetime) { - if (is_external) - scope = eValueTypeVariableGlobal; - else - scope = eValueTypeVariableStatic; - - if (debug_map_symfile) { - // When leaving the DWARF in the .o files on darwin, when we have a - // global variable that wasn't initialized, the .o file might not - // have allocated a virtual address for the global variable. In - // this case it will have created a symbol for the global variable - // that is undefined/data and external and the value will be the - // byte size of the variable. When we do the address map in - // SymbolFileDWARFDebugMap we rely on having an address, we need to - // do some magic here so we can get the correct address for our - // global variable. The address for all of these entries will be - // zero, and there will be an undefined symbol in this object file, - // and the executable will have a matching symbol with a good - // address. So here we dig up the correct address and replace it in - // the location for the variable, and set the variable's symbol - // context scope to be that of the main executable so the file - // address will resolve correctly. - bool linked_oso_file_addr = false; - if (is_external && location_DW_OP_addr == 0) { - // we have a possible uninitialized extern global - ConstString const_name(mangled ? mangled : name); - ObjectFile *debug_map_objfile = - debug_map_symfile->GetObjectFile(); - if (debug_map_objfile) { - Symtab *debug_map_symtab = debug_map_objfile->GetSymtab(); - if (debug_map_symtab) { - Symbol *exe_symbol = - debug_map_symtab->FindFirstSymbolWithNameAndType( - const_name, eSymbolTypeData, Symtab::eDebugYes, - Symtab::eVisibilityExtern); - if (exe_symbol) { - if (exe_symbol->ValueIsAddress()) { - const addr_t exe_file_addr = - exe_symbol->GetAddressRef().GetFileAddress(); - if (exe_file_addr != LLDB_INVALID_ADDRESS) { - if (location.Update_DW_OP_addr(exe_file_addr)) { - linked_oso_file_addr = true; - symbol_context_scope = exe_symbol; - } - } + const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); + const dw_tag_t parent_tag = die.GetParent().Tag(); + bool is_static_member = (parent_tag == DW_TAG_compile_unit || + parent_tag == DW_TAG_partial_unit) && + (parent_context_die.Tag() == DW_TAG_class_type || + parent_context_die.Tag() == DW_TAG_structure_type); + + ValueType scope = eValueTypeInvalid; + + const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die); + SymbolContextScope *symbol_context_scope = nullptr; + + bool has_explicit_mangled = mangled != nullptr; + if (!mangled) { + // LLDB relies on the mangled name (DW_TAG_linkage_name or + // DW_AT_MIPS_linkage_name) to generate fully qualified names + // of global variables with commands like "frame var j". For + // example, if j were an int variable holding a value 4 and + // declared in a namespace B which in turn is contained in a + // namespace A, the command "frame var j" returns + // "(int) A::B::j = 4". + // If the compiler does not emit a linkage name, we should be + // able to generate a fully qualified name from the + // declaration context. + if ((parent_tag == DW_TAG_compile_unit || + parent_tag == DW_TAG_partial_unit) && + Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU()))) + mangled = + GetDWARFDeclContext(die).GetQualifiedNameAsConstString().GetCString(); + } + + if (tag == DW_TAG_formal_parameter) + scope = eValueTypeVariableArgument; + else { + // DWARF doesn't specify if a DW_TAG_variable is a local, global + // or static variable, so we have to do a little digging: + // 1) DW_AT_linkage_name implies static lifetime (but may be missing) + // 2) An empty DW_AT_location is an (optimized-out) static lifetime var. + // 3) DW_AT_location containing a DW_OP_addr implies static lifetime. + // Clang likes to combine small global variables into the same symbol + // with locations like: DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus + // so we need to look through the whole expression. + bool is_static_lifetime = + has_explicit_mangled || (has_explicit_location && !location.IsValid()); + // Check if the location has a DW_OP_addr with any address value... + lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS; + if (!location_is_const_value_data) { + bool op_error = false; + location_DW_OP_addr = location.GetLocation_DW_OP_addr(0, op_error); + if (op_error) { + StreamString strm; + location.DumpLocationForAddress(&strm, eDescriptionLevelFull, 0, 0, + nullptr); + GetObjectFile()->GetModule()->ReportError( + "0x%8.8x: %s has an invalid location: %s", die.GetOffset(), + die.GetTagAsCString(), strm.GetData()); + } + if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) + is_static_lifetime = true; + } + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) + // Set the module of the expression to the linked module + // instead of the oject file so the relocated address can be + // found there. + location.SetModule(debug_map_symfile->GetObjectFile()->GetModule()); + + if (is_static_lifetime) { + if (is_external) + scope = eValueTypeVariableGlobal; + else + scope = eValueTypeVariableStatic; + + if (debug_map_symfile) { + // When leaving the DWARF in the .o files on darwin, when we have a + // global variable that wasn't initialized, the .o file might not + // have allocated a virtual address for the global variable. In + // this case it will have created a symbol for the global variable + // that is undefined/data and external and the value will be the + // byte size of the variable. When we do the address map in + // SymbolFileDWARFDebugMap we rely on having an address, we need to + // do some magic here so we can get the correct address for our + // global variable. The address for all of these entries will be + // zero, and there will be an undefined symbol in this object file, + // and the executable will have a matching symbol with a good + // address. So here we dig up the correct address and replace it in + // the location for the variable, and set the variable's symbol + // context scope to be that of the main executable so the file + // address will resolve correctly. + bool linked_oso_file_addr = false; + if (is_external && location_DW_OP_addr == 0) { + // we have a possible uninitialized extern global + ConstString const_name(mangled ? mangled : name); + ObjectFile *debug_map_objfile = debug_map_symfile->GetObjectFile(); + if (debug_map_objfile) { + Symtab *debug_map_symtab = debug_map_objfile->GetSymtab(); + if (debug_map_symtab) { + Symbol *exe_symbol = + debug_map_symtab->FindFirstSymbolWithNameAndType( + const_name, eSymbolTypeData, Symtab::eDebugYes, + Symtab::eVisibilityExtern); + if (exe_symbol) { + if (exe_symbol->ValueIsAddress()) { + const addr_t exe_file_addr = + exe_symbol->GetAddressRef().GetFileAddress(); + if (exe_file_addr != LLDB_INVALID_ADDRESS) { + if (location.Update_DW_OP_addr(exe_file_addr)) { + linked_oso_file_addr = true; + symbol_context_scope = exe_symbol; } } } } } - - if (!linked_oso_file_addr) { - // The DW_OP_addr is not zero, but it contains a .o file address - // which needs to be linked up correctly. - const lldb::addr_t exe_file_addr = - debug_map_symfile->LinkOSOFileAddress(this, - location_DW_OP_addr); - if (exe_file_addr != LLDB_INVALID_ADDRESS) { - // Update the file address for this variable - location.Update_DW_OP_addr(exe_file_addr); - } else { - // Variable didn't make it into the final executable - return var_sp; - } - } } - } else { - if (location_is_const_value_data && - die.GetDIE()->IsGlobalOrStaticScopeVariable()) - scope = eValueTypeVariableStatic; - else { - scope = eValueTypeVariableLocal; - if (debug_map_symfile) { - // We need to check for TLS addresses that we need to fixup - if (location.ContainsThreadLocalStorage()) { - location.LinkThreadLocalStorage( - debug_map_symfile->GetObjectFile()->GetModule(), - [this, debug_map_symfile]( - lldb::addr_t unlinked_file_addr) -> lldb::addr_t { - return debug_map_symfile->LinkOSOFileAddress( - this, unlinked_file_addr); - }); - scope = eValueTypeVariableThreadLocal; - } - } + } + + if (!linked_oso_file_addr) { + // The DW_OP_addr is not zero, but it contains a .o file address + // which needs to be linked up correctly. + const lldb::addr_t exe_file_addr = + debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr); + if (exe_file_addr != LLDB_INVALID_ADDRESS) { + // Update the file address for this variable + location.Update_DW_OP_addr(exe_file_addr); + } else { + // Variable didn't make it into the final executable + return var_sp; } } } - - if (symbol_context_scope == nullptr) { - switch (parent_tag) { - case DW_TAG_subprogram: - case DW_TAG_inlined_subroutine: - case DW_TAG_lexical_block: - if (sc.function) { - symbol_context_scope = sc.function->GetBlock(true).FindBlockByID( - sc_parent_die.GetID()); - if (symbol_context_scope == nullptr) - symbol_context_scope = sc.function; + } else { + if (location_is_const_value_data && + die.GetDIE()->IsGlobalOrStaticScopeVariable()) + scope = eValueTypeVariableStatic; + else { + scope = eValueTypeVariableLocal; + if (debug_map_symfile) { + // We need to check for TLS addresses that we need to fixup + if (location.ContainsThreadLocalStorage()) { + location.LinkThreadLocalStorage( + debug_map_symfile->GetObjectFile()->GetModule(), + [this, debug_map_symfile]( + lldb::addr_t unlinked_file_addr) -> lldb::addr_t { + return debug_map_symfile->LinkOSOFileAddress( + this, unlinked_file_addr); + }); + scope = eValueTypeVariableThreadLocal; } - break; - - default: - symbol_context_scope = sc.comp_unit; - break; } } + } + } - if (symbol_context_scope) { - SymbolFileTypeSP type_sp( - new SymbolFileType(*this, GetUID(type_die_form.Reference()))); + if (symbol_context_scope == nullptr) { + switch (parent_tag) { + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_lexical_block: + if (sc.function) { + symbol_context_scope = + sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); + if (symbol_context_scope == nullptr) + symbol_context_scope = sc.function; + } + break; - if (const_value.Form() && type_sp && type_sp->GetType()) - location.UpdateValue(const_value.Unsigned(), - type_sp->GetType()->GetByteSize().getValueOr(0), - die.GetCU()->GetAddressByteSize()); + default: + symbol_context_scope = sc.comp_unit; + break; + } + } - var_sp = std::make_shared<Variable>( - die.GetID(), name, mangled, type_sp, scope, symbol_context_scope, - scope_ranges, &decl, location, is_external, is_artificial, - is_static_member); + if (symbol_context_scope) { + auto type_sp = std::make_shared<SymbolFileType>( + *this, GetUID(type_die_form.Reference())); - var_sp->SetLocationIsConstantValueData(location_is_const_value_data); - } else { - // Not ready to parse this variable yet. It might be a global or static - // variable that is in a function scope and the function in the symbol - // context wasn't filled in yet - return var_sp; - } - } - // Cache var_sp even if NULL (the variable was just a specification or was - // missing vital information to be able to be displayed in the debugger - // (missing location due to optimization, etc)) so we don't re-parse this - // DIE over and over later... - GetDIEToVariable()[die.GetDIE()] = var_sp; - if (spec_die) - GetDIEToVariable()[spec_die.GetDIE()] = var_sp; + if (use_type_size_for_value && type_sp->GetType()) + location.UpdateValue( + const_value_form.Unsigned(), + type_sp->GetType()->GetByteSize(nullptr).getValueOr(0), + die.GetCU()->GetAddressByteSize()); + + var_sp = std::make_shared<Variable>( + die.GetID(), name, mangled, type_sp, scope, symbol_context_scope, + scope_ranges, &decl, location, is_external, is_artificial, + location_is_const_value_data, is_static_member); + } else { + // Not ready to parse this variable yet. It might be a global or static + // variable that is in a function scope and the function in the symbol + // context wasn't filled in yet + return var_sp; } + // Cache var_sp even if NULL (the variable was just a specification or was + // missing vital information to be able to be displayed in the debugger + // (missing location due to optimization, etc)) so we don't re-parse this + // DIE over and over later... + GetDIEToVariable()[die.GetDIE()] = var_sp; + if (spec_die) + GetDIEToVariable()[spec_die.GetDIE()] = var_sp; + return var_sp; } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 76ceb279c718..019f76c67c63 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -346,7 +346,7 @@ protected: lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu); - virtual DWARFUnit * + virtual DWARFCompileUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit); DWARFUnit *GetNextUnparsedDWARFCompileUnit(DWARFUnit *prev_cu); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 6515d78b8f23..fa24f975b073 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -1013,9 +1013,7 @@ void SymbolFileDWARFDebugMap::FindFunctions( FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "SymbolFileDWARFDebugMap::FindFunctions (name = %s)", + LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::FindFunctions (name = %s)", name.GetCString()); ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { @@ -1034,9 +1032,7 @@ void SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')", + LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')", regex.GetText().str().c_str()); ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { @@ -1055,9 +1051,7 @@ void SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, TypeList &type_list) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)", + LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)", type_mask); SymbolFileDWARF *oso_dwarf = nullptr; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 3aaa7d330b84..fcb51dfa0e7a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -49,8 +49,7 @@ DWARFCompileUnit *SymbolFileDWARFDwo::GetDWOCompileUnitForHash(uint64_t hash) { DWARFCompileUnit *cu = FindSingleCompileUnit(); if (!cu) return nullptr; - if (hash != - cu->GetUnitDIEOnly().GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0)) + if (hash != cu->GetDWOId()) return nullptr; return cu; } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 0acc77d7c67f..5b4ab78ac219 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -881,8 +881,8 @@ PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) { std::string uname = std::string(DropNameScope(udt.Name)); - CompilerType ct = m_clang.CreateTypedefType(ToCompilerType(qt), uname.c_str(), - ToCompilerDeclContext(*scope), 0); + CompilerType ct = ToCompilerType(qt).CreateTypedef( + uname.c_str(), ToCompilerDeclContext(*scope), 0); clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct); DeclStatus status; status.resolved = true; @@ -1015,8 +1015,7 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { proc_name.consume_front("::"); clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( - parent, OptionalClangModuleID(), proc_name.str().c_str(), func_ct, - storage, false); + parent, OptionalClangModuleID(), proc_name, func_ct, storage, false); lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp index 6ac6cc2da29b..dc964f64a915 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp @@ -39,7 +39,7 @@ PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {} } llvm::Expected<std::unique_ptr<PdbIndex>> -PdbIndex::create(std::unique_ptr<llvm::pdb::PDBFile> file) { +PdbIndex::create(llvm::pdb::PDBFile *file) { lldbassert(file); std::unique_ptr<PdbIndex> result(new PdbIndex()); @@ -53,7 +53,7 @@ PdbIndex::create(std::unique_ptr<llvm::pdb::PDBFile> file) { result->m_tpi->buildHashMap(); - result->m_file = std::move(file); + result->m_file = file; return std::move(result); } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h index ccc3cc2f4538..1b382e5263c1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h @@ -48,7 +48,7 @@ struct SegmentOffset; class PdbIndex { /// The underlying PDB file. - std::unique_ptr<llvm::pdb::PDBFile> m_file; + llvm::pdb::PDBFile *m_file = nullptr; /// The DBI stream. This contains general high level information about the /// features present in the PDB file, compile units (such as the information @@ -110,8 +110,7 @@ class PdbIndex { void BuildAddrToSymbolMap(CompilandIndexItem &cci); public: - static llvm::Expected<std::unique_ptr<PdbIndex>> - create(std::unique_ptr<llvm::pdb::PDBFile>); + static llvm::Expected<std::unique_ptr<PdbIndex>> create(llvm::pdb::PDBFile *); void SetLoadAddress(lldb::addr_t addr) { m_load_address = addr; } lldb::addr_t GetLoadAddress() const { return m_load_address; } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index cce06473d92f..24b4c64a91bc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -16,6 +16,7 @@ #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/ObjectFile/PDB/ObjectFilePDB.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" @@ -42,9 +43,11 @@ #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/Demangle/MicrosoftDemangle.h" #include "llvm/Object/COFF.h" @@ -81,32 +84,6 @@ static lldb::LanguageType TranslateLanguage(PDB_Lang lang) { } } -static std::unique_ptr<PDBFile> loadPDBFile(std::string PdbPath, - llvm::BumpPtrAllocator &Allocator) { - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer = - llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); - if (!ErrorOrBuffer) - return nullptr; - std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); - - llvm::StringRef Path = Buffer->getBufferIdentifier(); - auto Stream = std::make_unique<llvm::MemoryBufferByteStream>( - std::move(Buffer), llvm::support::little); - - auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator); - if (auto EC = File->parseFileHeaders()) { - llvm::consumeError(std::move(EC)); - return nullptr; - } - if (auto EC = File->parseStreamData()) { - llvm::consumeError(std::move(EC)); - return nullptr; - } - - return File; -} - static std::unique_ptr<PDBFile> loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { // Try to find a matching PDB for an EXE. @@ -134,13 +111,17 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { return nullptr; } - // if the file doesn't exist, is not a pdb, or doesn't have a matching guid, - // fail. - llvm::file_magic magic; - auto ec = llvm::identify_magic(pdb_file, magic); - if (ec || magic != llvm::file_magic::pdb) - return nullptr; - std::unique_ptr<PDBFile> pdb = loadPDBFile(std::string(pdb_file), allocator); + // 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).GetCString(); + } + + // 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); if (!pdb) return nullptr; @@ -284,24 +265,19 @@ uint32_t SymbolFileNativePDB::CalculateAbilities() { if (!m_index) { // Lazily load and match the PDB file, but only do this once. - std::unique_ptr<PDBFile> file_up = - loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(), m_allocator); - - if (!file_up) { - auto module_sp = m_objfile_sp->GetModule(); - if (!module_sp) - return 0; - // See if any symbol file is specified through `--symfile` option. - FileSpec symfile = module_sp->GetSymbolFileFileSpec(); - if (!symfile) - return 0; - file_up = loadPDBFile(symfile.GetPath(), m_allocator); + PDBFile *pdb_file; + if (auto *pdb = llvm::dyn_cast<ObjectFilePDB>(m_objfile_sp.get())) { + pdb_file = &pdb->GetPDBFile(); + } else { + m_file_up = loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(), + m_allocator); + pdb_file = m_file_up.get(); } - if (!file_up) + if (!pdb_file) return 0; - auto expected_index = PdbIndex::create(std::move(file_up)); + auto expected_index = PdbIndex::create(pdb_file); if (!expected_index) { llvm::consumeError(expected_index.takeError()); return 0; @@ -321,7 +297,10 @@ uint32_t SymbolFileNativePDB::CalculateAbilities() { } void SymbolFileNativePDB::InitializeObject() { - m_obj_load_address = m_objfile_sp->GetBaseAddress().GetFileAddress(); + m_obj_load_address = m_objfile_sp->GetModule() + ->GetObjectFile() + ->GetBaseAddress() + .GetFileAddress(); m_index->SetLoadAddress(m_obj_load_address); m_index->ParseSectionContribs(); @@ -460,7 +439,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id, lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType); return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(name), - modified_type->GetByteSize(), nullptr, + modified_type->GetByteSize(nullptr), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full); } @@ -584,7 +563,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, return std::make_shared<lldb_private::Type>( toOpaqueUid(type_id), this, ConstString(uname), - underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID, + underlying_type->GetByteSize(nullptr), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct, lldb_private::Type::ResolveState::Forward); } @@ -809,11 +788,13 @@ VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) { std::string global_name("::"); global_name += name; + bool artificial = false; + bool location_is_constant_data = false; + bool static_member = false; VariableSP var_sp = std::make_shared<Variable>( toOpaqueUid(var_id), name.str().c_str(), global_name.c_str(), type_sp, - scope, comp_unit.get(), ranges, &decl, location, is_external, false, - false); - var_sp->SetLocationIsConstantValueData(false); + scope, comp_unit.get(), ranges, &decl, location, is_external, artificial, + location_is_constant_data, static_member); return var_sp; } @@ -837,11 +818,14 @@ SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id, DWARFExpression location = MakeConstantLocationExpression( constant.Type, tpi, constant.Value, module); + bool external = false; + bool artificial = false; + bool location_is_constant_data = true; + bool static_member = false; VariableSP var_sp = std::make_shared<Variable>( toOpaqueUid(var_id), constant.Name.str().c_str(), global_name.c_str(), type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location, - false, false, false); - var_sp->SetLocationIsConstantValueData(true); + external, artificial, location_is_constant_data, static_member); return var_sp; } @@ -1343,10 +1327,14 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id, ValueType var_scope = is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal; + bool external = false; + bool artificial = false; + bool location_is_constant_data = false; + bool static_member = false; VariableSP var_sp = std::make_shared<Variable>( toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope, - comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, false, - false, false); + comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, external, + artificial, location_is_constant_data, static_member); if (!is_param) m_ast->GetOrCreateVariableDecl(scope_id, var_id); @@ -1376,9 +1364,10 @@ TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) { Declaration decl; return std::make_shared<lldb_private::Type>( - toOpaqueUid(id), this, ConstString(udt.Name), target_type->GetByteSize(), - nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, - decl, target_type->GetForwardCompilerType(), + toOpaqueUid(id), this, ConstString(udt.Name), + target_type->GetByteSize(nullptr), nullptr, target_type->GetID(), + lldb_private::Type::eEncodingIsTypedefUID, decl, + target_type->GetForwardCompilerType(), lldb_private::Type::ResolveState::Forward); } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h index bf5718e11a19..61c1d77164b7 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -231,6 +231,7 @@ private: lldb::addr_t m_obj_load_address = 0; bool m_done_full_type_scan = false; + std::unique_ptr<llvm::pdb::PDBFile> m_file_up; std::unique_ptr<PdbIndex> m_index; std::unique_ptr<PdbAstBuilder> m_ast; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index d87926a6588f..f9c12e634140 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -550,8 +550,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { if (!ast_typedef.IsValid()) { CompilerType target_ast_type = target_type->GetFullCompilerType(); - ast_typedef = m_ast.CreateTypedefType( - target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0); + ast_typedef = target_ast_type.CreateTypedef( + name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0); if (!ast_typedef) return nullptr; @@ -928,7 +928,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { : clang::StorageClass::SC_None; auto decl = m_ast.CreateFunctionDeclaration( - decl_context, OptionalClangModuleID(), name.c_str(), + decl_context, OptionalClangModuleID(), name, type->GetForwardCompilerType(), storage, func->hasInlineAttribute()); std::vector<clang::ParmVarDecl *> params; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index 1001514edede..befc08158cea 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -52,8 +52,6 @@ #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" #include "Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h" -#include <regex> - using namespace lldb; using namespace lldb_private; using namespace llvm::pdb; @@ -1020,8 +1018,8 @@ VariableSP SymbolFilePDB::ParseVariableForPDBData( var_sp = std::make_shared<Variable>( var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope, - ranges, &decl, location, is_external, is_artificial, is_static_member); - var_sp->SetLocationIsConstantValueData(is_constant); + ranges, &decl, location, is_external, is_artificial, is_constant, + is_static_member); m_variables.insert(std::make_pair(var_uid, var_sp)); return var_sp; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index c4a0e609aa22..3a5e02d4fb86 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -59,8 +59,6 @@ SymbolFileSymtab::SymbolFileSymtab(ObjectFileSP objfile_sp) : SymbolFile(std::move(objfile_sp)), m_source_indexes(), m_func_indexes(), m_code_indexes(), m_objc_class_name_to_index() {} -SymbolFileSymtab::~SymbolFileSymtab() {} - uint32_t SymbolFileSymtab::CalculateAbilities() { uint32_t abilities = 0; if (m_objfile_sp) { diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h index 9557ebbcb272..377c41e50770 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -31,8 +31,6 @@ public: // Constructors and Destructors SymbolFileSymtab(lldb::ObjectFileSP objfile_sp); - ~SymbolFileSymtab() override; - // Static Functions static void Initialize(); @@ -104,10 +102,6 @@ protected: lldb_private::Symtab::IndexCollection m_data_indexes; lldb_private::Symtab::NameToIndexMap m_objc_class_name_to_index; TypeMap m_objc_class_types; - -private: - SymbolFileSymtab(const SymbolFileSymtab &) = delete; - const SymbolFileSymtab &operator=(const SymbolFileSymtab &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_SYMTAB_SYMBOLFILESYMTAB_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index 2e6fd4365021..4df5140bd7e1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -31,9 +31,6 @@ LLDB_PLUGIN_DEFINE(SymbolVendorELF) SymbolVendorELF::SymbolVendorELF(const lldb::ModuleSP &module_sp) : SymbolVendor(module_sp) {} -// Destructor -SymbolVendorELF::~SymbolVendorELF() {} - void SymbolVendorELF::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); @@ -84,8 +81,7 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, if (!fspec) fspec = obj_file->GetDebugLink().getValueOr(FileSpec()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolVendorELF::CreateInstance (module = %s)", + LLDB_SCOPED_TIMERF("SymbolVendorELF::CreateInstance (module = %s)", module_sp->GetFileSpec().GetPath().c_str()); ModuleSpec module_spec; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h index 824906c04955..2080084a15b8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h @@ -17,8 +17,6 @@ public: // Constructors and Destructors SymbolVendorELF(const lldb::ModuleSP &module_sp); - ~SymbolVendorELF() override; - // Static Functions static void Initialize(); @@ -36,10 +34,6 @@ public: lldb_private::ConstString GetPluginName() override; uint32_t GetPluginVersion() override; - -private: - SymbolVendorELF(const SymbolVendorELF &) = delete; - const SymbolVendorELF &operator=(const SymbolVendorELF &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_ELF_SYMBOLVENDORELF_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp index 1c09dabc5622..67a1ef5e4e51 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp @@ -72,8 +72,7 @@ SymbolVendorWasm::CreateInstance(const lldb::ModuleSP &module_sp, lldb::eSectionTypeDWARFDebugInfo, true)) return nullptr; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolVendorWasm::CreateInstance (module = %s)", + LLDB_SCOPED_TIMERF("SymbolVendorWasm::CreateInstance (module = %s)", module_sp->GetFileSpec().GetPath().c_str()); ModuleSpec module_spec; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h index 96e737b1be96..b212337e0549 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h @@ -33,10 +33,6 @@ public: lldb_private::ConstString GetPluginName() override; uint32_t GetPluginVersion() override; /// \} - -private: - SymbolVendorWasm(const SymbolVendorWasm &) = delete; - const SymbolVendorWasm &operator=(const SymbolVendorWasm &) = delete; }; } // namespace wasm diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp new file mode 100644 index 000000000000..e1758dfcfc41 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp @@ -0,0 +1,73 @@ +//===-- CommandObjectTraceStartIntelPT.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 "CommandObjectTraceStartIntelPT.h" + +#include "lldb/Host/OptionParser.h" +#include "lldb/Target/Trace.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +#define LLDB_OPTIONS_thread_trace_start_intel_pt +#include "TraceIntelPTCommandOptions.inc" + +Status CommandObjectTraceStartIntelPT::CommandOptions::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 's': { + int32_t size_in_kb; + if (option_arg.empty() || option_arg.getAsInteger(0, size_in_kb) || + size_in_kb < 0) + error.SetErrorStringWithFormat("invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_size_in_kb = size_in_kb; + break; + } + case 'c': { + int32_t custom_config; + if (option_arg.empty() || option_arg.getAsInteger(0, custom_config) || + custom_config < 0) + error.SetErrorStringWithFormat("invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_custom_config = custom_config; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; +} + +void CommandObjectTraceStartIntelPT::CommandOptions::OptionParsingStarting( + ExecutionContext *execution_context) { + m_size_in_kb = 4; + m_custom_config = 0; +} + +llvm::ArrayRef<OptionDefinition> +CommandObjectTraceStartIntelPT::CommandOptions::GetDefinitions() { + return llvm::makeArrayRef(g_thread_trace_start_intel_pt_options); +} + +bool CommandObjectTraceStartIntelPT::HandleOneThread( + lldb::tid_t tid, CommandReturnObject &result) { + result.AppendMessageWithFormat( + "would trace tid %" PRIu64 " with size_in_kb %zu and custom_config %d\n", + tid, m_options.m_size_in_kb, m_options.m_custom_config); + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h new file mode 100644 index 000000000000..265569c553fa --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h @@ -0,0 +1,65 @@ +//===-- CommandObjectTraceStartIntelPT.h ----------------------*- C++ //-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H + +#include "../../../../source/Commands/CommandObjectThreadUtil.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +namespace lldb_private { +namespace trace_intel_pt { + +class CommandObjectTraceStartIntelPT : public CommandObjectIterateOverThreads { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override; + + size_t m_size_in_kb; + uint32_t m_custom_config; + }; + + CommandObjectTraceStartIntelPT(CommandInterpreter &interpreter) + : CommandObjectIterateOverThreads( + interpreter, "thread trace start", + "Start tracing one or more threads with intel-pt. " + "Defaults to the current thread. Thread indices can be " + "specified as arguments.\n Use the thread-index \"all\" to trace " + "all threads.", + "thread trace start [<thread-index> <thread-index> ...] " + "[<intel-pt-options>]", + lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock | + lldb::eCommandProcessMustBeLaunched | + lldb::eCommandProcessMustBePaused), + m_options() {} + + ~CommandObjectTraceStartIntelPT() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override; + + CommandOptions m_options; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp new file mode 100644 index 000000000000..6b8b06564052 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp @@ -0,0 +1,64 @@ +//===-- DecodedThread.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 "DecodedThread.h" + +#include "lldb/Utility/StreamString.h" + +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +char IntelPTError::ID; + +IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address) + : m_libipt_error_code(libipt_error_code), m_address(address) { + assert(libipt_error_code < 0); +} + +void IntelPTError::log(llvm::raw_ostream &OS) const { + const char *libipt_error_message = pt_errstr(pt_errcode(m_libipt_error_code)); + if (m_address != LLDB_INVALID_ADDRESS && m_address > 0) { + write_hex(OS, m_address, HexPrintStyle::PrefixLower, 18); + OS << " "; + } + OS << "error: " << libipt_error_message; +} + +bool IntelPTInstruction::IsError() const { return (bool)m_error; } + +Expected<lldb::addr_t> IntelPTInstruction::GetLoadAddress() const { + if (IsError()) + return ToError(); + return m_pt_insn.ip; +} + +Error IntelPTInstruction::ToError() const { + if (!IsError()) + return Error::success(); + + if (m_error->isA<IntelPTError>()) + return make_error<IntelPTError>(static_cast<IntelPTError &>(*m_error)); + return make_error<StringError>(m_error->message(), + m_error->convertToErrorCode()); +} + +size_t DecodedThread::GetLastPosition() const { + return m_instructions.empty() ? 0 : m_instructions.size() - 1; +} + +ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const { + return makeArrayRef(m_instructions); +} + +size_t DecodedThread::GetCursorPosition() const { return m_position; } + +size_t DecodedThread::SetCursorPosition(size_t new_position) { + m_position = std::min(new_position, GetLastPosition()); + return m_position; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h new file mode 100644 index 000000000000..3c7e030414cb --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h @@ -0,0 +1,146 @@ +//===-- DecodedThread.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H + +#include <vector> + +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" + +#include "lldb/Target/Trace.h" + +#include "intel-pt.h" + +namespace lldb_private { +namespace trace_intel_pt { + +/// Class for representing a libipt decoding error. +class IntelPTError : public llvm::ErrorInfo<IntelPTError> { +public: + static char ID; + + /// \param[in] libipt_error_code + /// Negative number returned by libipt when decoding the trace and + /// signaling errors. + /// + /// \param[in] address + /// Optional instruction address. When decoding an individual instruction, + /// its address might be available in the \a pt_insn object, and should be + /// passed to this constructor. Other errors don't have an associated + /// address. + IntelPTError(int libipt_error_code, + lldb::addr_t address = LLDB_INVALID_ADDRESS); + + std::error_code convertToErrorCode() const override { + return llvm::errc::not_supported; + } + + void log(llvm::raw_ostream &OS) const override; + +private: + int m_libipt_error_code; + lldb::addr_t m_address; +}; + +/// \class IntelPTInstruction +/// An instruction obtained from decoding a trace. It is either an actual +/// instruction or an error indicating a gap in the trace. +/// +/// Gaps in the trace can come in a few flavors: +/// - tracing gaps (e.g. tracing was paused and then resumed) +/// - tracing errors (e.g. buffer overflow) +/// - decoding errors (e.g. some memory region couldn't be decoded) +/// As mentioned, any gap is represented as an error in this class. +class IntelPTInstruction { +public: + IntelPTInstruction(const pt_insn &pt_insn) : m_pt_insn(pt_insn) {} + + /// Error constructor + /// + /// libipt errors should use the underlying \a IntelPTError class. + IntelPTInstruction(llvm::Error err) { + llvm::handleAllErrors(std::move(err), + [&](std::unique_ptr<llvm::ErrorInfoBase> info) { + m_error = std::move(info); + }); + } + + /// Check if this object represents an error (i.e. a gap). + /// + /// \return + /// Whether this object represents an error. + bool IsError() const; + + /// \return + /// The instruction pointer address, or an \a llvm::Error if it is an + /// error. + llvm::Expected<lldb::addr_t> GetLoadAddress() const; + + /// \return + /// An \a llvm::Error object if this class corresponds to an Error, or an + /// \a llvm::Error::success otherwise. + llvm::Error ToError() const; + + IntelPTInstruction(IntelPTInstruction &&other) = default; + +private: + IntelPTInstruction(const IntelPTInstruction &other) = delete; + const IntelPTInstruction &operator=(const IntelPTInstruction &other) = delete; + + pt_insn m_pt_insn; + std::unique_ptr<llvm::ErrorInfoBase> m_error; +}; + +/// \class DecodedThread +/// Class holding the instructions and function call hierarchy obtained from +/// decoding a trace, as well as a position cursor used when reverse debugging +/// the trace. +/// +/// Each decoded thread contains a cursor to the current position the user is +/// stopped at. See \a Trace::GetCursorPosition for more information. +class DecodedThread { +public: + DecodedThread(std::vector<IntelPTInstruction> &&instructions) + : m_instructions(std::move(instructions)), m_position(GetLastPosition()) { + } + + /// Get the instructions from the decoded trace. Some of them might indicate + /// errors (i.e. gaps) in the trace. + /// + /// \return + /// The instructions of the trace. + llvm::ArrayRef<IntelPTInstruction> GetInstructions() const; + + /// \return + /// The current position of the cursor of this trace, or 0 if there are no + /// instructions. + size_t GetCursorPosition() const; + + /// Change the position of the cursor of this trace. If this value is to high, + /// the new position will be set as the last instruction of the trace. + /// + /// \return + /// The effective new position. + size_t SetCursorPosition(size_t new_position); + /// \} + +private: + /// \return + /// The index of the last element of the trace, or 0 if empty. + size_t GetLastPosition() const; + + std::vector<IntelPTInstruction> m_instructions; + size_t m_position; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp new file mode 100644 index 000000000000..b6e8ae808632 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp @@ -0,0 +1,215 @@ +//===-- IntelPTDecoder.cpp --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "IntelPTDecoder.h" + +#include "llvm/Support/MemoryBuffer.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadTrace.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +/// Move the decoder forward to the next synchronization point (i.e. next PSB +/// packet). +/// +/// Once the decoder is at that sync. point, it can start decoding instructions. +/// +/// \return +/// A negative number with the libipt error if we couldn't synchronize. +/// Otherwise, a positive number with the synchronization status will be +/// returned. +static int FindNextSynchronizationPoint(pt_insn_decoder &decoder) { + // Try to sync the decoder. If it fails, then get + // the decoder_offset and try to sync again from + // the next synchronization point. If the + // new_decoder_offset is same as decoder_offset + // then we can't move to the next synchronization + // point. Otherwise, keep resyncing until either + // end of trace stream (eos) is reached or + // pt_insn_sync_forward() passes. + int errcode = pt_insn_sync_forward(&decoder); + + if (errcode != -pte_eos && errcode < 0) { + uint64_t decoder_offset = 0; + int errcode_off = pt_insn_get_offset(&decoder, &decoder_offset); + if (errcode_off >= 0) { // we could get the offset + while (true) { + errcode = pt_insn_sync_forward(&decoder); + if (errcode >= 0 || errcode == -pte_eos) + break; + + uint64_t new_decoder_offset = 0; + errcode_off = pt_insn_get_offset(&decoder, &new_decoder_offset); + if (errcode_off < 0) + break; // We can't further synchronize. + else if (new_decoder_offset <= decoder_offset) { + // We tried resyncing the decoder and + // decoder didn't make any progress because + // the offset didn't change. We will not + // make any progress further. Hence, + // stopping in this situation. + break; + } + // We'll try again starting from a new offset. + decoder_offset = new_decoder_offset; + } + } + } + + return errcode; +} + +/// Before querying instructions, we need to query the events associated that +/// instruction e.g. timing events like ptev_tick, or paging events like +/// ptev_paging. +/// +/// \return +/// 0 if there were no errors processing the events, or a negative libipt +/// error code in case of errors. +static int ProcessPTEvents(pt_insn_decoder &decoder, int errcode) { + while (errcode & pts_event_pending) { + pt_event event; + errcode = pt_insn_event(&decoder, &event, sizeof(event)); + if (errcode < 0) + return errcode; + } + return 0; +}; + +/// Decode all the instructions from a configured decoder. +/// The decoding flow is based on +/// https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#the-instruction-flow-decode-loop +/// but with some relaxation to allow for gaps in the trace. +/// +/// Error codes returned by libipt while decoding are: +/// - negative: actual errors +/// - positive or zero: not an error, but a list of bits signaling the status of +/// the decoder +/// +/// \param[in] decoder +/// A configured libipt \a pt_insn_decoder. +/// +/// \return +/// The decoded instructions. +static std::vector<IntelPTInstruction> +DecodeInstructions(pt_insn_decoder &decoder) { + std::vector<IntelPTInstruction> instructions; + + while (true) { + int errcode = FindNextSynchronizationPoint(decoder); + if (errcode == -pte_eos) + break; + + if (errcode < 0) { + instructions.emplace_back(make_error<IntelPTError>(errcode)); + break; + } + + // We have synchronized, so we can start decoding + // instructions and events. + while (true) { + errcode = ProcessPTEvents(decoder, errcode); + if (errcode < 0) { + instructions.emplace_back(make_error<IntelPTError>(errcode)); + break; + } + pt_insn insn; + + errcode = pt_insn_next(&decoder, &insn, sizeof(insn)); + if (errcode == -pte_eos) + break; + + if (errcode < 0) { + instructions.emplace_back(make_error<IntelPTError>(errcode, insn.ip)); + break; + } + + instructions.emplace_back(insn); + } + } + + return instructions; +} + +/// Callback used by libipt for reading the process memory. +/// +/// More information can be found in +/// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md +static int ReadProcessMemory(uint8_t *buffer, size_t size, + const pt_asid * /* unused */, uint64_t pc, + void *context) { + Process *process = static_cast<Process *>(context); + + Status error; + int bytes_read = process->ReadMemory(pc, buffer, size, error); + if (error.Fail()) + return -pte_nomap; + return bytes_read; +} + +static std::vector<IntelPTInstruction> makeInstructionListFromError(Error err) { + std::vector<IntelPTInstruction> instructions; + instructions.emplace_back(std::move(err)); + return instructions; +} + +static std::vector<IntelPTInstruction> +CreateDecoderAndDecode(Process &process, const pt_cpu &pt_cpu, + const FileSpec &trace_file) { + ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error = + MemoryBuffer::getFile(trace_file.GetPath()); + if (std::error_code err = trace_or_error.getError()) + return makeInstructionListFromError(errorCodeToError(err)); + + MemoryBuffer &trace = **trace_or_error; + + pt_config config; + pt_config_init(&config); + config.cpu = pt_cpu; + + if (int errcode = pt_cpu_errata(&config.errata, &config.cpu)) + return makeInstructionListFromError(make_error<IntelPTError>(errcode)); + + // The libipt library does not modify the trace buffer, hence the following + // cast is safe. + config.begin = + reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferStart())); + config.end = + reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferEnd())); + + pt_insn_decoder *decoder = pt_insn_alloc_decoder(&config); + if (!decoder) + return makeInstructionListFromError(make_error<IntelPTError>(-pte_nomem)); + + pt_image *image = pt_insn_get_image(decoder); + + int errcode = pt_image_set_callback(image, ReadProcessMemory, &process); + assert(errcode == 0); + (void)errcode; + + std::vector<IntelPTInstruction> instructions = DecodeInstructions(*decoder); + + pt_insn_free_decoder(decoder); + return instructions; +} + +const DecodedThread &ThreadTraceDecoder::Decode() { + if (!m_decoded_thread.hasValue()) { + m_decoded_thread = DecodedThread( + CreateDecoderAndDecode(*m_trace_thread->GetProcess(), m_pt_cpu, + m_trace_thread->GetTraceFile())); + } + + return *m_decoded_thread; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h new file mode 100644 index 000000000000..2e67f9bf6da7 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h @@ -0,0 +1,52 @@ +//===-- IntelPTDecoder.h --======--------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H + +#include "intel-pt.h" + +#include "DecodedThread.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { +namespace trace_intel_pt { + +/// \a lldb_private::ThreadTrace decoder that stores the output from decoding, +/// avoiding recomputations, as decoding is expensive. +class ThreadTraceDecoder { +public: + /// \param[in] trace_thread + /// The thread whose trace file will be decoded. + /// + /// \param[in] pt_cpu + /// The libipt cpu used when recording the trace. + ThreadTraceDecoder(const std::shared_ptr<ThreadTrace> &trace_thread, + const pt_cpu &pt_cpu) + : m_trace_thread(trace_thread), m_pt_cpu(pt_cpu), m_decoded_thread() {} + + /// Decode the thread and store the result internally. + /// + /// \return + /// A \a DecodedThread instance. + const DecodedThread &Decode(); + +private: + ThreadTraceDecoder(const ThreadTraceDecoder &other) = delete; + ThreadTraceDecoder &operator=(const ThreadTraceDecoder &other) = delete; + + std::shared_ptr<ThreadTrace> m_trace_thread; + pt_cpu m_pt_cpu; + llvm::Optional<DecodedThread> m_decoded_thread; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp new file mode 100644 index 000000000000..63a8b2dff4a7 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -0,0 +1,114 @@ +//===-- TraceIntelPT.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 "TraceIntelPT.h" + +#include "CommandObjectTraceStartIntelPT.h" +#include "TraceIntelPTSessionFileParser.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadTrace.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +LLDB_PLUGIN_DEFINE(TraceIntelPT) + +CommandObjectSP GetStartCommand(CommandInterpreter &interpreter) { + return CommandObjectSP(new CommandObjectTraceStartIntelPT(interpreter)); +} + +void TraceIntelPT::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "Intel Processor Trace", CreateInstance, + TraceIntelPTSessionFileParser::GetSchema(), GetStartCommand); +} + +void TraceIntelPT::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString TraceIntelPT::GetPluginNameStatic() { + static ConstString g_name("intel-pt"); + return g_name; +} + +StringRef TraceIntelPT::GetSchema() { + return TraceIntelPTSessionFileParser::GetSchema(); +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ + +ConstString TraceIntelPT::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t TraceIntelPT::GetPluginVersion() { return 1; } + +void TraceIntelPT::Dump(Stream *s) const {} + +Expected<TraceSP> +TraceIntelPT::CreateInstance(const json::Value &trace_session_file, + StringRef session_file_dir, Debugger &debugger) { + return TraceIntelPTSessionFileParser(debugger, trace_session_file, + session_file_dir) + .Parse(); +} + +TraceIntelPT::TraceIntelPT( + const pt_cpu &pt_cpu, + const std::vector<std::shared_ptr<ThreadTrace>> &traced_threads) + : m_pt_cpu(pt_cpu) { + for (const std::shared_ptr<ThreadTrace> &thread : traced_threads) + m_trace_threads.emplace( + std::piecewise_construct, + std::forward_as_tuple(thread->GetProcess()->GetID(), thread->GetID()), + std::forward_as_tuple(thread, pt_cpu)); +} + +const DecodedThread *TraceIntelPT::Decode(const Thread &thread) { + auto it = m_trace_threads.find( + std::make_pair(thread.GetProcess()->GetID(), thread.GetID())); + if (it == m_trace_threads.end()) + return nullptr; + return &it->second.Decode(); +} + +size_t TraceIntelPT::GetCursorPosition(const Thread &thread) { + const DecodedThread *decoded_thread = Decode(thread); + if (!decoded_thread) + return 0; + return decoded_thread->GetCursorPosition(); +} + +void TraceIntelPT::TraverseInstructions( + const Thread &thread, size_t position, TraceDirection direction, + std::function<bool(size_t index, Expected<lldb::addr_t> load_addr)> + callback) { + const DecodedThread *decoded_thread = Decode(thread); + if (!decoded_thread) + return; + + ArrayRef<IntelPTInstruction> instructions = decoded_thread->GetInstructions(); + + ssize_t delta = direction == TraceDirection::Forwards ? 1 : -1; + for (ssize_t i = position; i < (ssize_t)instructions.size() && i >= 0; + i += delta) + if (!callback(i, instructions[i].GetLoadAddress())) + break; +} + +size_t TraceIntelPT::GetInstructionCount(const Thread &thread) { + if (const DecodedThread *decoded_thread = Decode(thread)) + return decoded_thread->GetInstructions().size(); + else + return 0; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h new file mode 100644 index 000000000000..5058e6fd32f2 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -0,0 +1,96 @@ +//===-- TraceIntelPT.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H + +#include "IntelPTDecoder.h" +#include "TraceIntelPTSessionFileParser.h" + +namespace lldb_private { +namespace trace_intel_pt { + +class TraceIntelPT : public Trace { +public: + void Dump(Stream *s) const override; + + ~TraceIntelPT() override = default; + + /// PluginInterface protocol + /// \{ + ConstString GetPluginName() override; + + static void Initialize(); + + static void Terminate(); + + /// Create an instance of this class. + /// + /// \param[in] trace_session_file + /// The contents of the trace session file. See \a Trace::FindPlugin. + /// + /// \param[in] session_file_dir + /// The path to the directory that contains the session file. It's used to + /// resolved relative paths in the session file. + /// + /// \param[in] debugger + /// The debugger instance where new Targets will be created as part of the + /// JSON data parsing. + /// + /// \return + /// A trace instance or an error in case of failures. + static llvm::Expected<lldb::TraceSP> + CreateInstance(const llvm::json::Value &trace_session_file, + llvm::StringRef session_file_dir, Debugger &debugger); + + static ConstString GetPluginNameStatic(); + + uint32_t GetPluginVersion() override; + /// \} + + llvm::StringRef GetSchema() override; + + void TraverseInstructions( + const Thread &thread, size_t position, TraceDirection direction, + std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)> + callback) override; + + size_t GetInstructionCount(const Thread &thread) override; + + size_t GetCursorPosition(const Thread &thread) override; + +private: + friend class TraceIntelPTSessionFileParser; + + /// \param[in] trace_threads + /// ThreadTrace instances, which are not live-processes and whose trace + /// files are fixed. + TraceIntelPT(const pt_cpu &pt_cpu, + const std::vector<std::shared_ptr<ThreadTrace>> &traced_threads); + + /// Decode the trace of the given thread that, i.e. recontruct the traced + /// instructions. That trace must be managed by this class. + /// + /// \param[in] thread + /// If \a thread is a \a ThreadTrace, then its internal trace file will be + /// decoded. Live threads are not currently supported. + /// + /// \return + /// A \a DecodedThread instance if decoding was successful, or a \b + /// nullptr if the thread's trace is not managed by this class. + const DecodedThread *Decode(const Thread &thread); + + pt_cpu m_pt_cpu; + std::map<std::pair<lldb::pid_t, lldb::tid_t>, ThreadTraceDecoder> + m_trace_threads; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td new file mode 100644 index 000000000000..6ffe949dbe7b --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td @@ -0,0 +1,16 @@ +include "../../../../source/Commands/OptionsBase.td" + +let Command = "thread trace start intel pt" in { + def thread_trace_start_intel_pt_size: Option<"size", "s">, + Group<1>, + Arg<"Value">, + Desc<"The size of the trace in KB. The kernel rounds it down to the nearest" + " multiple of 4. Defaults to 4.">; + def thread_trace_start_intel_pt_custom_config: Option<"custom-config", "c">, + Group<1>, + Arg<"Value">, + Desc<"Low level bitmask configuration for the kernel based on the values " + "in `grep -H /sys/bus/event_source/devices/intel_pt/format/*`. " + "See https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/perf-intel-pt.txt" + " for more information. Defaults to 0.">; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp new file mode 100644 index 000000000000..beef5c3968ea --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp @@ -0,0 +1,97 @@ +//===-- TraceIntelPTSessionFileParser.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 "TraceIntelPTSessionFileParser.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadList.h" +#include "lldb/Target/ThreadTrace.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +StringRef TraceIntelPTSessionFileParser::GetSchema() { + static std::string schema; + if (schema.empty()) { + schema = TraceSessionFileParser::BuildSchema(R"({ + "type": "intel-pt", + "pt_cpu": { + "vendor": "intel" | "unknown", + "family": integer, + "model": integer, + "stepping": integer + } + })"); + } + return schema; +} + +pt_cpu TraceIntelPTSessionFileParser::ParsePTCPU(const JSONPTCPU &pt_cpu) { + return {pt_cpu.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown, + static_cast<uint16_t>(pt_cpu.family), + static_cast<uint8_t>(pt_cpu.model), + static_cast<uint8_t>(pt_cpu.stepping)}; +} + +TraceSP TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance( + const pt_cpu &pt_cpu, std::vector<ParsedProcess> &parsed_processes) { + std::vector<ThreadTraceSP> threads; + for (const ParsedProcess &parsed_process : parsed_processes) + threads.insert(threads.end(), parsed_process.threads.begin(), + parsed_process.threads.end()); + + TraceSP trace_instance(new TraceIntelPT(pt_cpu, threads)); + for (const ParsedProcess &parsed_process : parsed_processes) + parsed_process.target_sp->SetTrace(trace_instance); + + return trace_instance; +} + +Expected<TraceSP> TraceIntelPTSessionFileParser::Parse() { + json::Path::Root root("traceSession"); + TraceSessionFileParser::JSONTraceSession<JSONTraceIntelPTSettings> session; + if (!json::fromJSON(m_trace_session_file, session, root)) + return CreateJSONError(root, m_trace_session_file); + + if (Expected<std::vector<ParsedProcess>> parsed_processes = + ParseCommonSessionFile(session)) + return CreateTraceIntelPTInstance(ParsePTCPU(session.trace.pt_cpu), + *parsed_processes); + else + return parsed_processes.takeError(); +} + +namespace llvm { +namespace json { + +bool fromJSON(const Value &value, + TraceIntelPTSessionFileParser::JSONPTCPU &pt_cpu, Path path) { + ObjectMapper o(value, path); + return o && o.map("vendor", pt_cpu.vendor) && + o.map("family", pt_cpu.family) && o.map("model", pt_cpu.model) && + o.map("stepping", pt_cpu.stepping); +} + +bool fromJSON( + const Value &value, + TraceIntelPTSessionFileParser::JSONTraceIntelPTSettings &plugin_settings, + Path path) { + ObjectMapper o(value, path); + return o && o.map("pt_cpu", plugin_settings.pt_cpu) && + fromJSON( + value, + (TraceSessionFileParser::JSONTracePluginSettings &)plugin_settings, + path); +} + +} // namespace json +} // namespace llvm diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h new file mode 100644 index 000000000000..6a896de09d00 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h @@ -0,0 +1,84 @@ +//===-- TraceIntelPTSessionFileParser.h -----------------------*- C++ //-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H + +#include "TraceIntelPT.h" +#include "lldb/Target/TraceSessionFileParser.h" + +namespace lldb_private { +namespace trace_intel_pt { + +class TraceIntelPT; + +class TraceIntelPTSessionFileParser : public TraceSessionFileParser { +public: + struct JSONPTCPU { + std::string vendor; + int64_t family; + int64_t model; + int64_t stepping; + }; + + struct JSONTraceIntelPTSettings + : TraceSessionFileParser::JSONTracePluginSettings { + JSONPTCPU pt_cpu; + }; + + /// See \a TraceSessionFileParser::TraceSessionFileParser for the description + /// of these fields. + TraceIntelPTSessionFileParser(Debugger &debugger, + const llvm::json::Value &trace_session_file, + llvm::StringRef session_file_dir) + : TraceSessionFileParser(debugger, session_file_dir, GetSchema()), + m_trace_session_file(trace_session_file) {} + + /// \return + /// The JSON schema for the session data. + static llvm::StringRef GetSchema(); + + /// Parse the structured data trace session and create the corresponding \a + /// Target objects. In case of an error, no targets are created. + /// + /// \return + /// A \a lldb::TraceSP instance with the trace session data. In case of + /// errors, return a null pointer. + llvm::Expected<lldb::TraceSP> Parse(); + + lldb::TraceSP + CreateTraceIntelPTInstance(const pt_cpu &pt_cpu, + std::vector<ParsedProcess> &parsed_processes); + +private: + pt_cpu ParsePTCPU(const JSONPTCPU &pt_cpu); + + const llvm::json::Value &m_trace_session_file; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +namespace llvm { +namespace json { + +bool fromJSON( + const Value &value, + lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::JSONPTCPU + &pt_cpu, + Path path); + +bool fromJSON(const Value &value, + lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser:: + JSONTraceIntelPTSettings &plugin_settings, + Path path); + +} // namespace json +} // namespace llvm + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H diff --git a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 7491d0609e52..0218606b8937 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -148,10 +148,11 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) { return; clang::CXXBasePaths paths; + llvm::SmallVector<clang::NamedDecl *, 4> decls; auto find_overridden_methods = - [decl](const clang::CXXBaseSpecifier *specifier, - clang::CXXBasePath &path) { + [&decls, decl](const clang::CXXBaseSpecifier *specifier, + clang::CXXBasePath &path) { if (auto *base_record = llvm::dyn_cast<clang::CXXRecordDecl>( specifier->getType()->getAs<clang::RecordType>()->getDecl())) { @@ -163,6 +164,7 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) { if (auto *baseDtorDecl = base_record->getDestructor()) { if (baseDtorDecl->isVirtual()) { path.Decls = baseDtorDecl; + decls.push_back(baseDtorDecl); return true; } else return false; @@ -175,6 +177,7 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) { llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front())) if (method_decl->isVirtual() && !isOverload(decl, method_decl)) { path.Decls = method_decl; + decls.push_back(method_decl); return true; } } @@ -184,7 +187,7 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) { }; if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) { - for (auto *overridden_decl : paths.found_decls()) + for (auto *overridden_decl : decls) decl->addOverriddenMethod( llvm::cast<clang::CXXMethodDecl>(overridden_decl)); } @@ -610,7 +613,7 @@ lldb::TypeSystemSP TypeSystemClang::CreateInstance(lldb::LanguageType language, "ASTContext for '" + module->GetFileSpec().GetPath() + "'"; return std::make_shared<TypeSystemClang>(ast_name, triple); } else if (target && target->IsValid()) - return std::make_shared<TypeSystemClangForExpressions>(*target, triple); + return std::make_shared<ScratchTypeSystemClang>(*target, triple); return lldb::TypeSystemSP(); } @@ -1419,7 +1422,7 @@ static TemplateParameterList *CreateTemplateParameterList( clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - clang::FunctionDecl *func_decl, const char *name, + clang::FunctionDecl *func_decl, const TemplateParameterInfos &template_param_infos) { // /// Create a function template node. ASTContext &ast = getASTContext(); @@ -1657,9 +1660,9 @@ bool TypeSystemClang::FieldIsBitfield(FieldDecl *field, if (field->isBitField()) { Expr *bit_width_expr = field->getBitWidth(); if (bit_width_expr) { - llvm::APSInt bit_width_apsint; - if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, ast)) { - bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX); + if (Optional<llvm::APSInt> bit_width_apsint = + bit_width_expr->getIntegerConstantExpr(ast)) { + bitfield_bit_size = bit_width_apsint->getLimitedValue(UINT32_MAX); return true; } } @@ -1965,11 +1968,8 @@ TypeSystemClang::GetOpaqueCompilerType(clang::ASTContext *ast, #pragma mark Function Types clang::DeclarationName -TypeSystemClang::GetDeclarationName(const char *name, +TypeSystemClang::GetDeclarationName(llvm::StringRef name, const CompilerType &function_clang_type) { - if (!name || !name[0]) - return clang::DeclarationName(); - clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; if (!IsOperator(name, op_kind) || op_kind == clang::NUM_OVERLOADED_OPERATORS) return DeclarationName(&getASTContext().Idents.get( @@ -1994,10 +1994,40 @@ TypeSystemClang::GetDeclarationName(const char *name, return getASTContext().DeclarationNames.getCXXOperatorName(op_kind); } +PrintingPolicy TypeSystemClang::GetTypePrintingPolicy() { + clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); + 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.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 + // know the default arguments and where we don't know default arguments. + // + // For example, without this we would need to have formatters for both: + // std::basic_string<char> + // and + // std::basic_string<char, std::char_traits<char>, std::allocator<char> > + // to support setups where LLDB was able to reconstruct default arguments + // (and we then would have suppressed them from the type name) and also setups + // where LLDB wasn't able to reconstruct the default arguments. + printing_policy.SuppressDefaultTemplateArgs = false; + return printing_policy; +} + +std::string TypeSystemClang::GetTypeNameForDecl(const NamedDecl *named_decl) { + clang::PrintingPolicy printing_policy = GetTypePrintingPolicy(); + std::string result; + llvm::raw_string_ostream os(result); + named_decl->printQualifiedName(os, printing_policy); + return result; +} + FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - const char *name, const CompilerType &function_clang_type, int storage, - bool is_inline) { + llvm::StringRef name, const CompilerType &function_clang_type, + clang::StorageClass storage, bool is_inline) { FunctionDecl *func_decl = nullptr; ASTContext &ast = getASTContext(); if (!decl_ctx) @@ -2012,11 +2042,12 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( func_decl->setDeclContext(decl_ctx); func_decl->setDeclName(declarationName); func_decl->setType(ClangUtil::GetQualType(function_clang_type)); - func_decl->setStorageClass(static_cast<clang::StorageClass>(storage)); + func_decl->setStorageClass(storage); func_decl->setInlineSpecified(is_inline); func_decl->setHasWrittenPrototype(hasWrittenPrototype); - func_decl->setConstexprKind(isConstexprSpecified ? CSK_constexpr - : CSK_unspecified); + func_decl->setConstexprKind(isConstexprSpecified + ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); SetOwningModule(func_decl, owning_module); if (func_decl) decl_ctx->addDecl(func_decl); @@ -2499,6 +2530,8 @@ RemoveWrappingTypes(QualType type, ArrayRef<clang::Type::TypeClass> mask = {}) { case clang::Type::Decltype: case clang::Type::Elaborated: case clang::Type::Paren: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::TemplateSpecialization: case clang::Type::Typedef: case clang::Type::TypeOf: case clang::Type::TypeOfExpr: @@ -2882,20 +2915,11 @@ bool TypeSystemClang::IsCStringType(lldb::opaque_compiler_type_t type, return false; } -bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type, - bool *is_variadic_ptr) { +bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type) { if (type) { clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); if (qual_type->isFunctionType()) { - if (is_variadic_ptr) { - const clang::FunctionProtoType *function_proto_type = - llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); - if (function_proto_type) - *is_variadic_ptr = function_proto_type->isVariadic(); - else - *is_variadic_ptr = false; - } return true; } @@ -2908,8 +2932,8 @@ bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type, const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); if (reference_type) - return IsFunctionType(reference_type->getPointeeType().getAsOpaquePtr(), - nullptr); + return IsFunctionType( + reference_type->getPointeeType().getAsOpaquePtr()); } break; } } @@ -3123,6 +3147,20 @@ bool TypeSystemClang::IsEnumerationType(lldb::opaque_compiler_type_t type, return false; } +bool TypeSystemClang::IsScopedEnumerationType( + lldb::opaque_compiler_type_t type) { + if (type) { + const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>( + GetCanonicalQualType(type)->getCanonicalTypeInternal()); + + if (enum_type) { + return enum_type->isScopedEnumeralType(); + } + } + + return false; +} + bool TypeSystemClang::IsPointerType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type) { if (type) { @@ -3640,15 +3678,23 @@ ConstString TypeSystemClang::GetTypeName(lldb::opaque_compiler_type_t type) { clang::QualType qual_type(GetQualType(type)); + // Remove certain type sugar from the name. Sugar such as elaborated types + // or template types which only serve to improve diagnostics shouldn't + // act as their own types from the user's perspective (e.g., formatter + // shouldn't format a variable differently depending on how the ser has + // specified the type. '::Type' and 'Type' should behave the same). + // Typedefs and atomic derived types are not removed as they are actually + // useful for identifiying specific types. + qual_type = RemoveWrappingTypes(qual_type, + {clang::Type::Typedef, clang::Type::Atomic}); + // For a typedef just return the qualified name. if (const auto *typedef_type = qual_type->getAs<clang::TypedefType>()) { const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); - return ConstString(typedef_decl->getQualifiedNameAsString()); + return ConstString(GetTypeNameForDecl(typedef_decl)); } - clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); - printing_policy.SuppressTagKeyword = true; - return ConstString(qual_type.getAsString(printing_policy)); + return ConstString(qual_type.getAsString(GetTypePrintingPolicy())); } ConstString @@ -3661,6 +3707,7 @@ TypeSystemClang::GetDisplayTypeName(lldb::opaque_compiler_type_t type) { printing_policy.SuppressTagKeyword = true; printing_policy.SuppressScope = false; printing_policy.SuppressUnwrittenScope = true; + printing_policy.SuppressInlineNamespace = true; return ConstString(qual_type.getAsString(printing_policy)); } @@ -4088,7 +4135,7 @@ unsigned TypeSystemClang::GetTypeQualifiers(lldb::opaque_compiler_type_t type) { CompilerType TypeSystemClang::GetArrayElementType(lldb::opaque_compiler_type_t type, - uint64_t *stride) { + ExecutionContextScope *exe_scope) { if (type) { clang::QualType qual_type(GetQualType(type)); @@ -4098,14 +4145,7 @@ TypeSystemClang::GetArrayElementType(lldb::opaque_compiler_type_t type, if (!array_eletype) return CompilerType(); - CompilerType element_type = GetType(clang::QualType(array_eletype, 0)); - - // TODO: the real stride will be >= this value.. find the real one! - if (stride) - if (Optional<uint64_t> size = element_type.GetByteSize(nullptr)) - *stride = *size; - - return element_type; + return GetType(clang::QualType(array_eletype, 0)); } return CompilerType(); } @@ -4155,6 +4195,13 @@ TypeSystemClang::GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) { return CompilerType(); } +CompilerType +TypeSystemClang::GetEnumerationIntegerType(lldb::opaque_compiler_type_t type) { + if (type) + return GetEnumerationIntegerType(GetType(GetCanonicalQualType(type))); + return CompilerType(); +} + int TypeSystemClang::GetFunctionArgumentCount( lldb::opaque_compiler_type_t type) { if (type) { @@ -4376,39 +4423,6 @@ TypeSystemClang::GetNonReferenceType(lldb::opaque_compiler_type_t type) { return CompilerType(); } -CompilerType TypeSystemClang::CreateTypedefType( - const CompilerType &type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { - if (type && typedef_name && typedef_name[0]) { - TypeSystemClang *ast = - llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); - if (!ast) - return CompilerType(); - clang::ASTContext &clang_ast = ast->getASTContext(); - clang::QualType qual_type(ClangUtil::GetQualType(type)); - - clang::DeclContext *decl_ctx = - TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx); - if (!decl_ctx) - decl_ctx = ast->getASTContext().getTranslationUnitDecl(); - - clang::TypedefDecl *decl = - clang::TypedefDecl::CreateDeserialized(clang_ast, 0); - decl->setDeclContext(decl_ctx); - decl->setDeclName(&clang_ast.Idents.get(typedef_name)); - decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); - - SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); - decl->setAccess(clang::AS_public); // TODO respect proper access specifier - - decl_ctx->addDecl(decl); - - // Get a uniqued clang::QualType for the typedef decl type - return ast->GetType(clang_ast.getTypedefType(decl)); - } - return CompilerType(); -} - CompilerType TypeSystemClang::GetPointeeType(lldb::opaque_compiler_type_t type) { if (type) { @@ -4490,7 +4504,7 @@ TypeSystemClang::AddRestrictModifier(lldb::opaque_compiler_type_t type) { CompilerType TypeSystemClang::CreateTypedef( lldb::opaque_compiler_type_t type, const char *typedef_name, const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { - if (type) { + if (type && typedef_name && typedef_name[0]) { clang::ASTContext &clang_ast = getASTContext(); clang::QualType qual_type(GetQualType(type)); @@ -4499,10 +4513,12 @@ CompilerType TypeSystemClang::CreateTypedef( if (!decl_ctx) decl_ctx = getASTContext().getTranslationUnitDecl(); - clang::TypedefDecl *decl = clang::TypedefDecl::Create( - clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), - &clang_ast.Idents.get(typedef_name), - clang_ast.getTrivialTypeSourceInfo(qual_type)); + clang::TypedefDecl *decl = + clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&clang_ast.Idents.get(typedef_name)); + decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); + decl_ctx->addDecl(decl); SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); clang::TagDecl *tdecl = nullptr; @@ -4816,6 +4832,12 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin: break; + // PowerPC -- Matrix Multiply Assist + case clang::BuiltinType::VectorPair: + case clang::BuiltinType::VectorQuad: + break; + + // ARM -- Scalable Vector Extension case clang::BuiltinType::SveBool: case clang::BuiltinType::SveInt8: case clang::BuiltinType::SveInt8x2: @@ -6514,8 +6536,10 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( if (cxx_record_decl->lookupInBases( [decl_name](const clang::CXXBaseSpecifier *specifier, clang::CXXBasePath &path) { - return clang::CXXRecordDecl::FindOrdinaryMember( - specifier, path, decl_name); + path.Decls = + specifier->getType()->getAsCXXRecordDecl()->lookup( + decl_name); + return !path.Decls.empty(); }, paths)) { clang::CXXBasePaths::const_paths_iterator path, @@ -7399,7 +7423,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_dtor_decl->setType(method_qual_type); cxx_dtor_decl->setImplicit(is_artificial); cxx_dtor_decl->setInlineSpecified(is_inline); - cxx_dtor_decl->setConstexprKind(CSK_unspecified); + cxx_dtor_decl->setConstexprKind(ConstexprSpecKind::Unspecified); cxx_method_decl = cxx_dtor_decl; } else if (decl_name == cxx_record_decl->getDeclName()) { cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized( @@ -7411,7 +7435,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_ctor_decl->setType(method_qual_type); cxx_ctor_decl->setImplicit(is_artificial); cxx_ctor_decl->setInlineSpecified(is_inline); - cxx_ctor_decl->setConstexprKind(CSK_unspecified); + cxx_ctor_decl->setConstexprKind(ConstexprSpecKind::Unspecified); cxx_ctor_decl->setNumCtorInitializers(0); cxx_ctor_decl->setExplicitSpecifier(explicit_spec); cxx_method_decl = cxx_ctor_decl; @@ -7437,7 +7461,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_method_decl->setType(method_qual_type); cxx_method_decl->setStorageClass(SC); cxx_method_decl->setInlineSpecified(is_inline); - cxx_method_decl->setConstexprKind(CSK_unspecified); + cxx_method_decl->setConstexprKind(ConstexprSpecKind::Unspecified); } else if (num_params == 0) { // Conversion operators don't take params... auto *cxx_conversion_decl = @@ -7450,7 +7474,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_conversion_decl->setType(method_qual_type); cxx_conversion_decl->setInlineSpecified(is_inline); cxx_conversion_decl->setExplicitSpecifier(explicit_spec); - cxx_conversion_decl->setConstexprKind(CSK_unspecified); + cxx_conversion_decl->setConstexprKind(ConstexprSpecKind::Unspecified); cxx_method_decl = cxx_conversion_decl; } } @@ -7463,7 +7487,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_method_decl->setType(method_qual_type); cxx_method_decl->setInlineSpecified(is_inline); cxx_method_decl->setStorageClass(SC); - cxx_method_decl->setConstexprKind(CSK_unspecified); + cxx_method_decl->setConstexprKind(ConstexprSpecKind::Unspecified); } } SetMemberOwningModule(cxx_method_decl, cxx_record_decl); @@ -8925,8 +8949,7 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type, if (level == eDescriptionLevelVerbose) typedef_decl->dump(llvm_ostrm); else { - std::string clang_typedef_name( - typedef_decl->getQualifiedNameAsString()); + std::string clang_typedef_name(GetTypeNameForDecl(typedef_decl)); if (!clang_typedef_name.empty()) { s->PutCString("typedef "); s->PutCString(clang_typedef_name); @@ -9407,8 +9430,7 @@ TypeSystemClang::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) { clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx); if (named_decl) - return ConstString( - llvm::StringRef(named_decl->getQualifiedNameAsString())); + return ConstString(GetTypeNameForDecl(named_decl)); } return ConstString(); } @@ -9529,29 +9551,77 @@ TypeSystemClang::DeclContextGetTypeSystemClang(const CompilerDeclContext &dc) { return nullptr; } -TypeSystemClangForExpressions::TypeSystemClangForExpressions( - Target &target, llvm::Triple triple) - : TypeSystemClang("scratch ASTContext", triple), +namespace { +/// A specialized scratch AST used within ScratchTypeSystemClang. +/// These are the ASTs backing the different IsolatedASTKinds. They behave +/// like a normal ScratchTypeSystemClang but they don't own their own +/// persistent storage or target reference. +class SpecializedScratchAST : public TypeSystemClang { +public: + /// \param name The display name of the TypeSystemClang instance. + /// \param triple The triple used for the TypeSystemClang instance. + /// \param ast_source The ClangASTSource that should be used to complete + /// type information. + SpecializedScratchAST(llvm::StringRef name, llvm::Triple triple, + std::unique_ptr<ClangASTSource> ast_source) + : TypeSystemClang(name, triple), + m_scratch_ast_source_up(std::move(ast_source)) { + // Setup the ClangASTSource to complete this AST. + m_scratch_ast_source_up->InstallASTContext(*this); + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source( + m_scratch_ast_source_up->CreateProxy()); + SetExternalSource(proxy_ast_source); + } + + /// The ExternalASTSource that performs lookups and completes types. + std::unique_ptr<ClangASTSource> m_scratch_ast_source_up; +}; +} // namespace + +char ScratchTypeSystemClang::ID; +const llvm::NoneType ScratchTypeSystemClang::DefaultAST = llvm::None; + +ScratchTypeSystemClang::ScratchTypeSystemClang(Target &target, + llvm::Triple triple) + : TypeSystemClang("scratch ASTContext", triple), m_triple(triple), m_target_wp(target.shared_from_this()), m_persistent_variables(new ClangPersistentVariables) { - m_scratch_ast_source_up = std::make_unique<ClangASTSource>( - target.shared_from_this(), m_persistent_variables->GetClangASTImporter()); + m_scratch_ast_source_up = CreateASTSource(); m_scratch_ast_source_up->InstallASTContext(*this); llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source( m_scratch_ast_source_up->CreateProxy()); SetExternalSource(proxy_ast_source); } -void TypeSystemClangForExpressions::Finalize() { +void ScratchTypeSystemClang::Finalize() { TypeSystemClang::Finalize(); m_scratch_ast_source_up.reset(); } -UserExpression *TypeSystemClangForExpressions::GetUserExpression( +TypeSystemClang * +ScratchTypeSystemClang::GetForTarget(Target &target, + llvm::Optional<IsolatedASTKind> ast_kind, + bool create_on_demand) { + auto type_system_or_err = target.GetScratchTypeSystemForLanguage( + lldb::eLanguageTypeC, create_on_demand); + if (auto err = type_system_or_err.takeError()) { + LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET), + std::move(err), "Couldn't get scratch TypeSystemClang"); + return nullptr; + } + ScratchTypeSystemClang &scratch_ast = + llvm::cast<ScratchTypeSystemClang>(type_system_or_err.get()); + // If no dedicated sub-AST was requested, just return the main AST. + if (ast_kind == DefaultAST) + return &scratch_ast; + // Search the sub-ASTs. + return &scratch_ast.GetIsolatedAST(*ast_kind); +} + +UserExpression *ScratchTypeSystemClang::GetUserExpression( llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, Expression::ResultType desired_type, - const EvaluateExpressionOptions &options, - ValueObject *ctx_obj) { + const EvaluateExpressionOptions &options, ValueObject *ctx_obj) { TargetSP target_sp = m_target_wp.lock(); if (!target_sp) return nullptr; @@ -9560,7 +9630,7 @@ UserExpression *TypeSystemClangForExpressions::GetUserExpression( desired_type, options, ctx_obj); } -FunctionCaller *TypeSystemClangForExpressions::GetFunctionCaller( +FunctionCaller *ScratchTypeSystemClang::GetFunctionCaller( const CompilerType &return_type, const Address &function_address, const ValueList &arg_value_list, const char *name) { TargetSP target_sp = m_target_wp.lock(); @@ -9575,17 +9645,56 @@ FunctionCaller *TypeSystemClangForExpressions::GetFunctionCaller( arg_value_list, name); } -UtilityFunction * -TypeSystemClangForExpressions::GetUtilityFunction(const char *text, - const char *name) { +std::unique_ptr<UtilityFunction> +ScratchTypeSystemClang::CreateUtilityFunction(std::string text, + std::string name) { TargetSP target_sp = m_target_wp.lock(); if (!target_sp) - return nullptr; + return {}; - return new ClangUtilityFunction(*target_sp.get(), text, name); + return std::make_unique<ClangUtilityFunction>( + *target_sp.get(), std::move(text), std::move(name)); } PersistentExpressionState * -TypeSystemClangForExpressions::GetPersistentExpressionState() { +ScratchTypeSystemClang::GetPersistentExpressionState() { return m_persistent_variables.get(); } + +void ScratchTypeSystemClang::ForgetSource(ASTContext *src_ctx, + ClangASTImporter &importer) { + // Remove it as a source from the main AST. + importer.ForgetSource(&getASTContext(), src_ctx); + // Remove it as a source from all created sub-ASTs. + for (const auto &a : m_isolated_asts) + importer.ForgetSource(&a.second->getASTContext(), src_ctx); +} + +std::unique_ptr<ClangASTSource> ScratchTypeSystemClang::CreateASTSource() { + return std::make_unique<ClangASTSource>( + m_target_wp.lock()->shared_from_this(), + m_persistent_variables->GetClangASTImporter()); +} + +static llvm::StringRef +GetSpecializedASTName(ScratchTypeSystemClang::IsolatedASTKind feature) { + switch (feature) { + case ScratchTypeSystemClang::IsolatedASTKind::CppModules: + return "scratch ASTContext for C++ module types"; + } + llvm_unreachable("Unimplemented ASTFeature kind?"); +} + +TypeSystemClang &ScratchTypeSystemClang::GetIsolatedAST( + ScratchTypeSystemClang::IsolatedASTKind feature) { + auto found_ast = m_isolated_asts.find(feature); + if (found_ast != m_isolated_asts.end()) + return *found_ast->second; + + // Couldn't find the requested sub-AST, so create it now. + std::unique_ptr<TypeSystemClang> new_ast; + new_ast.reset(new SpecializedScratchAST(GetSpecializedASTName(feature), + m_triple, CreateASTSource())); + m_isolated_asts[feature] = std::move(new_ast); + return *m_isolated_asts[feature]; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 659d48812353..d1d876d05a6b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -156,18 +156,6 @@ public: static TypeSystemClang *GetASTContext(clang::ASTContext *ast_ctx); - static TypeSystemClang *GetScratch(Target &target, - bool create_on_demand = true) { - auto type_system_or_err = target.GetScratchTypeSystemForLanguage( - lldb::eLanguageTypeC, create_on_demand); - if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET), - std::move(err), "Couldn't get scratch TypeSystemClang"); - return nullptr; - } - return llvm::dyn_cast<TypeSystemClang>(&type_system_or_err.get()); - } - /// Returns the display name of this TypeSystemClang that indicates what /// purpose it serves in LLDB. Used for example in logs. llvm::StringRef getDisplayName() const { return m_display_name; } @@ -332,10 +320,11 @@ public: class TemplateParameterInfos { public: bool IsValid() const { - if (args.empty()) + // Having a pack name but no packed args doesn't make sense, so mark + // these template parameters as invalid. + if (pack_name && !packed_args) return false; return args.size() == names.size() && - ((bool)pack_name == (bool)packed_args) && (!packed_args || !packed_args->packed_args); } @@ -346,11 +335,9 @@ public: std::unique_ptr<TemplateParameterInfos> packed_args; }; - clang::FunctionTemplateDecl * - CreateFunctionTemplateDecl(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, - clang::FunctionDecl *func_decl, const char *name, - const TemplateParameterInfos &infos); + clang::FunctionTemplateDecl *CreateFunctionTemplateDecl( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + clang::FunctionDecl *func_decl, const TemplateParameterInfos &infos); void CreateFunctionTemplateSpecializationInfo( clang::FunctionDecl *func_decl, clang::FunctionTemplateDecl *Template, @@ -410,11 +397,10 @@ public: // Function Types - clang::FunctionDecl * - CreateFunctionDeclaration(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, - const char *name, const CompilerType &function_Type, - int storage, bool is_inline); + clang::FunctionDecl *CreateFunctionDeclaration( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + llvm::StringRef name, const CompilerType &function_Type, + clang::StorageClass storage, bool is_inline); CompilerType CreateFunctionType(const CompilerType &result_type, const CompilerType *args, unsigned num_args, @@ -594,8 +580,7 @@ public: bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex) override; - bool IsFunctionType(lldb::opaque_compiler_type_t type, - bool *is_variadic_ptr) override; + bool IsFunctionType(lldb::opaque_compiler_type_t type) override; uint32_t IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, CompilerType *base_type_ptr) override; @@ -617,6 +602,8 @@ public: bool IsEnumerationType(lldb::opaque_compiler_type_t type, bool &is_signed) override; + bool IsScopedEnumerationType(lldb::opaque_compiler_type_t type) override; + static bool IsObjCClassType(const CompilerType &type); static bool IsObjCClassTypeAndHasIVars(const CompilerType &type, @@ -682,16 +669,8 @@ public: // Creating related types - /// Using the current type, create a new typedef to that type using - /// "typedef_name" as the name and "decl_ctx" as the decl context. - /// \param payload is an opaque TypePayloadClang. - static CompilerType - CreateTypedefType(const CompilerType &type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx, - uint32_t opaque_payload); - CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type, - uint64_t *stride) override; + ExecutionContextScope *exe_scope) override; CompilerType GetArrayType(lldb::opaque_compiler_type_t type, uint64_t size) override; @@ -701,6 +680,9 @@ public: CompilerType GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) override; + CompilerType + GetEnumerationIntegerType(lldb::opaque_compiler_type_t type) override; + // Returns -1 if this isn't a function of if the function doesn't have a // prototype Returns a value >= 0 if there is a prototype. int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) override; @@ -737,6 +719,9 @@ public: CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type) override; + /// Using the current type, create a new typedef to that type using + /// "typedef_name" as the name and "decl_ctx" as the decl context. + /// \param opaque_payload is an opaque TypePayloadClang. CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, const CompilerDeclContext &decl_ctx, @@ -1057,7 +1042,8 @@ public: } clang::DeclarationName - GetDeclarationName(const char *name, const CompilerType &function_clang_type); + GetDeclarationName(llvm::StringRef name, + const CompilerType &function_clang_type); clang::LangOptions *GetLangOpts() const { return m_language_options_up.get(); @@ -1067,6 +1053,13 @@ public: } private: + /// Returns the PrintingPolicy used when generating the internal type names. + /// These type names are mostly used for the formatter selection. + clang::PrintingPolicy GetTypePrintingPolicy(); + /// Returns the internal type name for the given NamedDecl using the + /// type printing policy. + std::string GetTypeNameForDecl(const clang::NamedDecl *named_decl); + const clang::ClassTemplateSpecializationDecl * GetAsTemplateSpecialization(lldb::opaque_compiler_type_t type); @@ -1120,14 +1113,71 @@ private: /// The TypeSystemClang instance used for the scratch ASTContext in a /// lldb::Target. -class TypeSystemClangForExpressions : public TypeSystemClang { +class ScratchTypeSystemClang : public TypeSystemClang { + /// LLVM RTTI support + static char ID; + public: - TypeSystemClangForExpressions(Target &target, llvm::Triple triple); + ScratchTypeSystemClang(Target &target, llvm::Triple triple); - ~TypeSystemClangForExpressions() override = default; + ~ScratchTypeSystemClang() override = default; void Finalize() override; + /// The different kinds of isolated ASTs within the scratch TypeSystem. + /// + /// These ASTs are isolated from the main scratch AST and are each + /// dedicated to a special language option/feature that makes the contained + /// AST nodes incompatible with other AST nodes. + enum IsolatedASTKind { + /// The isolated AST for declarations/types from expressions that imported + /// type information from a C++ module. The templates from a C++ module + /// often conflict with the templates we generate from debug information, + /// so we put these types in their own AST. + CppModules + }; + + /// Alias for requesting the default scratch TypeSystemClang in GetForTarget. + // This isn't constexpr as gtest/llvm::Optional comparison logic is trying + // to get the address of this for pretty-printing. + static const llvm::NoneType DefaultAST; + + /// Infers the appropriate sub-AST from Clang's LangOptions. + static llvm::Optional<IsolatedASTKind> + InferIsolatedASTKindFromLangOpts(const clang::LangOptions &l) { + // If modules are activated we want the dedicated C++ module AST. + // See IsolatedASTKind::CppModules for more info. + if (l.Modules) + return IsolatedASTKind::CppModules; + return DefaultAST; + } + + /// Returns the scratch TypeSystemClang for the given target. + /// \param target The Target which scratch TypeSystemClang should be returned. + /// \param ast_kind Allows requesting a specific sub-AST instead of the + /// default scratch AST. See also `IsolatedASTKind`. + /// \param create_on_demand If the scratch TypeSystemClang instance can be + /// created by this call if it doesn't exist yet. If it doesn't exist yet and + /// this parameter is false, this function returns a nullptr. + /// \return The scratch type system of the target or a nullptr in case an + /// error occurred. + static TypeSystemClang * + GetForTarget(Target &target, + llvm::Optional<IsolatedASTKind> ast_kind = DefaultAST, + bool create_on_demand = true); + + /// Returns the scratch TypeSystemClang for the given target. The returned + /// TypeSystemClang will be the scratch AST or a sub-AST, depending on which + /// fits best to the passed LangOptions. + /// \param target The Target which scratch TypeSystemClang should be returned. + /// \param lang_opts The LangOptions of a clang ASTContext that the caller + /// wants to export type information from. This is used to + /// find the best matching sub-AST that will be returned. + static TypeSystemClang *GetForTarget(Target &target, + const clang::LangOptions &lang_opts) { + return GetForTarget(target, InferIsolatedASTKindFromLangOpts(lang_opts)); + } + UserExpression * GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, @@ -1140,16 +1190,48 @@ public: const ValueList &arg_value_list, const char *name) override; - UtilityFunction *GetUtilityFunction(const char *text, - const char *name) override; + std::unique_ptr<UtilityFunction> + CreateUtilityFunction(std::string text, std::string name) override; PersistentExpressionState *GetPersistentExpressionState() override; + + /// Unregisters the given ASTContext as a source from the scratch AST (and + /// all sub-ASTs). + /// \see ClangASTImporter::ForgetSource + void ForgetSource(clang::ASTContext *src_ctx, ClangASTImporter &importer); + + // llvm casting support + bool isA(const void *ClassID) const override { + return ClassID == &ID || TypeSystemClang::isA(ClassID); + } + static bool classof(const TypeSystem *ts) { return ts->isA(&ID); } + private: + std::unique_ptr<ClangASTSource> CreateASTSource(); + /// Returns the requested sub-AST. + /// Will lazily create the sub-AST if it hasn't been created before. + TypeSystemClang &GetIsolatedAST(IsolatedASTKind feature); + + /// The target triple. + /// This was potentially adjusted and might not be identical to the triple + /// of `m_target_wp`. + llvm::Triple m_triple; lldb::TargetWP m_target_wp; - std::unique_ptr<ClangPersistentVariables> - m_persistent_variables; // These are the persistent variables associated - // with this process for the expression parser + /// The persistent variables associated with this process for the expression + /// parser. + std::unique_ptr<ClangPersistentVariables> m_persistent_variables; + /// The ExternalASTSource that performs lookups and completes minimally + /// imported types. std::unique_ptr<ClangASTSource> m_scratch_ast_source_up; + + // FIXME: GCC 5.x doesn't support enum as map keys. + typedef int IsolatedASTKey; + + /// Map from IsolatedASTKind to their actual TypeSystemClang instance. + /// This map is lazily filled with sub-ASTs and should be accessed via + /// `GetSubAST` (which lazily fills this map). + std::unordered_map<IsolatedASTKey, std::unique_ptr<TypeSystemClang>> + m_isolated_asts; }; } // namespace lldb_private |