diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-12-18 20:30:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-04-06 20:11:55 +0000 |
commit | 5f757f3ff9144b609b3c433dfd370cc6bdc191ad (patch) | |
tree | 1b4e980b866cd26a00af34c0a653eb640bd09caf /contrib/llvm-project/lldb/source/Plugins | |
parent | 3e1c8a35f741a5d114d0ba670b15191355711fe9 (diff) | |
parent | 312c0ed19cc5276a17bacf2120097bec4515b0f1 (diff) |
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins')
231 files changed, 9786 insertions, 4434 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h index 283306ed0f81..025a7a3fc368 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h @@ -46,7 +46,7 @@ public: // in other environments there can be a large number of different functions // involved in async traps. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { - // Make sure the stack call frame addresses are are 8 byte aligned + // Make sure the stack call frame addresses are 8 byte aligned if (cfa & (8ull - 1ull)) return false; // Not 8 byte aligned if (cfa == 0) diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h index b3d4cba795f0..01d4af62fa6e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h @@ -49,7 +49,7 @@ public: // in other environments there can be a large number of different functions // involved in async traps. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { - // Make sure the stack call frame addresses are are 8 byte aligned + // Make sure the stack call frame addresses are 8 byte aligned if (cfa & (8ull - 1ull)) return false; // Not 8 byte aligned if (cfa == 0) diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.h b/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.h index a77af75e57b8..c5ebd9717575 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.h +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.h @@ -37,7 +37,7 @@ public: bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; bool CallFrameAddressIsValid(lldb::addr_t cfa) override { - // Make sure the stack call frame addresses are are 4 byte aligned + // Make sure the stack call frame addresses are 4 byte aligned if (cfa & (4ull - 1ull)) return false; // Not 4 byte aligned if (cfa == 0) diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABISysV_arm.h b/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABISysV_arm.h index ce67b367d18f..65bc3e0b6298 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABISysV_arm.h +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/ARM/ABISysV_arm.h @@ -37,7 +37,7 @@ public: bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; bool CallFrameAddressIsValid(lldb::addr_t cfa) override { - // Make sure the stack call frame addresses are are 4 byte aligned + // Make sure the stack call frame addresses are 4 byte aligned if (cfa & (4ull - 1ull)) return false; // Not 4 byte aligned if (cfa == 0) diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp new file mode 100644 index 000000000000..6395f5bb5bd9 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp @@ -0,0 +1,780 @@ +//===-- ABISysV_riscv.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 "ABISysV_riscv.h" + +#include <array> +#include <limits> + +#include "llvm/IR/DerivedTypes.h" + +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/RegisterValue.h" + +#define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString() +#define DEFINE_REG_NAME_STR(reg_name) ConstString(reg_name).GetCString() + +// The ABI is not a source of such information as size, offset, encoding, etc. +// of a register. Just provides correct dwarf and eh_frame numbers. + +#define DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, generic_num) \ + { \ + DEFINE_REG_NAME(dwarf_num), DEFINE_REG_NAME_STR(str_name), 0, 0, \ + eEncodingInvalid, eFormatDefault, \ + {dwarf_num, dwarf_num, generic_num, LLDB_INVALID_REGNUM, dwarf_num}, \ + nullptr, nullptr, nullptr, \ + } + +#define DEFINE_REGISTER_STUB(dwarf_num, str_name) \ + DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, LLDB_INVALID_REGNUM) + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE_ADV(ABISysV_riscv, ABIRISCV) + +namespace { +namespace dwarf { +enum regnums { + zero, + ra, + sp, + gp, + tp, + t0, + t1, + t2, + fp, + s0 = fp, + s1, + a0, + a1, + a2, + a3, + a4, + a5, + a6, + a7, + s2, + s3, + s4, + s5, + s6, + s7, + s8, + s9, + s10, + s11, + t3, + t4, + t5, + t6, + pc +}; + +static const std::array<RegisterInfo, 33> g_register_infos = { + {DEFINE_REGISTER_STUB(zero, nullptr), + DEFINE_GENERIC_REGISTER_STUB(ra, nullptr, LLDB_REGNUM_GENERIC_RA), + DEFINE_GENERIC_REGISTER_STUB(sp, nullptr, LLDB_REGNUM_GENERIC_SP), + DEFINE_REGISTER_STUB(gp, nullptr), + DEFINE_REGISTER_STUB(tp, nullptr), + DEFINE_REGISTER_STUB(t0, nullptr), + DEFINE_REGISTER_STUB(t1, nullptr), + DEFINE_REGISTER_STUB(t2, nullptr), + DEFINE_GENERIC_REGISTER_STUB(fp, nullptr, LLDB_REGNUM_GENERIC_FP), + DEFINE_REGISTER_STUB(s1, nullptr), + DEFINE_GENERIC_REGISTER_STUB(a0, nullptr, LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GENERIC_REGISTER_STUB(a1, nullptr, LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GENERIC_REGISTER_STUB(a2, nullptr, LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GENERIC_REGISTER_STUB(a3, nullptr, LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GENERIC_REGISTER_STUB(a4, nullptr, LLDB_REGNUM_GENERIC_ARG5), + DEFINE_GENERIC_REGISTER_STUB(a5, nullptr, LLDB_REGNUM_GENERIC_ARG6), + DEFINE_GENERIC_REGISTER_STUB(a6, nullptr, LLDB_REGNUM_GENERIC_ARG7), + DEFINE_GENERIC_REGISTER_STUB(a7, nullptr, LLDB_REGNUM_GENERIC_ARG8), + DEFINE_REGISTER_STUB(s2, nullptr), + DEFINE_REGISTER_STUB(s3, nullptr), + DEFINE_REGISTER_STUB(s4, nullptr), + DEFINE_REGISTER_STUB(s5, nullptr), + DEFINE_REGISTER_STUB(s6, nullptr), + DEFINE_REGISTER_STUB(s7, nullptr), + DEFINE_REGISTER_STUB(s8, nullptr), + DEFINE_REGISTER_STUB(s9, nullptr), + DEFINE_REGISTER_STUB(s10, nullptr), + DEFINE_REGISTER_STUB(s11, nullptr), + DEFINE_REGISTER_STUB(t3, nullptr), + DEFINE_REGISTER_STUB(t4, nullptr), + DEFINE_REGISTER_STUB(t5, nullptr), + DEFINE_REGISTER_STUB(t6, nullptr), + DEFINE_GENERIC_REGISTER_STUB(pc, nullptr, LLDB_REGNUM_GENERIC_PC)}}; +} // namespace dwarf +} // namespace + +const RegisterInfo *ABISysV_riscv::GetRegisterInfoArray(uint32_t &count) { + count = dwarf::g_register_infos.size(); + return dwarf::g_register_infos.data(); +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ + +ABISP +ABISysV_riscv::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) { + llvm::Triple::ArchType machine = arch.GetTriple().getArch(); + + if (llvm::Triple::riscv32 != machine && llvm::Triple::riscv64 != machine) + return ABISP(); + + ABISysV_riscv *abi = new ABISysV_riscv(std::move(process_sp), + MakeMCRegisterInfo(arch)); + if (abi) + abi->SetIsRV64((llvm::Triple::riscv64 == machine) ? true : false); + return ABISP(abi); +} + +static inline size_t AugmentArgSize(bool is_rv64, size_t size_in_bytes) { + size_t word_size = is_rv64 ? 8 : 4; + return llvm::alignTo(size_in_bytes, word_size); +} + +static size_t +TotalArgsSizeInWords(bool is_rv64, + const llvm::ArrayRef<ABI::CallArgument> &args) { + size_t reg_size = is_rv64 ? 8 : 4; + size_t word_size = reg_size; + size_t total_size = 0; + for (const auto &arg : args) + total_size += + (ABI::CallArgument::TargetValue == arg.type ? AugmentArgSize(is_rv64, + arg.size) + : reg_size) / + word_size; + + return total_size; +} + +bool ABISysV_riscv::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t return_addr, + llvm::ArrayRef<addr_t> args) const { + // TODO: Implement + return false; +} + +bool ABISysV_riscv::PrepareTrivialCall( + Thread &thread, addr_t sp, addr_t pc, addr_t ra, llvm::Type &prototype, + llvm::ArrayRef<ABI::CallArgument> args) const { + auto reg_ctx = thread.GetRegisterContext(); + if (!reg_ctx) + return false; + + uint32_t pc_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + if (pc_reg == LLDB_INVALID_REGNUM) + return false; + + uint32_t ra_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + if (ra_reg == LLDB_INVALID_REGNUM) + return false; + + uint32_t sp_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + if (sp_reg == LLDB_INVALID_REGNUM) + return false; + + Status error; + ProcessSP process = thread.GetProcess(); + if (!process) + return false; + + size_t reg_size = m_is_rv64 ? 8 : 4; + size_t word_size = reg_size; + // Push host data onto target. + for (const auto &arg : args) { + // Skip over target values. + if (arg.type == ABI::CallArgument::TargetValue) + continue; + + // Create space on the host stack for this data 4-byte aligned. + sp -= AugmentArgSize(m_is_rv64, arg.size); + + if (process->WriteMemory(sp, arg.data_up.get(), arg.size, error) < + arg.size || + error.Fail()) + return false; + + // Update the argument with the target pointer. + *const_cast<addr_t *>(&arg.value) = sp; + } + + // Make sure number of parameters matches prototype. + assert(prototype.getFunctionNumParams() == args.size()); + + const size_t num_args = args.size(); + const size_t regs_for_args_count = 8U; + const size_t num_args_in_regs = + num_args > regs_for_args_count ? regs_for_args_count : num_args; + + // Number of arguments passed on stack. + size_t args_size = TotalArgsSizeInWords(m_is_rv64, args); + auto on_stack = + args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count; + auto offset = on_stack * word_size; + + uint8_t reg_value[8]; + size_t reg_index = LLDB_REGNUM_GENERIC_ARG1; + + for (size_t i = 0; i < args_size; ++i) { + auto value = reinterpret_cast<const uint8_t *>(&args[i].value); + auto size = + ABI::CallArgument::TargetValue == args[i].type ? args[i].size : reg_size; + + // Pass arguments via registers. + if (i < num_args_in_regs) { + // copy value to register, padding if arg is smaller than register + auto end = size < reg_size ? size : reg_size; + memcpy(reg_value, value, end); + if (reg_size > end) + memset(reg_value + end, 0, reg_size - end); + + RegisterValue reg_val_obj(llvm::ArrayRef(reg_value, reg_size), + eByteOrderLittle); + if (!reg_ctx->WriteRegister( + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, reg_index), + reg_val_obj)) + return false; + + // NOTE: It's unsafe to iterate through LLDB_REGNUM_GENERICs + // But the "a" registers are sequential in the RISC-V register space + ++reg_index; + } + + if (reg_index < regs_for_args_count || size == 0) + continue; + + // Remaining arguments are passed on the stack. + if (process->WriteMemory(sp - offset, value, size, error) < size || + !error.Success()) + return false; + + offset -= AugmentArgSize(m_is_rv64, size); + } + + // Set stack pointer immediately below arguments. + sp -= on_stack * word_size; + + // Update registers with current function call state. + reg_ctx->WriteRegisterFromUnsigned(pc_reg, pc); + reg_ctx->WriteRegisterFromUnsigned(ra_reg, ra); + reg_ctx->WriteRegisterFromUnsigned(sp_reg, sp); + + return true; +} + +bool ABISysV_riscv::GetArgumentValues(Thread &thread, ValueList &values) const { + // TODO: Implement + return false; +} + +Status ABISysV_riscv::SetReturnValueObject(StackFrameSP &frame_sp, + ValueObjectSP &new_value_sp) { + Status result; + if (!new_value_sp) { + result.SetErrorString("Empty value object for return value."); + return result; + } + + CompilerType compiler_type = new_value_sp->GetCompilerType(); + if (!compiler_type) { + result.SetErrorString("Null clang type for return value."); + return result; + } + + auto ®_ctx = *frame_sp->GetThread()->GetRegisterContext(); + + bool is_signed = false; + if (!compiler_type.IsIntegerOrEnumerationType(is_signed) && + !compiler_type.IsPointerType()) { + result.SetErrorString("We don't support returning other types at present"); + return result; + } + + DataExtractor data; + size_t num_bytes = new_value_sp->GetData(data, result); + + if (result.Fail()) { + result.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", result.AsCString()); + return result; + } + + size_t reg_size = m_is_rv64 ? 8 : 4; + if (num_bytes <= 2 * reg_size) { + offset_t offset = 0; + uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); + + auto reg_info = + reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) { + result.SetErrorStringWithFormat("Couldn't write value to register %s", + reg_info->name); + return result; + } + + if (num_bytes <= reg_size) + return result; // Successfully written. + + // for riscv32, get the upper 32 bits from raw_value and write them + // for riscv64, get the next 64 bits from data and write them + if (4 == reg_size) + raw_value >>= 32; + else + raw_value = data.GetMaxU64(&offset, num_bytes - reg_size); + reg_info = + reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2); + if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) { + result.SetErrorStringWithFormat("Couldn't write value to register %s", + reg_info->name); + } + + return result; + } + + result.SetErrorString( + "We don't support returning large integer values at present."); + return result; +} + +template <typename T> +static void SetInteger(Scalar &scalar, uint64_t raw_value, bool is_signed) { + raw_value &= std::numeric_limits<T>::max(); + if (is_signed) + scalar = static_cast<typename std::make_signed<T>::type>(raw_value); + else + scalar = static_cast<T>(raw_value); +} + +static bool SetSizedInteger(Scalar &scalar, uint64_t raw_value, + uint8_t size_in_bytes, bool is_signed) { + switch (size_in_bytes) { + default: + return false; + + case sizeof(uint64_t): + SetInteger<uint64_t>(scalar, raw_value, is_signed); + break; + + case sizeof(uint32_t): + SetInteger<uint32_t>(scalar, raw_value, is_signed); + break; + + case sizeof(uint16_t): + SetInteger<uint16_t>(scalar, raw_value, is_signed); + break; + + case sizeof(uint8_t): + SetInteger<uint8_t>(scalar, raw_value, is_signed); + break; + } + + return true; +} + +static bool SetSizedFloat(Scalar &scalar, uint64_t raw_value, + uint8_t size_in_bytes) { + switch (size_in_bytes) { + default: + return false; + + case sizeof(uint64_t): + scalar = *reinterpret_cast<double *>(&raw_value); + break; + + case sizeof(uint32_t): + scalar = *reinterpret_cast<float *>(&raw_value); + break; + } + + return true; +} + +static ValueObjectSP GetValObjFromIntRegs(Thread &thread, + const RegisterContextSP ®_ctx, + llvm::Triple::ArchType machine, + uint32_t type_flags, + uint32_t byte_size) { + Value value; + ValueObjectSP return_valobj_sp; + auto reg_info_a0 = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + auto reg_info_a1 = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2); + uint64_t raw_value; + + switch (byte_size) { + case sizeof(uint32_t): + // Read a0 to get the arg + raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0) & UINT32_MAX; + break; + case sizeof(uint64_t): + // Read a0 to get the arg on riscv64, a0 and a1 on riscv32 + if (llvm::Triple::riscv32 == machine) { + raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0) & UINT32_MAX; + raw_value |= + (reg_ctx->ReadRegisterAsUnsigned(reg_info_a1, 0) & UINT32_MAX) << 32U; + } else { + raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0); + } + break; + case 16: { + // Read a0 and a1 to get the arg on riscv64, not supported on riscv32 + if (llvm::Triple::riscv32 == machine) + return return_valobj_sp; + + // Create the ValueObjectSP here and return + std::unique_ptr<DataBufferHeap> heap_data_up( + new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = thread.GetProcess()->GetByteOrder(); + RegisterValue reg_value_a0, reg_value_a1; + if (reg_ctx->ReadRegister(reg_info_a0, reg_value_a0) && + reg_ctx->ReadRegister(reg_info_a1, reg_value_a1)) { + Status error; + if (reg_value_a0.GetAsMemoryData(*reg_info_a0, + heap_data_up->GetBytes() + 0, 8, + byte_order, error) && + reg_value_a1.GetAsMemoryData(*reg_info_a1, + heap_data_up->GetBytes() + 8, 8, + byte_order, error)) { + value.SetBytes(heap_data_up.release(), byte_size); + return ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } + } + break; + } + default: + return return_valobj_sp; + } + + if (type_flags & eTypeIsInteger) { + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed)) + return return_valobj_sp; + } else if (type_flags & eTypeIsFloat) { + if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size)) + return return_valobj_sp; + } else + return return_valobj_sp; + + value.SetValueType(Value::ValueType::Scalar); + return_valobj_sp = ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + return return_valobj_sp; +} + +static ValueObjectSP +GetValObjFromFPRegs(Thread &thread, const RegisterContextSP ®_ctx, + llvm::Triple::ArchType machine, uint32_t arch_fp_flags, + uint32_t type_flags, uint32_t byte_size) { + auto reg_info_fa0 = reg_ctx->GetRegisterInfoByName("fa0"); + bool use_fp_regs = false; + ValueObjectSP return_valobj_sp; + + switch (arch_fp_flags) { + // fp return value in integer registers a0 and possibly a1 + case ArchSpec::eRISCV_float_abi_soft: + return_valobj_sp = + GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size); + return return_valobj_sp; + // fp return value in fp register fa0 (only float) + case ArchSpec::eRISCV_float_abi_single: + if (byte_size <= 4) + use_fp_regs = true; + break; + // fp return value in fp registers fa0 (float, double) + case ArchSpec::eRISCV_float_abi_double: + [[fallthrough]]; + // fp return value in fp registers fa0 (float, double, quad) + // not implemented; act like they're doubles + case ArchSpec::eRISCV_float_abi_quad: + if (byte_size <= 8) + use_fp_regs = true; + break; + } + + if (use_fp_regs) { + uint64_t raw_value; + Value value; + raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info_fa0, 0); + if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size)) + return return_valobj_sp; + value.SetValueType(Value::ValueType::Scalar); + return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), + value, ConstString("")); + } + // we should never reach this, but if we do, use the integer registers + return GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size); +} + +ValueObjectSP +ABISysV_riscv::GetReturnValueObjectSimple(Thread &thread, + CompilerType &compiler_type) const { + ValueObjectSP return_valobj_sp; + + if (!compiler_type) + return return_valobj_sp; + + auto reg_ctx = thread.GetRegisterContext(); + if (!reg_ctx) + return return_valobj_sp; + + Value value; + value.SetCompilerType(compiler_type); + + const uint32_t type_flags = compiler_type.GetTypeInfo(); + const size_t byte_size = compiler_type.GetByteSize(&thread).value_or(0); + const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture(); + const llvm::Triple::ArchType machine = arch.GetMachine(); + + // Integer return type. + if (type_flags & eTypeIsInteger) { + return_valobj_sp = + GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size); + return return_valobj_sp; + } + // Pointer return type. + else if (type_flags & eTypeIsPointer) { + auto reg_info_a0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1); + value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0); + value.SetValueType(Value::ValueType::Scalar); + return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), + value, ConstString("")); + } + // Floating point return type. + else if (type_flags & eTypeIsFloat) { + uint32_t float_count = 0; + bool is_complex = false; + + if (compiler_type.IsFloatingPointType(float_count, is_complex) && + float_count == 1 && !is_complex) { + const uint32_t arch_fp_flags = + arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask; + return_valobj_sp = GetValObjFromFPRegs( + thread, reg_ctx, machine, arch_fp_flags, type_flags, byte_size); + return return_valobj_sp; + } + } + // Unsupported return type. + return return_valobj_sp; +} + +ValueObjectSP +ABISysV_riscv::GetReturnValueObjectImpl(lldb_private::Thread &thread, + llvm::Type &type) const { + Value value; + ValueObjectSP return_valobj_sp; + + auto reg_ctx = thread.GetRegisterContext(); + if (!reg_ctx) + return return_valobj_sp; + + uint32_t type_flags = 0; + if (type.isIntegerTy()) + type_flags = eTypeIsInteger; + else if (type.isVoidTy()) + type_flags = eTypeIsPointer; + else if (type.isFloatTy()) + type_flags = eTypeIsFloat; + + const uint32_t byte_size = type.getPrimitiveSizeInBits() / CHAR_BIT; + const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture(); + const llvm::Triple::ArchType machine = arch.GetMachine(); + + // Integer return type. + if (type_flags & eTypeIsInteger) { + return_valobj_sp = + GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size); + return return_valobj_sp; + } + // Pointer return type. + else if (type_flags & eTypeIsPointer) { + auto reg_info_a0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1); + value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0); + value.SetValueType(Value::ValueType::Scalar); + return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), + value, ConstString("")); + } + // Floating point return type. + else if (type_flags & eTypeIsFloat) { + const uint32_t arch_fp_flags = + arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask; + return_valobj_sp = GetValObjFromFPRegs( + thread, reg_ctx, machine, arch_fp_flags, type_flags, byte_size); + return return_valobj_sp; + } + // Unsupported return type. + return return_valobj_sp; +} + +ValueObjectSP ABISysV_riscv::GetReturnValueObjectImpl( + Thread &thread, CompilerType &return_compiler_type) const { + ValueObjectSP return_valobj_sp; + + if (!return_compiler_type) + return return_valobj_sp; + + ExecutionContext exe_ctx(thread.shared_from_this()); + return GetReturnValueObjectSimple(thread, return_compiler_type); +} + +bool ABISysV_riscv::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC; + uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP; + uint32_t ra_reg_num = LLDB_REGNUM_GENERIC_RA; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Define CFA as the stack pointer + row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); + + // Previous frame's pc is in ra + + row->SetRegisterLocationToRegister(pc_reg_num, ra_reg_num, true); + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("riscv function-entry unwind plan"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + + return true; +} + +bool ABISysV_riscv::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindGeneric); + + uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC; + uint32_t fp_reg_num = LLDB_REGNUM_GENERIC_FP; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Define the CFA as the current frame pointer value. + row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 0); + row->SetOffset(0); + + int reg_size = 4; + if (m_is_rv64) + reg_size = 8; + + // Assume the ra reg (return pc) and caller's frame pointer + // have been spilled to stack already. + row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, reg_size * -2, true); + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, reg_size * -1, true); + + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("riscv default unwind plan"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + return true; +} + +bool ABISysV_riscv::RegisterIsVolatile(const RegisterInfo *reg_info) { + return !RegisterIsCalleeSaved(reg_info); +} + +bool ABISysV_riscv::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { + if (!reg_info) + return false; + + const char *name = reg_info->name; + ArchSpec arch = GetProcessSP()->GetTarget().GetArchitecture(); + uint32_t arch_flags = arch.GetFlags(); + // floating point registers are only callee saved when using + // F, D or Q hardware floating point ABIs + bool is_hw_fp = (arch_flags & ArchSpec::eRISCV_float_abi_mask) != 0; + + bool is_callee_saved = + llvm::StringSwitch<bool>(name) + // integer ABI names + .Cases("ra", "sp", "fp", true) + .Cases("s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", + true) + .Cases("s10", "s11", true) + // integer hardware names + .Cases("x1", "x2", "x8", "x9", "x18", "x19", "x20", "x21", "x22", + true) + .Cases("x23", "x24", "x25", "x26", "x27", true) + // floating point ABI names + .Cases("fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", + is_hw_fp) + .Cases("fs8", "fs9", "fs10", "fs11", is_hw_fp) + // floating point hardware names + .Cases("f8", "f9", "f18", "f19", "f20", "f21", "f22", "f23", is_hw_fp) + .Cases("f24", "f25", "f26", "f27", is_hw_fp) + .Default(false); + + return is_callee_saved; +} + +void ABISysV_riscv::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "System V ABI for RISCV targets", CreateInstance); +} + +void ABISysV_riscv::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +static uint32_t GetGenericNum(llvm::StringRef name) { + return llvm::StringSwitch<uint32_t>(name) + .Case("pc", LLDB_REGNUM_GENERIC_PC) + .Cases("ra", "x1", LLDB_REGNUM_GENERIC_RA) + .Cases("sp", "x2", LLDB_REGNUM_GENERIC_SP) + .Cases("fp", "s0", LLDB_REGNUM_GENERIC_FP) + .Case("a0", LLDB_REGNUM_GENERIC_ARG1) + .Case("a1", LLDB_REGNUM_GENERIC_ARG2) + .Case("a2", LLDB_REGNUM_GENERIC_ARG3) + .Case("a3", LLDB_REGNUM_GENERIC_ARG4) + .Case("a4", LLDB_REGNUM_GENERIC_ARG5) + .Case("a5", LLDB_REGNUM_GENERIC_ARG6) + .Case("a6", LLDB_REGNUM_GENERIC_ARG7) + .Case("a7", LLDB_REGNUM_GENERIC_ARG8) + .Default(LLDB_INVALID_REGNUM); +} + +void ABISysV_riscv::AugmentRegisterInfo( + std::vector<lldb_private::DynamicRegisterInfo::Register> ®s) { + lldb_private::RegInfoBasedABI::AugmentRegisterInfo(regs); + + for (auto it : llvm::enumerate(regs)) { + // Set alt name for certain registers for convenience + if (it.value().name == "zero") + it.value().alt_name.SetCString("x0"); + else if (it.value().name == "ra") + it.value().alt_name.SetCString("x1"); + else if (it.value().name == "sp") + it.value().alt_name.SetCString("x2"); + else if (it.value().name == "gp") + it.value().alt_name.SetCString("x3"); + else if (it.value().name == "fp") + it.value().alt_name.SetCString("s0"); + else if (it.value().name == "s0") + it.value().alt_name.SetCString("x8"); + + // Set generic regnum so lldb knows what the PC, etc is + it.value().regnum_generic = GetGenericNum(it.value().name.GetStringRef()); + } +} diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h b/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h new file mode 100644 index 000000000000..d8cf008dbb0b --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h @@ -0,0 +1,129 @@ +//===-- ABISysV_riscv.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_ABISysV_riscv_h_ +#define liblldb_ABISysV_riscv_h_ + +// Other libraries and framework includes +#include "llvm/TargetParser/Triple.h" + +// Project includes +#include "lldb/Target/ABI.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/Flags.h" +#include "lldb/lldb-private.h" + +class ABISysV_riscv : public lldb_private::RegInfoBasedABI { +public: + ~ABISysV_riscv() override = default; + + size_t GetRedZoneSize() const override { return 0; } + + bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef<lldb::addr_t> args) const override; + + // Special thread plan for GDB style non-jit function calls. + bool + PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, lldb::addr_t returnAddress, + llvm::Type &prototype, + llvm::ArrayRef<ABI::CallArgument> args) const override; + + bool GetArgumentValues(lldb_private::Thread &thread, + lldb_private::ValueList &values) const override; + + lldb_private::Status + SetReturnValueObject(lldb::StackFrameSP &frame_sp, + lldb::ValueObjectSP &new_value) override; + + lldb::ValueObjectSP + GetReturnValueObjectImpl(lldb_private::Thread &thread, + lldb_private::CompilerType &type) const override; + + // Specialized to work with llvm IR types. + lldb::ValueObjectSP GetReturnValueObjectImpl(lldb_private::Thread &thread, + llvm::Type &type) const override; + + bool + CreateFunctionEntryUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override; + + bool CreateDefaultUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override; + + bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; + + bool CallFrameAddressIsValid(lldb::addr_t cfa) override { + // The CFA must be 128 bit aligned, unless the E ABI is used + lldb_private::ArchSpec arch = GetProcessSP()->GetTarget().GetArchitecture(); + lldb_private::Flags arch_flags = arch.GetFlags(); + if (arch_flags.Test(lldb_private::ArchSpec::eRISCV_rve)) + return (cfa & 0x3ull) == 0; + return (cfa & 0xfull) == 0; + } + + void SetIsRV64(bool is_rv64) { m_is_rv64 = is_rv64; } + + bool CodeAddressIsValid(lldb::addr_t pc) override { + // Calls can use the least significant bit to store auxiliary information, + // so no strict check is done for alignment. + + lldb_private::ArchSpec arch = GetProcessSP()->GetTarget().GetArchitecture(); + + // <addr> & 2 set is a fault if C extension is not used. + lldb_private::Flags arch_flags(arch.GetFlags()); + if (!arch_flags.Test(lldb_private::ArchSpec::eRISCV_rvc) && (pc & 2)) + return false; + + // Make sure 64 bit addr_t only has lower 32 bits set on riscv32 + llvm::Triple::ArchType machine = arch.GetMachine(); + if (llvm::Triple::riscv32 == machine) + return (pc <= UINT32_MAX); + + return true; + } + + const lldb_private::RegisterInfo * + GetRegisterInfoArray(uint32_t &count) override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + + static void Initialize(); + + static void Terminate(); + + static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, + const lldb_private::ArchSpec &arch); + + static llvm::StringRef GetPluginNameStatic() { return "sysv-riscv"; } + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +protected: + void AugmentRegisterInfo( + std::vector<lldb_private::DynamicRegisterInfo::Register> ®s) override; + + bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); + +private: + lldb::ValueObjectSP + GetReturnValueObjectSimple(lldb_private::Thread &thread, + lldb_private::CompilerType &ast_type) const; + + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance + // instead. + bool m_is_rv64; // true if target is riscv64; false if target is riscv32 +}; + +#endif // liblldb_ABISysV_riscv_h_ diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.h b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.h index 462317f17666..8c637b7671f6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.h +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.h @@ -52,7 +52,7 @@ public: // If we were to enforce 16-byte alignment, we also need to relax to 4-byte // alignment for non-darwin i386 targets. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { - // Make sure the stack call frame addresses are are 4 byte aligned + // Make sure the stack call frame addresses are 4 byte aligned if (cfa & (4ull - 1ull)) return false; // Not 4 byte aligned if (cfa == 0) diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp b/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp index 1b2b41ee8758..181ba4e7d877 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp @@ -8,7 +8,10 @@ #include "Plugins/Architecture/AArch64/ArchitectureAArch64.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Target/RegisterContext.h" #include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataExtractor.h" using namespace lldb_private; using namespace lldb; @@ -34,3 +37,88 @@ ArchitectureAArch64::Create(const ArchSpec &arch) { } return std::unique_ptr<Architecture>(new ArchitectureAArch64()); } + +static void +UpdateARM64SVERegistersInfos(DynamicRegisterInfo::reg_collection_range regs, + 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 ® : 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; + } +} + +static void +UpdateARM64SMERegistersInfos(DynamicRegisterInfo::reg_collection_range regs, + uint64_t svg) { + for (auto ® : regs) { + if (strcmp(reg.name, "za") == 0) { + // ZA is a register with size (svg*8) * (svg*8). A square essentially. + reg.byte_size = (svg * 8) * (svg * 8); + } + reg.byte_offset = LLDB_INVALID_INDEX32; + } +} + +bool ArchitectureAArch64::ReconfigureRegisterInfo(DynamicRegisterInfo ®_info, + DataExtractor ®_data, + RegisterContext ®_context + +) const { + // Once we start to reconfigure registers, we cannot read any of them. + // So we must read VG and SVG up front. + + const uint64_t fail_value = LLDB_INVALID_ADDRESS; + std::optional<uint64_t> vg_reg_value; + const RegisterInfo *vg_reg_info = reg_info.GetRegisterInfo("vg"); + if (vg_reg_info) { + uint32_t vg_reg_num = vg_reg_info->kinds[eRegisterKindLLDB]; + uint64_t reg_value = + reg_context.ReadRegisterAsUnsigned(vg_reg_num, fail_value); + if (reg_value != fail_value && reg_value <= 32) + vg_reg_value = reg_value; + } + + std::optional<uint64_t> svg_reg_value; + const RegisterInfo *svg_reg_info = reg_info.GetRegisterInfo("svg"); + if (svg_reg_info) { + uint32_t svg_reg_num = svg_reg_info->kinds[eRegisterKindLLDB]; + uint64_t reg_value = + reg_context.ReadRegisterAsUnsigned(svg_reg_num, fail_value); + if (reg_value != fail_value && reg_value <= 32) + svg_reg_value = reg_value; + } + + if (!vg_reg_value && !svg_reg_value) + return false; + + auto regs = reg_info.registers<DynamicRegisterInfo::reg_collection_range>(); + if (vg_reg_value) + UpdateARM64SVERegistersInfos(regs, *vg_reg_value); + if (svg_reg_value) + UpdateARM64SMERegistersInfos(regs, *svg_reg_value); + + // At this point if we have updated any registers, their offsets will all be + // invalid. If we did, we need to update them all. + reg_info.ConfigureOffsets(); + // From here we are able to read registers again. + + // Make a heap based buffer that is big enough to store all registers + reg_data.SetData( + std::make_shared<DataBufferHeap>(reg_info.GetRegisterDataByteSize(), 0)); + reg_data.SetByteOrder(reg_context.GetByteOrder()); + + return true; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h b/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h index da0b867fb1e9..ba409428c951 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h @@ -28,6 +28,17 @@ public: return &m_memory_tag_manager; } + bool + RegisterWriteCausesReconfigure(const llvm::StringRef name) const override { + // lldb treats svg as read only, so only vg can be written. This results in + // the SVE registers changing size. + return name == "vg"; + } + + bool ReconfigureRegisterInfo(DynamicRegisterInfo ®_info, + DataExtractor ®_data, + RegisterContext ®_context) const override; + private: static std::unique_ptr<Architecture> Create(const ArchSpec &arch); ArchitectureAArch64() = default; diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp b/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp index bb44675e842e..81c72122cb7e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp @@ -51,7 +51,7 @@ void ArchitectureArm::OverrideStopInfo(Thread &thread) const { // stepping because the debugger stops regardless due to the BVR/BCR // triggering a stop. // - // It also means we can set breakpoints on instructions inside an an if/then + // It also means we can set breakpoints on instructions inside an if/then // block and correctly skip them if we use the BKPT instruction. The ARM and // Thumb BKPT instructions are unconditional even when executed in a Thumb IT // block. 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 09115cc670da..1628107170e7 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -18,6 +18,7 @@ #include "llvm/MC/MCDisassembler/MCRelocationInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -59,9 +60,11 @@ public: uint64_t GetMCInst(const uint8_t *opcode_data, size_t opcode_data_len, lldb::addr_t pc, llvm::MCInst &mc_inst) const; - void PrintMCInst(llvm::MCInst &mc_inst, std::string &inst_string, - std::string &comments_string); + void PrintMCInst(llvm::MCInst &mc_inst, lldb::addr_t pc, + std::string &inst_string, std::string &comments_string); void SetStyle(bool use_hex_immed, HexImmediateStyle hex_style); + void SetUseColor(bool use_color); + bool GetUseColor() const; bool CanBranch(llvm::MCInst &mc_inst) const; bool HasDelaySlot(llvm::MCInst &mc_inst) const; bool IsCall(llvm::MCInst &mc_inst) const; @@ -75,7 +78,8 @@ private: std::unique_ptr<llvm::MCAsmInfo> &&asm_info_up, std::unique_ptr<llvm::MCContext> &&context_up, std::unique_ptr<llvm::MCDisassembler> &&disasm_up, - std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up); + std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up, + std::unique_ptr<llvm::MCInstrAnalysis> &&instr_analysis_up); std::unique_ptr<llvm::MCInstrInfo> m_instr_info_up; std::unique_ptr<llvm::MCRegisterInfo> m_reg_info_up; @@ -84,6 +88,7 @@ private: std::unique_ptr<llvm::MCContext> m_context_up; std::unique_ptr<llvm::MCDisassembler> m_disasm_up; std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_up; + std::unique_ptr<llvm::MCInstrAnalysis> m_instr_analysis_up; }; namespace x86 { @@ -562,7 +567,9 @@ public: if (m_opcode.GetData(data)) { std::string out_string; + std::string markup_out_string; std::string comment_string; + std::string markup_comment_string; DisassemblerScope disasm(*this, exe_ctx); if (disasm) { @@ -604,7 +611,14 @@ public: if (inst_size > 0) { mc_disasm_ptr->SetStyle(use_hex_immediates, hex_style); - mc_disasm_ptr->PrintMCInst(inst, out_string, comment_string); + + const bool saved_use_color = mc_disasm_ptr->GetUseColor(); + mc_disasm_ptr->SetUseColor(false); + mc_disasm_ptr->PrintMCInst(inst, pc, out_string, comment_string); + mc_disasm_ptr->SetUseColor(true); + mc_disasm_ptr->PrintMCInst(inst, pc, markup_out_string, + markup_comment_string); + mc_disasm_ptr->SetUseColor(saved_use_color); if (!comment_string.empty()) { AppendComment(comment_string); @@ -669,6 +683,11 @@ public: m_opcode_name = matches[1].str(); m_mnemonics = matches[2].str(); } + matches.clear(); + if (s_regex.Execute(markup_out_string, &matches)) { + m_markup_opcode_name = matches[1].str(); + m_markup_mnemonics = matches[2].str(); + } } } } @@ -1287,11 +1306,17 @@ DisassemblerLLVMC::MCDisasmInstance::Create(const char *triple, const char *cpu, if (!instr_printer_up) return Instance(); - return Instance( - new MCDisasmInstance(std::move(instr_info_up), std::move(reg_info_up), - std::move(subtarget_info_up), std::move(asm_info_up), - std::move(context_up), std::move(disasm_up), - std::move(instr_printer_up))); + instr_printer_up->setPrintBranchImmAsAddress(true); + + // Not all targets may have registered createMCInstrAnalysis(). + std::unique_ptr<llvm::MCInstrAnalysis> instr_analysis_up( + curr_target->createMCInstrAnalysis(instr_info_up.get())); + + return Instance(new MCDisasmInstance( + std::move(instr_info_up), std::move(reg_info_up), + std::move(subtarget_info_up), std::move(asm_info_up), + std::move(context_up), std::move(disasm_up), std::move(instr_printer_up), + std::move(instr_analysis_up))); } DisassemblerLLVMC::MCDisasmInstance::MCDisasmInstance( @@ -1301,13 +1326,15 @@ DisassemblerLLVMC::MCDisasmInstance::MCDisasmInstance( std::unique_ptr<llvm::MCAsmInfo> &&asm_info_up, std::unique_ptr<llvm::MCContext> &&context_up, std::unique_ptr<llvm::MCDisassembler> &&disasm_up, - std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up) + std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up, + std::unique_ptr<llvm::MCInstrAnalysis> &&instr_analysis_up) : m_instr_info_up(std::move(instr_info_up)), m_reg_info_up(std::move(reg_info_up)), m_subtarget_info_up(std::move(subtarget_info_up)), m_asm_info_up(std::move(asm_info_up)), m_context_up(std::move(context_up)), m_disasm_up(std::move(disasm_up)), - m_instr_printer_up(std::move(instr_printer_up)) { + m_instr_printer_up(std::move(instr_printer_up)), + m_instr_analysis_up(std::move(instr_analysis_up)) { assert(m_instr_info_up && m_reg_info_up && m_subtarget_info_up && m_asm_info_up && m_context_up && m_disasm_up && m_instr_printer_up); } @@ -1328,15 +1355,17 @@ uint64_t DisassemblerLLVMC::MCDisasmInstance::GetMCInst( } void DisassemblerLLVMC::MCDisasmInstance::PrintMCInst( - llvm::MCInst &mc_inst, std::string &inst_string, + llvm::MCInst &mc_inst, lldb::addr_t pc, std::string &inst_string, std::string &comments_string) { llvm::raw_string_ostream inst_stream(inst_string); llvm::raw_string_ostream comments_stream(comments_string); + inst_stream.enable_colors(m_instr_printer_up->getUseColor()); m_instr_printer_up->setCommentStream(comments_stream); - m_instr_printer_up->printInst(&mc_inst, 0, llvm::StringRef(), + m_instr_printer_up->printInst(&mc_inst, pc, llvm::StringRef(), *m_subtarget_info_up, inst_stream); m_instr_printer_up->setCommentStream(llvm::nulls()); + comments_stream.flush(); static std::string g_newlines("\r\n"); @@ -1363,8 +1392,18 @@ void DisassemblerLLVMC::MCDisasmInstance::SetStyle( } } +void DisassemblerLLVMC::MCDisasmInstance::SetUseColor(bool use_color) { + m_instr_printer_up->setUseColor(use_color); +} + +bool DisassemblerLLVMC::MCDisasmInstance::GetUseColor() const { + return m_instr_printer_up->getUseColor(); +} + bool DisassemblerLLVMC::MCDisasmInstance::CanBranch( llvm::MCInst &mc_inst) const { + if (m_instr_analysis_up) + return m_instr_analysis_up->mayAffectControlFlow(mc_inst, *m_reg_info_up); return m_instr_info_up->get(mc_inst.getOpcode()) .mayAffectControlFlow(mc_inst, *m_reg_info_up); } @@ -1375,6 +1414,8 @@ bool DisassemblerLLVMC::MCDisasmInstance::HasDelaySlot( } bool DisassemblerLLVMC::MCDisasmInstance::IsCall(llvm::MCInst &mc_inst) const { + if (m_instr_analysis_up) + return m_instr_analysis_up->isCall(mc_inst); return m_instr_info_up->get(mc_inst.getOpcode()).isCall(); } @@ -1535,6 +1576,8 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, ArchSpec::eRISCV_float_abi_quad) features_str += "+f,+d,+q,"; // FIXME: how do we detect features such as `+a`, `+m`? + // Turn them on by default now, since everyone seems to use them + features_str += "+a,+m,"; } // 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/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp new file mode 100644 index 000000000000..6d2e17d4eac6 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp @@ -0,0 +1,789 @@ +//===-- DynamicLoaderFreeBSDKernel.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/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/StreamFile.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/OperatingSystem.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "Plugins/ObjectFile/ELF/ObjectFileELF.h" + +#include "DynamicLoaderFreeBSDKernel.h" +#include <memory> +#include <mutex> + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(DynamicLoaderFreeBSDKernel) + +void DynamicLoaderFreeBSDKernel::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInit); +} + +void DynamicLoaderFreeBSDKernel::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +llvm::StringRef DynamicLoaderFreeBSDKernel::GetPluginDescriptionStatic() { + return "The Dynamic Loader Plugin For FreeBSD Kernel"; +} + +static bool is_kernel(Module *module) { + if (!module) + return false; + + ObjectFile *objfile = module->GetObjectFile(); + if (!objfile) + return false; + if (objfile->GetType() != ObjectFile::eTypeExecutable) + return false; + if (objfile->GetStrata() != ObjectFile::eStrataUnknown && + objfile->GetStrata() != ObjectFile::eStrataKernel) + return false; + + return true; +} + +static bool is_kmod(Module *module) { + if (!module) + return false; + if (!module->GetObjectFile()) + return false; + ObjectFile *objfile = module->GetObjectFile(); + if (objfile->GetType() != ObjectFile::eTypeObjectFile && + objfile->GetType() != ObjectFile::eTypeSharedLibrary) + return false; + + return true; +} + +static bool is_reloc(Module *module) { + if (!module) + return false; + if (!module->GetObjectFile()) + return false; + ObjectFile *objfile = module->GetObjectFile(); + if (objfile->GetType() != ObjectFile::eTypeObjectFile) + return false; + + return true; +} + +// Instantiate Function of the FreeBSD Kernel Dynamic Loader Plugin called when +// Register the Plugin +DynamicLoader * +DynamicLoaderFreeBSDKernel::CreateInstance(lldb_private::Process *process, + bool force) { + // Check the environment when the plugin is not force loaded + Module *exec = process->GetTarget().GetExecutableModulePointer(); + if (exec && !is_kernel(exec)) { + return nullptr; + } + if (!force) { + // Check if the target is kernel + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (!triple_ref.isOSFreeBSD()) { + return nullptr; + } + } + + // At this point we have checked the target is a FreeBSD kernel and all we + // have to do is to find the kernel address + const addr_t kernel_address = FindFreeBSDKernel(process); + + if (CheckForKernelImageAtAddress(process, kernel_address).IsValid()) + return new DynamicLoaderFreeBSDKernel(process, kernel_address); + + return nullptr; +} + +addr_t +DynamicLoaderFreeBSDKernel::FindFreeBSDKernel(lldb_private::Process *process) { + addr_t kernel_addr = process->GetImageInfoAddress(); + if (kernel_addr == LLDB_INVALID_ADDRESS) + kernel_addr = FindKernelAtLoadAddress(process); + return kernel_addr; +} + +// Get the kernel address if the kernel is not loaded with a slide +addr_t DynamicLoaderFreeBSDKernel::FindKernelAtLoadAddress( + lldb_private::Process *process) { + Module *exe_module = process->GetTarget().GetExecutableModulePointer(); + + if (!is_kernel(exe_module)) + return LLDB_INVALID_ADDRESS; + + ObjectFile *exe_objfile = exe_module->GetObjectFile(); + + if (!exe_objfile->GetBaseAddress().IsValid()) + return LLDB_INVALID_ADDRESS; + + if (CheckForKernelImageAtAddress( + process, exe_objfile->GetBaseAddress().GetFileAddress()) + .IsValid()) + return exe_objfile->GetBaseAddress().GetFileAddress(); + + return LLDB_INVALID_ADDRESS; +} + +// Read ELF header from memry and return +bool DynamicLoaderFreeBSDKernel::ReadELFHeader(Process *process, + lldb::addr_t addr, + llvm::ELF::Elf32_Ehdr &header, + bool *read_error) { + Status error; + if (read_error) + *read_error = false; + + if (process->ReadMemory(addr, &header, sizeof(header), error) != + sizeof(header)) { + if (read_error) + *read_error = true; + return false; + } + + if (!header.checkMagic()) + return false; + + return true; +} + +// Check the correctness of Kernel and return UUID +lldb_private::UUID DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress( + Process *process, lldb::addr_t addr, bool *read_error) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (addr == LLDB_INVALID_ADDRESS) { + if (read_error) + *read_error = true; + return UUID(); + } + + LLDB_LOGF(log, + "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress: " + "looking for kernel binary at 0x%" PRIx64, + addr); + + llvm::ELF::Elf32_Ehdr header; + if (!ReadELFHeader(process, addr, header)) { + *read_error = true; + return UUID(); + } + + // Check header type + if (header.e_type != llvm::ELF::ET_EXEC) + return UUID(); + + ModuleSP memory_module_sp = + process->ReadModuleFromMemory(FileSpec("temp_freebsd_kernel"), addr); + + if (!memory_module_sp.get()) { + *read_error = true; + return UUID(); + } + + ObjectFile *exe_objfile = memory_module_sp->GetObjectFile(); + if (exe_objfile == nullptr) { + LLDB_LOGF(log, + "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress " + "found a binary at 0x%" PRIx64 + " but could not create an object file from memory", + addr); + return UUID(); + } + + // In here, I should check is_kernel for memory_module_sp + // However, the ReadModuleFromMemory reads wrong section so that this check + // will failed + ArchSpec kernel_arch(llvm::ELF::convertEMachineToArchName(header.e_machine)); + + if (!process->GetTarget().GetArchitecture().IsCompatibleMatch(kernel_arch)) + process->GetTarget().SetArchitecture(kernel_arch); + + std::string uuid_str; + if (memory_module_sp->GetUUID().IsValid()) { + uuid_str = "with UUID "; + uuid_str += memory_module_sp->GetUUID().GetAsString(); + } else { + uuid_str = "and no LC_UUID found in load commands "; + } + LLDB_LOGF(log, + "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress: " + "kernel binary image found at 0x%" PRIx64 " with arch '%s' %s", + addr, kernel_arch.GetTriple().str().c_str(), uuid_str.c_str()); + + return memory_module_sp->GetUUID(); +} + +void DynamicLoaderFreeBSDKernel::DebuggerInit( + lldb_private::Debugger &debugger) {} + +DynamicLoaderFreeBSDKernel::DynamicLoaderFreeBSDKernel(Process *process, + addr_t kernel_address) + : DynamicLoader(process), m_process(process), + m_linker_file_list_struct_addr(LLDB_INVALID_ADDRESS), + m_linker_file_head_addr(LLDB_INVALID_ADDRESS), + m_kernel_load_address(kernel_address), m_mutex() { + process->SetCanRunCode(false); +} + +DynamicLoaderFreeBSDKernel::~DynamicLoaderFreeBSDKernel() { Clear(true); } + +void DynamicLoaderFreeBSDKernel::Update() { + LoadKernelModules(); + SetNotificationBreakPoint(); +} + +// Create in memory Module at the load address +bool DynamicLoaderFreeBSDKernel::KModImageInfo::ReadMemoryModule( + lldb_private::Process *process) { + Log *log = GetLog(LLDBLog::DynamicLoader); + if (m_memory_module_sp) + return true; + if (m_load_address == LLDB_INVALID_ADDRESS) + return false; + + FileSpec file_spec(m_name); + + ModuleSP memory_module_sp; + + llvm::ELF::Elf32_Ehdr elf_eheader; + size_t size_to_read = 512; + + if (ReadELFHeader(process, m_load_address, elf_eheader)) { + if (elf_eheader.e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32) { + size_to_read = sizeof(llvm::ELF::Elf32_Ehdr) + + elf_eheader.e_phnum * elf_eheader.e_phentsize; + } else if (elf_eheader.e_ident[llvm::ELF::EI_CLASS] == + llvm::ELF::ELFCLASS64) { + llvm::ELF::Elf64_Ehdr elf_eheader; + Status error; + if (process->ReadMemory(m_load_address, &elf_eheader, sizeof(elf_eheader), + error) == sizeof(elf_eheader)) + size_to_read = sizeof(llvm::ELF::Elf64_Ehdr) + + elf_eheader.e_phnum * elf_eheader.e_phentsize; + } + } + + memory_module_sp = + process->ReadModuleFromMemory(file_spec, m_load_address, size_to_read); + + if (!memory_module_sp) + return false; + + bool this_is_kernel = is_kernel(memory_module_sp.get()); + + if (!m_uuid.IsValid() && memory_module_sp->GetUUID().IsValid()) + m_uuid = memory_module_sp->GetUUID(); + + m_memory_module_sp = memory_module_sp; + m_is_kernel = this_is_kernel; + + // The kernel binary is from memory + if (this_is_kernel) { + LLDB_LOGF(log, "KextImageInfo::ReadMemoryModule read the kernel binary out " + "of memory"); + + if (memory_module_sp->GetArchitecture().IsValid()) + process->GetTarget().SetArchitecture(memory_module_sp->GetArchitecture()); + } + + return true; +} + +bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule( + lldb_private::Process *process) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (IsLoaded()) + return true; + + Target &target = process->GetTarget(); + + if (IsKernel() && m_uuid.IsValid()) { + Stream &s = target.GetDebugger().GetOutputStream(); + s.Printf("Kernel UUID: %s\n", m_uuid.GetAsString().c_str()); + s.Printf("Load Address: 0x%" PRIx64 "\n", m_load_address); + } + + // Test if the module is loaded into the taget, + // maybe the module is loaded manually by user by doing target module add + // So that we have to create the module manually + if (!m_module_sp) { + const ModuleList &target_images = target.GetImages(); + m_module_sp = target_images.FindModule(m_uuid); + + // Search in the file system + if (!m_module_sp) { + ModuleSpec module_spec(FileSpec(GetPath()), target.GetArchitecture()); + if (IsKernel()) { + Status error; + if (PluginManager::DownloadObjectAndSymbolFile(module_spec, error, + true)) { + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) + m_module_sp = std::make_shared<Module>(module_spec.GetFileSpec(), + target.GetArchitecture()); + } + } + + if (!m_module_sp) + m_module_sp = target.GetOrCreateModule(module_spec, true); + if (IsKernel() && !m_module_sp) { + Stream &s = target.GetDebugger().GetOutputStream(); + s.Printf("WARNING: Unable to locate kernel binary on the debugger " + "system.\n"); + } + } + + if (m_module_sp) { + // If the file is not kernel or kmod, the target should be loaded once and + // don't reload again + if (!IsKernel() && !is_kmod(m_module_sp.get())) { + ModuleSP existing_module_sp = target.GetImages().FindModule(m_uuid); + if (existing_module_sp && + existing_module_sp->IsLoadedInTarget(&target)) { + LLDB_LOGF(log, + "'%s' with UUID %s is not a kmod or kernel, and is " + "already registered in target, not loading.", + m_name.c_str(), m_uuid.GetAsString().c_str()); + return true; + } + } + m_uuid = m_module_sp->GetUUID(); + + // or append to the images + target.GetImages().AppendIfNeeded(m_module_sp, false); + } + } + + // If this file is relocatable kernel module(x86_64), adjust it's + // section(PT_LOAD segment) and return Because the kernel module's load + // address is the text section. lldb cannot create full memory module upon + // relocatable file So what we do is to set the load address only. + if (is_kmod(m_module_sp.get()) && is_reloc(m_module_sp.get())) { + m_stop_id = process->GetStopID(); + bool changed = false; + m_module_sp->SetLoadAddress(target, m_load_address, true, changed); + return true; + } + + if (m_module_sp) + ReadMemoryModule(process); + + // Calculate the slides of in memory module + if (!m_memory_module_sp || !m_module_sp) { + m_module_sp.reset(); + return false; + } + + ObjectFile *ondisk_object_file = m_module_sp->GetObjectFile(); + ObjectFile *memory_object_file = m_memory_module_sp->GetObjectFile(); + + if (!ondisk_object_file || !memory_object_file) + m_module_sp.reset(); + + // Find the slide address + addr_t fixed_slide = LLDB_INVALID_ADDRESS; + if (ObjectFileELF *memory_objfile_elf = + llvm::dyn_cast<ObjectFileELF>(memory_object_file)) { + addr_t load_address = memory_object_file->GetBaseAddress().GetFileAddress(); + + if (load_address != LLDB_INVALID_ADDRESS && + m_load_address != load_address) { + fixed_slide = m_load_address - load_address; + LLDB_LOGF(log, + "kmod %s in-memory LOAD vmaddr is not correct, using a " + "fixed slide of 0x%" PRIx64, + m_name.c_str(), fixed_slide); + } + } + + SectionList *ondisk_section_list = ondisk_object_file->GetSectionList(); + SectionList *memory_section_list = memory_object_file->GetSectionList(); + + if (memory_section_list && ondisk_object_file) { + const uint32_t num_ondisk_sections = ondisk_section_list->GetSize(); + uint32_t num_load_sections = 0; + + for (uint32_t section_idx = 0; section_idx < num_ondisk_sections; + ++section_idx) { + SectionSP on_disk_section_sp = + ondisk_section_list->GetSectionAtIndex(section_idx); + + if (!on_disk_section_sp) + continue; + if (fixed_slide != LLDB_INVALID_ADDRESS) { + target.SetSectionLoadAddress(on_disk_section_sp, + on_disk_section_sp->GetFileAddress() + + fixed_slide); + + } else { + const Section *memory_section = + memory_section_list + ->FindSectionByName(on_disk_section_sp->GetName()) + .get(); + if (memory_section) { + target.SetSectionLoadAddress(on_disk_section_sp, + memory_section->GetFileAddress()); + ++num_load_sections; + } + } + } + + if (num_load_sections) + m_stop_id = process->GetStopID(); + else + m_module_sp.reset(); + } else { + m_module_sp.reset(); + } + + if (IsLoaded() && m_module_sp && IsKernel()) { + Stream &s = target.GetDebugger().GetOutputStream(); + ObjectFile *kernel_object_file = m_module_sp->GetObjectFile(); + if (kernel_object_file) { + addr_t file_address = + kernel_object_file->GetBaseAddress().GetFileAddress(); + if (m_load_address != LLDB_INVALID_ADDRESS && + file_address != LLDB_INVALID_ADDRESS) { + s.Printf("Kernel slide 0x%" PRIx64 " in memory.\n", + m_load_address - file_address); + s.Printf("Loaded kernel file %s\n", + m_module_sp->GetFileSpec().GetPath().c_str()); + } + } + s.Flush(); + } + + return IsLoaded(); +} + +// This function is work for kernel file, others it wil reset load address and +// return false +bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingFileAddress( + lldb_private::Process *process) { + if (IsLoaded()) + return true; + + if (m_module_sp) { + bool changed = false; + if (m_module_sp->SetLoadAddress(process->GetTarget(), 0, true, changed)) + m_stop_id = process->GetStopID(); + } + + return false; +} + +// Get the head of found_list +bool DynamicLoaderFreeBSDKernel::ReadKmodsListHeader() { + std::lock_guard<decltype(m_mutex)> guard(m_mutex); + + if (m_linker_file_list_struct_addr.IsValid()) { + // Get tqh_first struct element from linker_files + Status error; + addr_t address = m_process->ReadPointerFromMemory( + m_linker_file_list_struct_addr.GetLoadAddress(&m_process->GetTarget()), + error); + if (address != LLDB_INVALID_ADDRESS && error.Success()) { + m_linker_file_head_addr = Address(address); + } else { + m_linker_file_list_struct_addr.Clear(); + return false; + } + + if (!m_linker_file_head_addr.IsValid() || + m_linker_file_head_addr.GetFileAddress() == 0) { + m_linker_file_list_struct_addr.Clear(); + return false; + } + } + return true; +} + +// Parse Kmod info in found_list +bool DynamicLoaderFreeBSDKernel::ParseKmods(Address linker_files_head_addr) { + std::lock_guard<decltype(m_mutex)> guard(m_mutex); + KModImageInfo::collection_type linker_files_list; + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (!ReadAllKmods(linker_files_head_addr, linker_files_list)) + return false; + LLDB_LOGF( + log, + "Kmod-changed breakpoint hit, there are %zu kernel modules currently.\n", + linker_files_list.size()); + + ModuleList &modules = m_process->GetTarget().GetImages(); + ModuleList remove_modules; + ModuleList add_modules; + + for (ModuleSP module : modules.Modules()) { + if (is_kernel(module.get())) + continue; + if (is_kmod(module.get())) + remove_modules.AppendIfNeeded(module); + } + + m_process->GetTarget().ModulesDidUnload(remove_modules, false); + + for (KModImageInfo &image_info : linker_files_list) { + if (m_kld_name_to_uuid.find(image_info.GetName()) != + m_kld_name_to_uuid.end()) + image_info.SetUUID(m_kld_name_to_uuid[image_info.GetName()]); + bool failed_to_load = false; + if (!image_info.LoadImageUsingMemoryModule(m_process)) { + image_info.LoadImageUsingFileAddress(m_process); + failed_to_load = true; + } else { + m_linker_files_list.push_back(image_info); + m_kld_name_to_uuid[image_info.GetName()] = image_info.GetUUID(); + } + + if (!failed_to_load) + add_modules.AppendIfNeeded(image_info.GetModule()); + } + m_process->GetTarget().ModulesDidLoad(add_modules); + return true; +} + +// Read all kmod from a given arrays of list +bool DynamicLoaderFreeBSDKernel::ReadAllKmods( + Address linker_files_head_addr, + KModImageInfo::collection_type &kmods_list) { + + // Get offset of next member and load address symbol + static ConstString kld_off_address_symbol_name("kld_off_address"); + static ConstString kld_off_next_symbol_name("kld_off_next"); + static ConstString kld_off_filename_symbol_name("kld_off_filename"); + static ConstString kld_off_pathname_symbol_name("kld_off_pathname"); + const Symbol *kld_off_address_symbol = + m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( + kld_off_address_symbol_name, eSymbolTypeData); + const Symbol *kld_off_next_symbol = + m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( + kld_off_next_symbol_name, eSymbolTypeData); + const Symbol *kld_off_filename_symbol = + m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( + kld_off_filename_symbol_name, eSymbolTypeData); + const Symbol *kld_off_pathname_symbol = + m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( + kld_off_pathname_symbol_name, eSymbolTypeData); + + if (!kld_off_address_symbol || !kld_off_next_symbol || + !kld_off_filename_symbol || !kld_off_pathname_symbol) + return false; + + Status error; + const int32_t kld_off_address = m_process->ReadSignedIntegerFromMemory( + kld_off_address_symbol->GetAddress().GetLoadAddress( + &m_process->GetTarget()), + 4, 0, error); + if (error.Fail()) + return false; + const int32_t kld_off_next = m_process->ReadSignedIntegerFromMemory( + kld_off_next_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget()), + 4, 0, error); + if (error.Fail()) + return false; + const int32_t kld_off_filename = m_process->ReadSignedIntegerFromMemory( + kld_off_filename_symbol->GetAddress().GetLoadAddress( + &m_process->GetTarget()), + 4, 0, error); + if (error.Fail()) + return false; + + const int32_t kld_off_pathname = m_process->ReadSignedIntegerFromMemory( + kld_off_pathname_symbol->GetAddress().GetLoadAddress( + &m_process->GetTarget()), + 4, 0, error); + if (error.Fail()) + return false; + + // Parse KMods + addr_t kld_load_addr(LLDB_INVALID_ADDRESS); + char kld_filename[255]; + char kld_pathname[255]; + addr_t current_kld = + linker_files_head_addr.GetLoadAddress(&m_process->GetTarget()); + + while (current_kld != 0) { + addr_t kld_filename_addr = + m_process->ReadPointerFromMemory(current_kld + kld_off_filename, error); + if (error.Fail()) + return false; + addr_t kld_pathname_addr = + m_process->ReadPointerFromMemory(current_kld + kld_off_pathname, error); + if (error.Fail()) + return false; + + m_process->ReadCStringFromMemory(kld_filename_addr, kld_filename, + sizeof(kld_filename), error); + if (error.Fail()) + return false; + m_process->ReadCStringFromMemory(kld_pathname_addr, kld_pathname, + sizeof(kld_pathname), error); + if (error.Fail()) + return false; + kld_load_addr = + m_process->ReadPointerFromMemory(current_kld + kld_off_address, error); + if (error.Fail()) + return false; + + kmods_list.emplace_back(); + KModImageInfo &kmod_info = kmods_list.back(); + kmod_info.SetName(kld_filename); + kmod_info.SetLoadAddress(kld_load_addr); + kmod_info.SetPath(kld_pathname); + + current_kld = + m_process->ReadPointerFromMemory(current_kld + kld_off_next, error); + if (kmod_info.GetName() == "kernel") + kmods_list.pop_back(); + if (error.Fail()) + return false; + } + + return true; +} + +// Read all kmods +void DynamicLoaderFreeBSDKernel::ReadAllKmods() { + std::lock_guard<decltype(m_mutex)> guard(m_mutex); + + if (ReadKmodsListHeader()) { + if (m_linker_file_head_addr.IsValid()) { + if (!ParseKmods(m_linker_file_head_addr)) + m_linker_files_list.clear(); + } + } +} + +// Load all Kernel Modules +void DynamicLoaderFreeBSDKernel::LoadKernelModules() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules " + "Start loading Kernel Module"); + + // Initialize Kernel Image Information at the first time + if (m_kernel_image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS) { + ModuleSP module_sp = m_process->GetTarget().GetExecutableModule(); + if (is_kernel(module_sp.get())) { + m_kernel_image_info.SetModule(module_sp); + m_kernel_image_info.SetIsKernel(true); + } + + // Set name for kernel + llvm::StringRef kernel_name("freebsd_kernel"); + module_sp = m_kernel_image_info.GetModule(); + if (module_sp.get() && module_sp->GetObjectFile() && + !module_sp->GetObjectFile()->GetFileSpec().GetFilename().IsEmpty()) + kernel_name = module_sp->GetObjectFile() + ->GetFileSpec() + .GetFilename() + .GetStringRef(); + m_kernel_image_info.SetName(kernel_name.data()); + + if (m_kernel_image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS) { + m_kernel_image_info.SetLoadAddress(m_kernel_load_address); + } + + // Build In memory Module + if (m_kernel_image_info.GetLoadAddress() != LLDB_INVALID_ADDRESS) { + // If the kernel is not loaded in the memory, use file to load + if (!m_kernel_image_info.LoadImageUsingMemoryModule(m_process)) + m_kernel_image_info.LoadImageUsingFileAddress(m_process); + } + } + + LoadOperatingSystemPlugin(false); + + if (!m_kernel_image_info.IsLoaded() || !m_kernel_image_info.GetModule()) { + m_kernel_image_info.Clear(); + return; + } + + static ConstString modlist_symbol_name("linker_files"); + + const Symbol *symbol = + m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( + modlist_symbol_name, lldb::eSymbolTypeData); + + if (symbol) { + m_linker_file_list_struct_addr = symbol->GetAddress(); + ReadAllKmods(); + } else { + LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules " + "cannot file modlist symbol"); + } +} + +// Update symbol when use kldload by setting callback function on kldload +void DynamicLoaderFreeBSDKernel::SetNotificationBreakPoint() {} + +// Hook called when attach to a process +void DynamicLoaderFreeBSDKernel::DidAttach() { + PrivateInitialize(m_process); + Update(); +} + +// Hook called after attach to a process +void DynamicLoaderFreeBSDKernel::DidLaunch() { + PrivateInitialize(m_process); + Update(); +} + +// Clear all member except kernel address +void DynamicLoaderFreeBSDKernel::Clear(bool clear_process) { + std::lock_guard<decltype(m_mutex)> guard(m_mutex); + if (clear_process) + m_process = nullptr; + m_linker_file_head_addr.Clear(); + m_linker_file_list_struct_addr.Clear(); + m_kernel_image_info.Clear(); + m_linker_files_list.clear(); +} + +// Reinitialize class +void DynamicLoaderFreeBSDKernel::PrivateInitialize(Process *process) { + Clear(true); + m_process = process; +} + +ThreadPlanSP DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan( + lldb_private::Thread &thread, bool stop_others) { + Log *log = GetLog(LLDBLog::Step); + LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan is " + "not yet implemented."); + return {}; +} + +Status DynamicLoaderFreeBSDKernel::CanLoadImage() { + Status error("shared object cannot be loaded into kernel"); + return error; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h new file mode 100644 index 000000000000..d8656e9c49df --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h @@ -0,0 +1,171 @@ +//===-- DynamicLoaderFreeBSDKernel.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_DYNAMICLOADER_FREEBSD_KERNEL_DYNAMICLOADERFREEBSDKERNEL_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_FREEBSD_KERNEL_DYNAMICLOADERFREEBSDKERNEL_H + +#include <mutex> +#include <string> +#include <vector> + +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "llvm/BinaryFormat/ELF.h" + +class DynamicLoaderFreeBSDKernel : public lldb_private::DynamicLoader { +public: + DynamicLoaderFreeBSDKernel(lldb_private::Process *process, + lldb::addr_t kernel_addr); + + ~DynamicLoaderFreeBSDKernel() override; + + // Static Functions + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "freebsd-kernel"; } + + static llvm::StringRef GetPluginDescriptionStatic(); + + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); + + static void DebuggerInit(lldb_private::Debugger &debugger); + + static lldb::addr_t FindFreeBSDKernel(lldb_private::Process *process); + + // Hooks for time point that after attach to some proccess + void DidAttach() override; + + void DidLaunch() override; + + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others) override; + + lldb_private::Status CanLoadImage() override; + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +protected: + class KModImageInfo { + public: + KModImageInfo() + : m_module_sp(), m_memory_module_sp(), m_uuid(), m_name(), m_path() {} + + void Clear() { + m_load_address = LLDB_INVALID_ADDRESS; + m_name.clear(); + m_uuid.Clear(); + m_module_sp.reset(); + m_memory_module_sp.reset(); + m_stop_id = UINT32_MAX; + m_path.clear(); + } + + void SetLoadAddress(lldb::addr_t load_address) { + m_load_address = load_address; + } + + lldb::addr_t GetLoadAddress() const { return m_load_address; } + + void SetUUID(const lldb_private::UUID uuid) { m_uuid = uuid; } + + lldb_private::UUID GetUUID() const { return m_uuid; } + + void SetName(const char *name) { m_name = name; } + + std::string GetName() const { return m_name; } + + void SetPath(const char *path) { m_path = path; } + + std::string GetPath() const { return m_path; } + + void SetModule(lldb::ModuleSP module) { m_module_sp = module; } + + lldb::ModuleSP GetModule() { return m_module_sp; } + + void SetIsKernel(bool is_kernel) { m_is_kernel = is_kernel; } + + bool IsKernel() const { return m_is_kernel; }; + + void SetStopID(uint32_t stop_id) { m_stop_id = stop_id; } + + uint32_t GetStopID() { return m_stop_id; } + + bool IsLoaded() const { return m_stop_id != UINT32_MAX; }; + + bool ReadMemoryModule(lldb_private::Process *process); + + bool LoadImageUsingMemoryModule(lldb_private::Process *process); + + bool LoadImageUsingFileAddress(lldb_private::Process *process); + + using collection_type = std::vector<KModImageInfo>; + + private: + lldb::ModuleSP m_module_sp; + lldb::ModuleSP m_memory_module_sp; + lldb::addr_t m_load_address = LLDB_INVALID_ADDRESS; + lldb_private::UUID m_uuid; + bool m_is_kernel = false; + std::string m_name; + std::string m_path; + uint32_t m_stop_id = UINT32_MAX; + }; + + void PrivateInitialize(lldb_private::Process *process); + + void Clear(bool clear_process); + + void Update(); + + void LoadKernelModules(); + + void ReadAllKmods(); + + bool ReadAllKmods(lldb_private::Address linker_files_head_address, + KModImageInfo::collection_type &kmods_list); + + bool ReadKmodsListHeader(); + + bool ParseKmods(lldb_private::Address linker_files_head_address); + + void SetNotificationBreakPoint(); + + static lldb_private::UUID + CheckForKernelImageAtAddress(lldb_private::Process *process, + lldb::addr_t address, + bool *read_error = nullptr); + + static lldb::addr_t FindKernelAtLoadAddress(lldb_private::Process *process); + + static bool ReadELFHeader(lldb_private::Process *process, + lldb::addr_t address, llvm::ELF::Elf32_Ehdr &header, + bool *read_error = nullptr); + + lldb_private::Process *m_process; + lldb_private::Address m_linker_file_list_struct_addr; + lldb_private::Address m_linker_file_head_addr; + lldb::addr_t m_kernel_load_address; + KModImageInfo m_kernel_image_info; + KModImageInfo::collection_type m_linker_files_list; + std::recursive_mutex m_mutex; + std::unordered_map<std::string, lldb_private::UUID> m_kld_name_to_uuid; + +private: + DynamicLoaderFreeBSDKernel(const DynamicLoaderFreeBSDKernel &) = delete; + + const DynamicLoaderFreeBSDKernel & + operator=(const DynamicLoaderFreeBSDKernel &) = delete; +}; + +#endif 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 f20167b46d27..1a9c4593b1b4 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 @@ -25,6 +25,32 @@ using namespace lldb; using namespace lldb_private; +const char *DYLDRendezvous::StateToCStr(RendezvousState state) { + switch (state) { + case DYLDRendezvous::eConsistent: + return "eConsistent"; + case DYLDRendezvous::eAdd: + return "eAdd"; + case DYLDRendezvous::eDelete: + return "eDelete"; + } + return "<invalid RendezvousState>"; +} + +const char *DYLDRendezvous::ActionToCStr(RendezvousAction action) { + switch (action) { + case DYLDRendezvous::RendezvousAction::eTakeSnapshot: + return "eTakeSnapshot"; + case DYLDRendezvous::RendezvousAction::eAddModules: + return "eAddModules"; + case DYLDRendezvous::RendezvousAction::eRemoveModules: + return "eRemoveModules"; + case DYLDRendezvous::RendezvousAction::eNoAction: + return "eNoAction"; + } + return "<invalid RendezvousAction>"; +} + DYLDRendezvous::DYLDRendezvous(Process *process) : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_executable_interpreter(false), m_current(), m_previous(), @@ -129,6 +155,13 @@ void DYLDRendezvous::UpdateExecutablePath() { } } +void DYLDRendezvous::Rendezvous::DumpToLog(Log *log, const char *label) { + LLDB_LOGF(log, "%s Rendezvous: version = %" PRIu64 ", map_addr = 0x%16.16" + PRIx64 ", brk = 0x%16.16" PRIx64 ", state = %" PRIu64 + " (%s), ldbase = 0x%16.16" PRIx64, label ? label : "", version, + map_addr, brk, state, StateToCStr((RendezvousState)state), ldbase); +} + bool DYLDRendezvous::Resolve() { Log *log = GetLog(LLDBLog::DynamicLoader); @@ -176,6 +209,9 @@ bool DYLDRendezvous::Resolve() { m_previous = m_current; m_current = info; + m_previous.DumpToLog(log, "m_previous"); + m_current.DumpToLog(log, "m_current "); + if (m_current.map_addr == 0) return false; @@ -217,6 +253,75 @@ DYLDRendezvous::RendezvousAction DYLDRendezvous::GetAction() const { break; case eAdd: + // If the main executable or a shared library defines a publicly visible + // symbol named "_r_debug", then it will cause problems once the executable + // that contains the symbol is loaded into the process. The correct + // "_r_debug" structure is currently found by LLDB by looking through + // the .dynamic section in the main executable and finding the DT_DEBUG tag + // entry. + // + // An issue comes up if someone defines another publicly visible "_r_debug" + // struct in their program. Sample code looks like: + // + // #include <link.h> + // r_debug _r_debug; + // + // If code like this is in an executable or shared library, this creates a + // new "_r_debug" structure and it causes problems once the executable is + // loaded due to the way symbol lookups happen in linux: the shared library + // list from _r_debug.r_map will be searched for a symbol named "_r_debug" + // and the first match will be the new version that is used. The dynamic + // loader is always last in this list. So at some point the dynamic loader + // will start updating the copy of "_r_debug" that gets found first. The + // issue is that LLDB will only look at the copy that is pointed to by the + // DT_DEBUG entry, or the initial version from the ld.so binary. + // + // Steps that show the problem are: + // + // - LLDB finds the "_r_debug" structure via the DT_DEBUG entry in the + // .dynamic section and this points to the "_r_debug" in ld.so + // - ld.so uodates its copy of "_r_debug" with "state = eAdd" before it + // loads the dependent shared libraries for the main executable and + // any dependencies of all shared libraries from the executable's list + // and ld.so code calls the debugger notification function + // that LLDB has set a breakpoint on. + // - LLDB hits the breakpoint and the breakpoint has a callback function + // where we read the _r_debug.state (eAdd) state and we do nothing as the + // "eAdd" state indicates that the shared libraries are about to be added. + // - ld.so finishes loading the main executable and any dependent shared + // libraries and it will update the "_r_debug.state" member with a + // "eConsistent", but it now updates the "_r_debug" in the a.out program + // and it calls the debugger notification function. + // - lldb hits the notification breakpoint and checks the ld.so copy of + // "_r_debug.state" which still has a state of "eAdd", but LLDB needs to see a + // "eConsistent" state to trigger the shared libraries to get loaded into + // the debug session, but LLDB the ld.so _r_debug.state which still + // contains "eAdd" and doesn't do anyhing and library load is missed. + // The "_r_debug" in a.out has the state set correctly to "eConsistent" + // but LLDB is still looking at the "_r_debug" from ld.so. + // + // So if we detect two "eAdd" states in a row, we assume this is the issue + // and we now load shared libraries correctly and will emit a log message + // in the "log enable lldb dyld" log channel which states there might be + // multiple "_r_debug" structs causing problems. + // + // The correct solution is that no one should be adding a duplicate + // publicly visible "_r_debug" symbols to their binaries, but we have + // programs that are doing this already and since it can be done, we should + // be able to work with this and keep debug sessions working as expected. + // + // If a user includes the <link.h> file, they can just use the existing + // "_r_debug" structure as it is defined in this header file as "extern + // struct r_debug _r_debug;" and no local copies need to be made. + if (m_previous.state == eAdd) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "DYLDRendezvous::GetAction() found two eAdd states in a " + "row, check process for multiple \"_r_debug\" symbols. " + "Returning eAddModules to ensure shared libraries get loaded " + "correctly"); + return eAddModules; + } + return eNoAction; case eDelete: return eNoAction; } @@ -225,7 +330,9 @@ DYLDRendezvous::RendezvousAction DYLDRendezvous::GetAction() const { } bool DYLDRendezvous::UpdateSOEntriesFromRemote() { - auto action = GetAction(); + const auto action = GetAction(); + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "{0} action = {1}", LLVM_PRETTY_FUNCTION, ActionToCStr(action)); if (action == eNoAction) return false; @@ -263,7 +370,10 @@ bool DYLDRendezvous::UpdateSOEntriesFromRemote() { bool DYLDRendezvous::UpdateSOEntries() { m_added_soentries.clear(); m_removed_soentries.clear(); - switch (GetAction()) { + const auto action = GetAction(); + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "{0} action = {1}", LLVM_PRETTY_FUNCTION, ActionToCStr(action)); + switch (action) { case eTakeSnapshot: m_soentries.clear(); return TakeSnapshot(m_soentries); @@ -372,7 +482,7 @@ bool DYLDRendezvous::RemoveSOEntriesFromRemote( // Only add shared libraries and not the executable. if (!SOEntryIsMainExecutable(entry)) { - auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + auto pos = llvm::find(m_soentries, entry); if (pos == m_soentries.end()) return false; @@ -439,6 +549,7 @@ bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) { switch (triple.getOS()) { case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: + case llvm::Triple::OpenBSD: return entry.file_spec == m_exe_file_spec; case llvm::Triple::Linux: if (triple.isAndroid()) @@ -600,16 +711,19 @@ bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field, target.GetImages().FindSymbolsWithNameAndType(ConstString(name), eSymbolTypeAny, list); if (list.IsEmpty()) - return false; + return false; Address address = list[0].symbol->GetAddress(); - addr_t addr = address.GetLoadAddress(&target); - if (addr == LLDB_INVALID_ADDRESS) - return false; + address.SetOffset(address.GetOffset() + field * sizeof(uint32_t)); + // Read from target memory as this allows us to try process memory and + // fallback to reading from read only sections from the object files. Here we + // are reading read only data from libpthread.so to find data in the thread + // specific area for the data we want and this won't be saved into process + // memory due to it being read only. Status error; - value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory( - addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error); + value = + target.ReadUnsignedIntegerFromMemory(address, sizeof(uint32_t), 0, error); if (error.Fail()) return false; 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 fc1dd6921455..b8bdf78fbdfa 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 @@ -21,6 +21,7 @@ using lldb_private::LoadedModuleInfoList; namespace lldb_private { +class Log; class Process; } @@ -28,9 +29,81 @@ class Process; /// Interface to the runtime linker. /// /// A structure is present in a processes memory space which is updated by the -/// runtime liker each time a module is loaded or unloaded. This class +/// dynamic linker each time a module is loaded or unloaded. This class /// provides an interface to this structure and maintains a consistent /// snapshot of the currently loaded modules. +/// +/// In the dynamic loader sources, this structure has a type of "r_debug" and +/// the name of the structure us "_r_debug". The structure looks like: +/// +/// struct r_debug { +/// // Version number for this protocol. +/// int r_version; +/// // Head of the chain of loaded objects. +/// struct link_map *r_map; +/// // The address the debugger should set a breakpoint at in order to get +/// // notified when shared libraries are added or removed +/// uintptr_t r_brk; +/// // This state value describes the mapping change taking place when the +/// // 'r_brk' address is called. +/// enum { +/// RT_CONSISTENT, // Mapping change is complete. +/// RT_ADD, // Beginning to add a new object. +/// RT_DELETE, // Beginning to remove an object mapping. +/// } r_state; +/// // Base address the linker is loaded at. +/// uintptr_t r_ldbase; +/// }; +/// +/// The dynamic linker then defines a global variable using this type named +/// "_r_debug": +/// +/// r_debug _r_debug; +/// +/// The DYLDRendezvous class defines a local version of this structure named +/// DYLDRendezvous::Rendezvous. See the definition inside the class definition +/// for DYLDRendezvous. +/// +/// This structure can be located by looking through the .dynamic section in +/// the main executable and finding the DT_DEBUG tag entry. This value starts +/// out with a value of zero when the program first is initially loaded, but +/// the address of the "_r_debug" structure from ld.so is filled in by the +/// dynamic loader during program initialization code in ld.so prior to loading +/// or unloading and shared libraries. +/// +/// The dynamic loader will update this structure as shared libraries are +/// loaded and will call a specific function that LLDB knows to set a +/// breakpoint on (from _r_debug.r_brk) so LLDB will find out when shared +/// libraries are loaded or unloaded. Each time this breakpoint is hit, LLDB +/// looks at the contents of this structure and the contents tell LLDB what +/// needs to be done. +/// +/// Currently we expect the "state" in this structure to change as things +/// happen. +/// +/// When any shared libraries are loaded the following happens: +/// - _r_debug.r_map is updated with the new shared libraries. This is a +/// doubly linked list of "link_map *" entries. +/// - _r_debug.r_state is set to RT_ADD and the debugger notification +/// function is called notifying the debugger that shared libraries are +/// about to be added, but are not yet ready for use. +/// - Once the the shared libraries are fully loaded, _r_debug.r_state is set +/// to RT_CONSISTENT and the debugger notification function is called again +/// notifying the debugger that shared libraries are ready for use. +/// DYLDRendezvous must remember that the previous state was RT_ADD when it +/// receives a RT_CONSISTENT in order to know to add libraries +/// +/// When any shared libraries are unloaded the following happens: +/// - _r_debug.r_map is updated and the unloaded libraries are removed. +/// - _r_debug.r_state is set to RT_DELETE and the debugger notification +/// function is called notifying the debugger that shared libraries are +/// about to be removed. +/// - Once the the shared libraries are removed _r_debug.r_state is set to +/// RT_CONSISTENT and the debugger notification function is called again +/// notifying the debugger that shared libraries have been removed. +/// DYLDRendezvous must remember that the previous state was RT_DELETE when +/// it receives a RT_CONSISTENT in order to know to remove libraries +/// class DYLDRendezvous { // This structure is used to hold the contents of the debug rendezvous @@ -45,6 +118,8 @@ class DYLDRendezvous { lldb::addr_t ldbase = 0; Rendezvous() = default; + + void DumpToLog(lldb_private::Log *log, const char *label); }; /// Locates the address of the rendezvous structure. It updates @@ -126,8 +201,15 @@ public: /// Constants describing the state of the rendezvous. /// + /// These values are defined to match the r_debug.r_state enum from the + /// actual dynamic loader sources. + /// /// \see GetState(). - enum RendezvousState { eConsistent, eAdd, eDelete }; + enum RendezvousState { + eConsistent, // RT_CONSISTENT + eAdd, // RT_ADD + eDelete // RT_DELETE + }; /// Structure representing the shared objects currently loaded into the /// inferior process. @@ -276,6 +358,9 @@ protected: eRemoveModules }; + static const char *StateToCStr(RendezvousState state); + static const char *ActionToCStr(RendezvousAction action); + /// Returns the current action to be taken given the current and previous /// state RendezvousAction GetAction() const; 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 b4b38a88e1b9..9baf86da4dc7 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 @@ -53,7 +53,8 @@ DynamicLoader *DynamicLoaderPOSIXDYLD::CreateInstance(Process *process, process->GetTarget().GetArchitecture().GetTriple(); if (triple_ref.getOS() == llvm::Triple::FreeBSD || triple_ref.getOS() == llvm::Triple::Linux || - triple_ref.getOS() == llvm::Triple::NetBSD) + triple_ref.getOS() == llvm::Triple::NetBSD || + triple_ref.getOS() == llvm::Triple::OpenBSD) create = true; } @@ -337,29 +338,20 @@ bool DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() { }; ModuleSP interpreter = LoadInterpreterModule(); - if (!interpreter) { - FileSpecList containingModules; + FileSpecList containingModules; + if (interpreter) + containingModules.Append(interpreter->GetFileSpec()); + else containingModules.Append( m_process->GetTarget().GetExecutableModulePointer()->GetFileSpec()); - dyld_break = target.CreateBreakpoint( - &containingModules, /*containingSourceFiles=*/nullptr, - DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC, - /*m_offset=*/0, - /*skip_prologue=*/eLazyBoolNo, - /*internal=*/true, - /*request_hardware=*/false); - } else { - FileSpecList containingModules; - containingModules.Append(interpreter->GetFileSpec()); - dyld_break = target.CreateBreakpoint( - &containingModules, /*containingSourceFiles=*/nullptr, - DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC, - /*m_offset=*/0, - /*skip_prologue=*/eLazyBoolNo, - /*internal=*/true, - /*request_hardware=*/false); - } + dyld_break = target.CreateBreakpoint( + &containingModules, /*containingSourceFiles=*/nullptr, + DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC, + /*m_offset=*/0, + /*skip_prologue=*/eLazyBoolNo, + /*internal=*/true, + /*request_hardware=*/false); } if (dyld_break->GetNumResolvedLocations() != 1) { @@ -420,6 +412,11 @@ void DynamicLoaderPOSIXDYLD::RefreshModules() { if (!m_rendezvous.Resolve()) return; + // The rendezvous class doesn't enumerate the main module, so track that + // ourselves here. + ModuleSP executable = GetTargetExecutable(); + m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); + DYLDRendezvous::iterator I; DYLDRendezvous::iterator E; @@ -441,6 +438,14 @@ void DynamicLoaderPOSIXDYLD::RefreshModules() { m_initial_modules_added = true; } for (; I != E; ++I) { + // Don't load a duplicate copy of ld.so if we have already loaded it + // earlier in LoadInterpreterModule. If we instead loaded then unloaded it + // later, the section information for ld.so would be removed. That + // information is required for placing breakpoints on Arm/Thumb systems. + if ((m_interpreter_module.lock() != nullptr) && + (I->base_addr == m_interpreter_base)) + continue; + ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true); if (!module_sp.get()) @@ -454,15 +459,6 @@ void DynamicLoaderPOSIXDYLD::RefreshModules() { } else if (module_sp == interpreter_sp) { // Module already loaded. continue; - } else { - // 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; } } @@ -727,41 +723,66 @@ lldb::addr_t DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr) { + Log *log = GetLog(LLDBLog::DynamicLoader); auto it = m_loaded_modules.find(module_sp); - if (it == m_loaded_modules.end()) + if (it == m_loaded_modules.end()) { + LLDB_LOGF( + log, "GetThreadLocalData error: module(%s) not found in loaded modules", + module_sp->GetObjectName().AsCString()); return LLDB_INVALID_ADDRESS; + } addr_t link_map = it->second; - if (link_map == LLDB_INVALID_ADDRESS) + if (link_map == LLDB_INVALID_ADDRESS || link_map == 0) { + LLDB_LOGF(log, + "GetThreadLocalData error: invalid link map address=0x%" PRIx64, + link_map); return LLDB_INVALID_ADDRESS; + } const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); - if (!metadata.valid) + if (!metadata.valid) { + LLDB_LOGF(log, + "GetThreadLocalData error: fail to read thread info metadata"); return LLDB_INVALID_ADDRESS; + } + + LLDB_LOGF(log, + "GetThreadLocalData info: link_map=0x%" PRIx64 + ", thread info metadata: " + "modid_offset=0x%" PRIx32 ", dtv_offset=0x%" PRIx32 + ", tls_offset=0x%" PRIx32 ", dtv_slot_size=%" PRIx32 "\n", + link_map, metadata.modid_offset, metadata.dtv_offset, + metadata.tls_offset, metadata.dtv_slot_size); // Get the thread pointer. addr_t tp = thread->GetThreadPointer(); - if (tp == LLDB_INVALID_ADDRESS) + if (tp == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, "GetThreadLocalData error: fail to read thread pointer"); return LLDB_INVALID_ADDRESS; + } // Find the module's modid. int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit int64_t modid = ReadUnsignedIntWithSizeInBytes( link_map + metadata.modid_offset, modid_size); - if (modid == -1) + if (modid == -1) { + LLDB_LOGF(log, "GetThreadLocalData error: fail to read modid"); return LLDB_INVALID_ADDRESS; + } // Lookup the DTV structure for this thread. addr_t dtv_ptr = tp + metadata.dtv_offset; addr_t dtv = ReadPointer(dtv_ptr); - if (dtv == LLDB_INVALID_ADDRESS) + if (dtv == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, "GetThreadLocalData error: fail to read dtv"); return LLDB_INVALID_ADDRESS; + } // Find the TLS block for this module. addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid; addr_t tls_block = ReadPointer(dtv_slot + metadata.tls_offset); - Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::Performed TLS lookup: " "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 @@ -769,9 +790,10 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp, module_sp->GetObjectName().AsCString(""), link_map, tp, (int64_t)modid, tls_block); - if (tls_block == LLDB_INVALID_ADDRESS) + if (tls_block == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, "GetThreadLocalData error: fail to read tls_block"); return LLDB_INVALID_ADDRESS; - else + } else return tls_block + tls_file_addr; } 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 2826b102625f..5d109feb3d39 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -902,7 +902,6 @@ void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( // We want that 'to' is actually complete after this function so let's // tell the ASTImporter that 'to' was imported from 'from'. MapImported(from, to); - ASTImporter::Imported(from, to); Log *log = GetLog(LLDBLog::Expressions); @@ -1028,7 +1027,7 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, // Some decls shouldn't be tracked here because they were not created by // copying 'from' to 'to'. Just exit early for those. if (m_decls_to_ignore.count(to)) - return clang::ASTImporter::Imported(from, to); + return; // Transfer module ownership information. auto *from_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>( @@ -1081,12 +1080,6 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) to_context_md->setOrigin(to, origin); - ImporterDelegateSP direct_completer = - m_main.GetDelegate(&to->getASTContext(), origin.ctx); - - if (direct_completer.get() != this) - direct_completer->ASTImporter::Imported(origin.decl, to); - LLDB_LOG(log, " [ClangASTImporter] Propagated origin " "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to " 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 5d7e1252038d..79dd306f7627 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -201,19 +201,17 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) { LLDB_LOG(log, " CTD Searching namespace {0} in module {1}", item.second.GetName(), item.first->GetFileSpec().GetFilename()); - TypeList types; - ConstString name(decl->getName()); - item.first->FindTypesInNamespace(name, item.second, UINT32_MAX, types); - - for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) { - lldb::TypeSP type = types.GetTypeAtIndex(ti); - - if (!type) - continue; + // Create a type matcher using the CompilerDeclContext for the namespace + // as the context (item.second) and search for the name inside of this + // context. + TypeQuery query(item.second, name); + TypeResults results; + item.first->FindTypes(query, results); - CompilerType clang_type(type->GetFullCompilerType()); + for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types()) { + CompilerType clang_type(type_sp->GetFullCompilerType()); if (!ClangUtil::IsClangType(clang_type)) continue; @@ -233,24 +231,15 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) { } } } else { - TypeList types; - - ConstString name(decl->getName()); - const ModuleList &module_list = m_target->GetImages(); + // Create a type matcher using a CompilerDecl. Each TypeSystem class knows + // how to fill out a CompilerContext array using a CompilerDecl. + TypeQuery query(CompilerDecl(m_clang_ast_context, (void *)decl)); + TypeResults results; + module_list.FindTypes(nullptr, query, results); + for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types()) { - bool exact_match = false; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, - searched_symbol_files, types); - - for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) { - lldb::TypeSP type = types.GetTypeAtIndex(ti); - - if (!type) - continue; - - CompilerType clang_type(type->GetFullCompilerType()); + CompilerType clang_type(type_sp->GetFullCompilerType()); if (!ClangUtil::IsClangType(clang_type)) continue; @@ -263,13 +252,6 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) { TagDecl *candidate_tag_decl = const_cast<TagDecl *>(tag_type->getDecl()); - // We have found a type by basename and we need to make sure the decl - // contexts are the same before we can try to complete this type with - // another - if (!TypeSystemClang::DeclsAreEquivalent(const_cast<TagDecl *>(decl), - candidate_tag_decl)) - continue; - if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(), candidate_tag_decl)) return candidate_tag_decl; @@ -589,8 +571,8 @@ bool ClangASTSource::IgnoreName(const ConstString name, // The ClangASTSource is not responsible for finding $-names. return name_string_ref.empty() || - (ignore_all_dollar_names && name_string_ref.startswith("$")) || - name_string_ref.startswith("_$"); + (ignore_all_dollar_names && name_string_ref.starts_with("$")) || + name_string_ref.starts_with("_$"); } void ClangASTSource::FindExternalVisibleDecls( @@ -614,41 +596,40 @@ void ClangASTSource::FindExternalVisibleDecls( if (context.m_found_type) return; - TypeList types; - const bool exact_match = true; - llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; - if (module_sp && namespace_decl) - module_sp->FindTypesInNamespace(name, namespace_decl, 1, types); - else { - m_target->GetImages().FindTypes(module_sp.get(), name, exact_match, 1, - searched_symbol_files, types); + lldb::TypeSP type_sp; + TypeResults results; + if (module_sp && namespace_decl) { + // Match the name in the specified decl context. + TypeQuery query(namespace_decl, name, TypeQueryOptions::e_find_one); + module_sp->FindTypes(query, results); + type_sp = results.GetFirstType(); + } else { + // Match the exact name of the type at the root level. + TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_exact_match | + TypeQueryOptions::e_find_one); + m_target->GetImages().FindTypes(nullptr, query, results); + type_sp = results.GetFirstType(); } - if (size_t num_types = types.GetSize()) { - for (size_t ti = 0; ti < num_types; ++ti) { - lldb::TypeSP type_sp = types.GetTypeAtIndex(ti); - - if (log) { - const char *name_string = type_sp->GetName().GetCString(); - - LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name, - (name_string ? name_string : "<anonymous>")); - } + if (type_sp) { + if (log) { + const char *name_string = type_sp->GetName().GetCString(); - CompilerType full_type = type_sp->GetFullCompilerType(); + LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name, + (name_string ? name_string : "<anonymous>")); + } - CompilerType copied_clang_type(GuardedCopyType(full_type)); + CompilerType full_type = type_sp->GetFullCompilerType(); - if (!copied_clang_type) { - LLDB_LOG(log, " CAS::FEVD - Couldn't export a type"); + CompilerType copied_clang_type(GuardedCopyType(full_type)); - continue; - } + if (!copied_clang_type) { + LLDB_LOG(log, " CAS::FEVD - Couldn't export a type"); + } else { context.AddTypeDecl(copied_clang_type); context.m_found_type = true; - break; } } 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 6fbc0bb22f82..2d306b42760b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1369,7 +1369,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( if (!namespace_decl) SearchPersistenDecls(context, name); - if (name.GetStringRef().startswith("$") && !namespace_decl) { + if (name.GetStringRef().starts_with("$") && !namespace_decl) { if (name == "$__lldb_class") { LookUpLldbClass(context); return; @@ -1385,7 +1385,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( } // any other $__lldb names should be weeded out now - if (name.GetStringRef().startswith("$__lldb")) + if (name.GetStringRef().starts_with("$__lldb")) return; // No ParserVars means we can't do register or variable lookup. @@ -1400,7 +1400,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( return; } - assert(name.GetStringRef().startswith("$")); + assert(name.GetStringRef().starts_with("$")); llvm::StringRef reg_name = name.GetStringRef().substr(1); if (m_parser_vars->m_exe_ctx.GetRegisterContext()) { 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 9430ab5b0464..d8d519693f10 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -53,7 +53,7 @@ class ClangPersistentVariables; /// struct so that it can be passed to the JITted version of the IR. /// /// Fourth and finally, it "dematerializes" the struct after the JITted code -/// has has executed, placing the new values back where it found the old ones. +/// has executed, placing the new values back where it found the old ones. class ClangExpressionDeclMap : public ClangASTSource { public: /// Constructor 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 f3d6ea26b30d..574d661e2a21 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -71,7 +71,6 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/File.h" @@ -576,6 +575,7 @@ ClangExpressionParser::ClangExpressionParser( lang_opts.GNUMode = true; lang_opts.GNUKeywords = true; lang_opts.CPlusPlus11 = true; + lang_opts.BuiltinHeadersInSystemModules = true; // The Darwin libc expects this macro to be set. lang_opts.GNUCVersion = 40201; @@ -834,13 +834,13 @@ public: case CodeCompletionResult::RK_Declaration: return !( Result.Declaration->getIdentifier() && - Result.Declaration->getIdentifier()->getName().startswith(Filter)); + Result.Declaration->getIdentifier()->getName().starts_with(Filter)); case CodeCompletionResult::RK_Keyword: - return !StringRef(Result.Keyword).startswith(Filter); + return !StringRef(Result.Keyword).starts_with(Filter); case CodeCompletionResult::RK_Macro: - return !Result.Macro->getName().startswith(Filter); + return !Result.Macro->getName().starts_with(Filter); case CodeCompletionResult::RK_Pattern: - return !StringRef(Result.Pattern->getAsString()).startswith(Filter); + return !StringRef(Result.Pattern->getAsString()).starts_with(Filter); } // If we trigger this assert or the above switch yields a warning, then // CodeCompletionResult has been enhanced with more kinds of completion @@ -904,7 +904,7 @@ private: } // We also filter some internal lldb identifiers here. The user // shouldn't see these. - if (llvm::StringRef(ToInsert).startswith("$__lldb_")) + if (llvm::StringRef(ToInsert).starts_with("$__lldb_")) return std::nullopt; if (ToInsert.empty()) return std::nullopt; @@ -1078,13 +1078,14 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, // While parsing the Sema will call this consumer with the provided // completion suggestions. if (completion_consumer) { - auto main_file = source_mgr.getFileEntryForID(source_mgr.getMainFileID()); + auto main_file = + source_mgr.getFileEntryRefForID(source_mgr.getMainFileID()); auto &PP = m_compiler->getPreprocessor(); // Lines and columns start at 1 in Clang, but code completion positions are // indexed from 0, so we need to add 1 to the line and column here. ++completion_line; ++completion_column; - PP.SetCodeCompletionPoint(main_file, completion_line, completion_column); + PP.SetCodeCompletionPoint(*main_file, completion_line, completion_column); } ASTConsumer *ast_transformer = 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 74c1212791be..68bdd96e8adb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -27,7 +27,6 @@ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Expression/ExpressionSourceCode.h" #include "lldb/Expression/IRExecutionUnit.h" @@ -873,7 +872,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, } lldb::addr_t ClangUserExpression::GetCppObjectPointer( - lldb::StackFrameSP frame_sp, ConstString &object_name, Status &err) { + lldb::StackFrameSP frame_sp, llvm::StringRef object_name, Status &err) { auto valobj_sp = GetObjectPointerValueObject(std::move(frame_sp), object_name, err); @@ -890,9 +889,9 @@ lldb::addr_t ClangUserExpression::GetCppObjectPointer( lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); if (ret == LLDB_INVALID_ADDRESS) { - err.SetErrorStringWithFormat( - "Couldn't load '%s' because its value couldn't be evaluated", - object_name.AsCString()); + err.SetErrorStringWithFormatv( + "Couldn't load '{0}' because its value couldn't be evaluated", + object_name); return LLDB_INVALID_ADDRESS; } @@ -911,19 +910,18 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, if (!frame_sp) return true; - ConstString object_name; - - if (m_in_cplusplus_method) { - object_name.SetCString("this"); - } else if (m_in_objectivec_method) { - object_name.SetCString("self"); - } else { + if (!m_in_cplusplus_method && !m_in_objectivec_method) { diagnostic_manager.PutString( eDiagnosticSeverityError, "need object pointer but don't know the language"); return false; } + static constexpr llvm::StringLiteral g_cplusplus_object_name("this"); + static constexpr llvm::StringLiteral g_objc_object_name("self"); + llvm::StringRef object_name = + m_in_cplusplus_method ? g_cplusplus_object_name : g_objc_object_name; + Status object_ptr_error; if (m_ctx_obj) { @@ -943,14 +941,14 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, } if (!object_ptr_error.Success()) { - exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf( - "warning: `%s' is not accessible (substituting 0). %s\n", - object_name.AsCString(), object_ptr_error.AsCString()); + exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Format( + "warning: `{0}' is not accessible (substituting 0). {1}\n", + object_name, object_ptr_error.AsCString()); object_ptr = 0; } if (m_in_objectivec_method) { - ConstString cmd_name("_cmd"); + static constexpr llvm::StringLiteral cmd_name("_cmd"); cmd_ptr = GetObjectPointer(frame_sp, cmd_name, object_ptr_error); 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 0fbeff7f6143..7a8c095f6118 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -204,7 +204,7 @@ private: bool for_completion); lldb::addr_t GetCppObjectPointer(lldb::StackFrameSP frame, - ConstString &object_name, Status &err); + llvm::StringRef object_name, Status &err); /// Defines how the current expression should be wrapped. ClangExpressionSourceCode::WrapKind GetWrapKind() const; 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 371605d427ad..56d6cf19ee4c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -17,7 +17,6 @@ #include "lldb/Core/Module.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Host/Host.h" #include "lldb/Target/ExecutionContext.h" 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 847dab6592b8..62443d1290dc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp @@ -72,7 +72,7 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f, // 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++")) { + parent_path(posix_dir, Style::posix).ends_with("c++")) { if (!m_std_inc.TrySet(posix_dir)) return false; if (triple.str().empty()) 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 cd7d1ff6148b..bc0f5993aad0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp @@ -273,7 +273,7 @@ protected: PointerType *GetI8PtrTy() { if (!m_i8ptr_ty) - m_i8ptr_ty = llvm::Type::getInt8PtrTy(m_module.getContext()); + m_i8ptr_ty = llvm::PointerType::getUnqual(m_module.getContext()); return m_i8ptr_ty; } 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 1b7e86bb187f..597873af8b2a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -154,9 +154,10 @@ clang::NamedDecl *IRForTarget::DeclForGlobal(GlobalValue *global_val) { /// Returns true iff the mangled symbol is for a static guard variable. static bool isGuardVariableSymbol(llvm::StringRef mangled_symbol, bool check_ms_abi = true) { - bool result = mangled_symbol.startswith("_ZGV"); // Itanium ABI guard variable + bool result = + mangled_symbol.starts_with("_ZGV"); // Itanium ABI guard variable if (check_ms_abi) - result |= mangled_symbol.endswith("@4IA"); // Microsoft ABI + result |= mangled_symbol.ends_with("@4IA"); // Microsoft ABI return result; } @@ -404,7 +405,7 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str, Type *ns_str_ty = ns_str->getType(); - Type *i8_ptr_ty = Type::getInt8PtrTy(m_module->getContext()); + Type *i8_ptr_ty = PointerType::getUnqual(m_module->getContext()); Type *i32_ty = Type::getInt32Ty(m_module->getContext()); Type *i8_ty = Type::getInt8Ty(m_module->getContext()); @@ -720,8 +721,9 @@ bool IRForTarget::RewriteObjCConstStrings() { static bool IsObjCSelectorRef(Value *value) { GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value); - return !(!global_variable || !global_variable->hasName() || - !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_")); + return !( + !global_variable || !global_variable->hasName() || + !global_variable->getName().starts_with("OBJC_SELECTOR_REFERENCES_")); } // This function does not report errors; its callers are responsible. @@ -801,11 +803,11 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) { // is uint8_t* // Type *sel_type = StructType::get(m_module->getContext()); // Type *sel_ptr_type = PointerType::getUnqual(sel_type); - Type *sel_ptr_type = Type::getInt8PtrTy(m_module->getContext()); + Type *sel_ptr_type = PointerType::getUnqual(m_module->getContext()); Type *type_array[1]; - type_array[0] = llvm::Type::getInt8PtrTy(m_module->getContext()); + type_array[0] = llvm::PointerType::getUnqual(m_module->getContext()); ArrayRef<Type *> srN_arg_types(type_array, 1); @@ -940,7 +942,7 @@ bool IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block) { if (AllocaInst *alloc = dyn_cast<AllocaInst>(&inst)) { llvm::StringRef alloc_name = alloc->getName(); - if (alloc_name.startswith("$") && !alloc_name.startswith("$__lldb")) { + if (alloc_name.starts_with("$") && !alloc_name.starts_with("$__lldb")) { if (alloc_name.find_first_of("0123456789") == 1) { LLDB_LOG(log, "Rejecting a numeric persistent variable."); @@ -1017,7 +1019,7 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { const Type *value_type = nullptr; - if (name.startswith("$")) { + if (name.starts_with("$")) { // The $__lldb_expr_result name indicates the return value has allocated // as a static variable. Per the comment at // ASTResultSynthesizer::SynthesizeBodyResult, accesses to this static @@ -1223,7 +1225,7 @@ bool IRForTarget::ResolveExternals(Function &llvm_function) { LLDB_LOG(log, "Examining {0}, DeclForGlobalValue returns {1}", global_name, static_cast<void *>(DeclForGlobal(&global_var))); - if (global_name.startswith("OBJC_IVAR")) { + if (global_name.starts_with("OBJC_IVAR")) { if (!HandleSymbol(&global_var)) { m_error_stream.Format("Error [IRForTarget]: Couldn't find Objective-C " "indirect ivar symbol {0}\n", @@ -1641,14 +1643,6 @@ bool IRForTarget::runOnModule(Module &llvm_module) { } } - llvm::Type *int8_ty = Type::getInt8Ty(m_module->getContext()); - - m_reloc_placeholder = new llvm::GlobalVariable( - (*m_module), int8_ty, false /* IsConstant */, - GlobalVariable::InternalLinkage, Constant::getNullValue(int8_ty), - "reloc_placeholder", nullptr /* InsertBefore */, - GlobalVariable::NotThreadLocal /* ThreadLocal */, 0 /* AddressSpace */); - //////////////////////////////////////////////////////////// // Replace $__lldb_expr_result with a persistent variable // diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h index eb93952e2b3c..a924187ba04c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h @@ -111,43 +111,6 @@ private: /// True on success; false otherwise. bool FixFunctionLinkage(llvm::Function &llvm_function); - /// A module-level pass to replace all function pointers with their - /// integer equivalents. - - /// The top-level pass implementation - /// - /// \param[in] llvm_function - /// The function currently being processed. - /// - /// \return - /// True on success; false otherwise. - bool HasSideEffects(llvm::Function &llvm_function); - - /// A function-level pass to check whether the function has side - /// effects. - - /// Get the address of a function, and a location to put the complete Value - /// of the function if one is available. - /// - /// \param[in] function - /// The function to find the location of. - /// - /// \param[out] ptr - /// The location of the function in the target. - /// - /// \param[out] name - /// The resolved name of the function (matters for intrinsics). - /// - /// \param[out] value_ptr - /// A variable to put the function's completed Value* in, or NULL - /// if the Value* shouldn't be stored anywhere. - /// - /// \return - /// The pointer. - LookupResult GetFunctionAddress(llvm::Function *function, uint64_t &ptr, - lldb_private::ConstString &name, - llvm::Constant **&value_ptr); - /// A function-level pass to take the generated global value /// $__lldb_expr_result and make it into a persistent variable. Also see /// ASTResultSynthesizer. @@ -170,30 +133,6 @@ public: private: clang::NamedDecl *DeclForGlobal(llvm::GlobalValue *global); - /// Set the constant result variable m_const_result to the provided - /// constant, assuming it can be evaluated. The result variable will be - /// reset to NULL later if the expression has side effects. - /// - /// \param[in] initializer - /// The constant initializer for the variable. - /// - /// \param[in] name - /// The name of the result variable. - /// - /// \param[in] type - /// The Clang type of the result variable. - void MaybeSetConstantResult(llvm::Constant *initializer, - lldb_private::ConstString name, - lldb_private::TypeFromParser type); - - /// If the IR represents a cast of a variable, set m_const_result to the - /// result of the cast. The result variable will be reset to - /// NULL latger if the expression has side effects. - /// - /// \param[in] type - /// The Clang type of the result variable. - void MaybeSetCastResult(lldb_private::TypeFromParser type); - /// The top-level pass implementation /// /// \param[in] llvm_function @@ -409,15 +348,9 @@ private: lldb_private::Stream &m_error_stream; /// The execution unit containing the IR being created. lldb_private::IRExecutionUnit &m_execution_unit; - /// If non-NULL, the store instruction that writes to the result variable. If - /// m_has_side_effects is true, this is NULL. - llvm::StoreInst *m_result_store = nullptr; /// True if the function's result in the AST is a pointer (see comments in /// ASTResultSynthesizer::SynthesizeBodyResult) bool m_result_is_pointer = false; - /// A placeholder that will be replaced by a pointer to the final location of - /// the static allocation. - llvm::GlobalVariable *m_reloc_placeholder = nullptr; class FunctionValueCache { public: @@ -454,13 +387,6 @@ private: FunctionValueCache &value_maker, FunctionValueCache &entry_instruction_finder, lldb_private::Stream &error_stream); - - /// Commit the allocation in m_data_allocator and use its final location to - /// replace m_reloc_placeholder. - /// - /// \return - /// True on success; false otherwise - bool CompleteDataAllocation(); }; #endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H 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 a67cc8e10c17..da59855a9f16 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -62,9 +62,9 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, clang::DeclContext *context = const_cast<DeclContext *>(m_decl_context); if (extern_c) { - context = LinkageSpecDecl::Create( - ast, context, SourceLocation(), SourceLocation(), - clang::LinkageSpecDecl::LanguageIDs::lang_c, false); + context = LinkageSpecDecl::Create(ast, context, SourceLocation(), + SourceLocation(), + clang::LinkageSpecLanguageIDs::C, false); // FIXME: The LinkageSpecDecl here should be added to m_decl_context. } diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp index 44070b422220..a09c89103b0e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp @@ -9,23 +9,14 @@ #include "InstrumentationRuntimeASan.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" -#include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" -#include "lldb/Core/ValueObject.h" -#include "lldb/Expression/UserExpression.h" -#include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Symbol/Symbol.h" -#include "lldb/Target/InstrumentationRuntimeStopInfo.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" +#include "lldb/Target/Process.h" #include "lldb/Utility/RegularExpression.h" -#include "lldb/Utility/Stream.h" -#include "llvm/ADT/StringSwitch.h" +#include "Plugins/InstrumentationRuntime/Utility/ReportRetriever.h" using namespace lldb; using namespace lldb_private; @@ -69,173 +60,6 @@ bool InstrumentationRuntimeASan::CheckIfRuntimeIsValid( return symbol != nullptr; } -const char *address_sanitizer_retrieve_report_data_prefix = R"( -extern "C" -{ -int __asan_report_present(); -void *__asan_get_report_pc(); -void *__asan_get_report_bp(); -void *__asan_get_report_sp(); -void *__asan_get_report_address(); -const char *__asan_get_report_description(); -int __asan_get_report_access_type(); -size_t __asan_get_report_access_size(); -} -)"; - -const char *address_sanitizer_retrieve_report_data_command = R"( -struct { - int present; - int access_type; - void *pc; - void *bp; - void *sp; - void *address; - size_t access_size; - const char *description; -} t; - -t.present = __asan_report_present(); -t.access_type = __asan_get_report_access_type(); -t.pc = __asan_get_report_pc(); -t.bp = __asan_get_report_bp(); -t.sp = __asan_get_report_sp(); -t.address = __asan_get_report_address(); -t.access_size = __asan_get_report_access_size(); -t.description = __asan_get_report_description(); -t -)"; - -StructuredData::ObjectSP InstrumentationRuntimeASan::RetrieveReportData() { - ProcessSP process_sp = GetProcessSP(); - if (!process_sp) - return StructuredData::ObjectSP(); - - ThreadSP thread_sp = - process_sp->GetThreadList().GetExpressionExecutionThread(); - StackFrameSP frame_sp = - thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame); - - if (!frame_sp) - return StructuredData::ObjectSP(); - - EvaluateExpressionOptions options; - options.SetUnwindOnError(true); - options.SetTryAllThreads(true); - options.SetStopOthers(true); - options.SetIgnoreBreakpoints(true); - options.SetTimeout(process_sp->GetUtilityExpressionTimeout()); - options.SetPrefix(address_sanitizer_retrieve_report_data_prefix); - options.SetAutoApplyFixIts(false); - options.SetLanguage(eLanguageTypeObjC_plus_plus); - - ValueObjectSP return_value_sp; - ExecutionContext exe_ctx; - Status eval_error; - frame_sp->CalculateExecutionContext(exe_ctx); - ExpressionResults result = UserExpression::Evaluate( - exe_ctx, options, address_sanitizer_retrieve_report_data_command, "", - return_value_sp, eval_error); - if (result != eExpressionCompleted) { - StreamString ss; - ss << "cannot evaluate AddressSanitizer expression:\n"; - ss << eval_error.AsCString(); - Debugger::ReportWarning(ss.GetString().str(), - process_sp->GetTarget().GetDebugger().GetID()); - return StructuredData::ObjectSP(); - } - - int present = return_value_sp->GetValueForExpressionPath(".present") - ->GetValueAsUnsigned(0); - if (present != 1) - return StructuredData::ObjectSP(); - - addr_t pc = - return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0); - /* commented out because rdar://problem/18533301 - addr_t bp = - return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0); - addr_t sp = - return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0); - */ - addr_t address = return_value_sp->GetValueForExpressionPath(".address") - ->GetValueAsUnsigned(0); - addr_t access_type = - return_value_sp->GetValueForExpressionPath(".access_type") - ->GetValueAsUnsigned(0); - addr_t access_size = - return_value_sp->GetValueForExpressionPath(".access_size") - ->GetValueAsUnsigned(0); - addr_t description_ptr = - return_value_sp->GetValueForExpressionPath(".description") - ->GetValueAsUnsigned(0); - std::string description; - Status error; - process_sp->ReadCStringFromMemory(description_ptr, description, error); - - StructuredData::Dictionary *dict = new StructuredData::Dictionary(); - dict->AddStringItem("instrumentation_class", "AddressSanitizer"); - dict->AddStringItem("stop_type", "fatal_error"); - dict->AddIntegerItem("pc", pc); - /* commented out because rdar://problem/18533301 - dict->AddIntegerItem("bp", bp); - dict->AddIntegerItem("sp", sp); - */ - dict->AddIntegerItem("address", address); - dict->AddIntegerItem("access_type", access_type); - dict->AddIntegerItem("access_size", access_size); - dict->AddStringItem("description", description); - - return StructuredData::ObjectSP(dict); -} - -std::string -InstrumentationRuntimeASan::FormatDescription(StructuredData::ObjectSP report) { - std::string description = std::string(report->GetAsDictionary() - ->GetValueForKey("description") - ->GetAsString() - ->GetValue()); - return llvm::StringSwitch<std::string>(description) - .Case("heap-use-after-free", "Use of deallocated memory") - .Case("heap-buffer-overflow", "Heap buffer overflow") - .Case("stack-buffer-underflow", "Stack buffer underflow") - .Case("initialization-order-fiasco", "Initialization order problem") - .Case("stack-buffer-overflow", "Stack buffer overflow") - .Case("stack-use-after-return", "Use of stack memory after return") - .Case("use-after-poison", "Use of poisoned memory") - .Case("container-overflow", "Container overflow") - .Case("stack-use-after-scope", "Use of out-of-scope stack memory") - .Case("global-buffer-overflow", "Global buffer overflow") - .Case("unknown-crash", "Invalid memory access") - .Case("stack-overflow", "Stack space exhausted") - .Case("null-deref", "Dereference of null pointer") - .Case("wild-jump", "Jump to non-executable address") - .Case("wild-addr-write", "Write through wild pointer") - .Case("wild-addr-read", "Read from wild pointer") - .Case("wild-addr", "Access through wild pointer") - .Case("signal", "Deadly signal") - .Case("double-free", "Deallocation of freed memory") - .Case("new-delete-type-mismatch", - "Deallocation size different from allocation size") - .Case("bad-free", "Deallocation of non-allocated memory") - .Case("alloc-dealloc-mismatch", - "Mismatch between allocation and deallocation APIs") - .Case("bad-malloc_usable_size", "Invalid argument to malloc_usable_size") - .Case("bad-__sanitizer_get_allocated_size", - "Invalid argument to __sanitizer_get_allocated_size") - .Case("param-overlap", - "Call to function disallowing overlapping memory ranges") - .Case("negative-size-param", "Negative size used when accessing memory") - .Case("bad-__sanitizer_annotate_contiguous_container", - "Invalid argument to __sanitizer_annotate_contiguous_container") - .Case("odr-violation", "Symbol defined in multiple translation units") - .Case( - "invalid-pointer-pair", - "Comparison or arithmetic on pointers from different memory regions") - // for unknown report codes just show the code - .Default("AddressSanitizer detected: " + description); -} - bool InstrumentationRuntimeASan::NotifyBreakpointHit( void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) { @@ -248,32 +72,8 @@ bool InstrumentationRuntimeASan::NotifyBreakpointHit( ProcessSP process_sp = instance->GetProcessSP(); - if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) - return false; - - StructuredData::ObjectSP report = instance->RetrieveReportData(); - std::string description; - if (report) { - description = instance->FormatDescription(report); - } - // Make sure this is the right process - if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) { - ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); - if (thread_sp) - thread_sp->SetStopInfo(InstrumentationRuntimeStopInfo:: - CreateStopReasonWithInstrumentationData( - *thread_sp, description, report)); - - StreamFileSP stream_sp( - process_sp->GetTarget().GetDebugger().GetOutputStreamSP()); - if (stream_sp) { - stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread " - "info -s' to get extended information about the " - "report.\n"); - } - return true; // Return true to stop the target - } else - return false; // Let target run + return ReportRetriever::NotifyBreakpointHit(process_sp, context, break_id, + break_loc_id); } void InstrumentationRuntimeASan::Activate() { @@ -284,29 +84,14 @@ void InstrumentationRuntimeASan::Activate() { if (!process_sp) return; - ConstString symbol_name("_ZN6__asanL7AsanDieEv"); - const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType( - symbol_name, eSymbolTypeCode); - - if (symbol == nullptr) - return; + Breakpoint *breakpoint = ReportRetriever::SetupBreakpoint( + GetRuntimeModuleSP(), process_sp, ConstString("_ZN6__asanL7AsanDieEv")); - if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid()) + if (!breakpoint) return; - Target &target = process_sp->GetTarget(); - addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target); - - if (symbol_address == LLDB_INVALID_ADDRESS) - return; - - const bool internal = true; - const bool hardware = false; const bool sync = false; - Breakpoint *breakpoint = - process_sp->GetTarget() - .CreateBreakpoint(symbol_address, internal, hardware) - .get(); + breakpoint->SetCallback(InstrumentationRuntimeASan::NotifyBreakpointHit, this, sync); breakpoint->SetBreakpointKind("address-sanitizer-report"); @@ -316,12 +101,13 @@ void InstrumentationRuntimeASan::Activate() { } void InstrumentationRuntimeASan::Deactivate() { - if (GetBreakpointID() != LLDB_INVALID_BREAK_ID) { - ProcessSP process_sp = GetProcessSP(); - if (process_sp) { - process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID()); - SetBreakpointID(LLDB_INVALID_BREAK_ID); - } - } SetActive(false); + + if (GetBreakpointID() == LLDB_INVALID_BREAK_ID) + return; + + if (ProcessSP process_sp = GetProcessSP()) { + process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID()); + SetBreakpointID(LLDB_INVALID_BREAK_ID); + } } diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h index 83a88cf7f89f..177959d7126b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h @@ -10,9 +10,6 @@ #define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMEASAN_H #include "lldb/Target/InstrumentationRuntime.h" -#include "lldb/Target/Process.h" -#include "lldb/Utility/StructuredData.h" -#include "lldb/lldb-private.h" namespace lldb_private { @@ -51,10 +48,6 @@ private: StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); - - StructuredData::ObjectSP RetrieveReportData(); - - std::string FormatDescription(StructuredData::ObjectSP report); }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.cpp new file mode 100644 index 000000000000..d84cd36d7ce1 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.cpp @@ -0,0 +1,120 @@ +//===-- InstrumentationRuntimeASanLibsanitizers.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 "InstrumentationRuntimeASanLibsanitizers.h" + +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginInterface.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/RegularExpression.h" + +#include "Plugins/InstrumentationRuntime/Utility/ReportRetriever.h" + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(InstrumentationRuntimeASanLibsanitizers) + +lldb::InstrumentationRuntimeSP +InstrumentationRuntimeASanLibsanitizers::CreateInstance( + const lldb::ProcessSP &process_sp) { + return InstrumentationRuntimeSP( + new InstrumentationRuntimeASanLibsanitizers(process_sp)); +} + +void InstrumentationRuntimeASanLibsanitizers::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), + "AddressSanitizer instrumentation runtime plugin for Libsanitizers.", + CreateInstance, GetTypeStatic); +} + +void InstrumentationRuntimeASanLibsanitizers::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +lldb::InstrumentationRuntimeType +InstrumentationRuntimeASanLibsanitizers::GetTypeStatic() { + return eInstrumentationRuntimeTypeLibsanitizersAsan; +} + +InstrumentationRuntimeASanLibsanitizers:: + ~InstrumentationRuntimeASanLibsanitizers() { + Deactivate(); +} + +const RegularExpression & +InstrumentationRuntimeASanLibsanitizers::GetPatternForRuntimeLibrary() { + static RegularExpression regex( + llvm::StringRef("libsystem_sanitizers\\.dylib")); + return regex; +} + +bool InstrumentationRuntimeASanLibsanitizers::CheckIfRuntimeIsValid( + const lldb::ModuleSP module_sp) { + const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( + ConstString("__asan_abi_init"), lldb::eSymbolTypeAny); + + return symbol != nullptr; +} + +bool InstrumentationRuntimeASanLibsanitizers::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + assert(baton && "null baton"); + if (!baton) + return false; + + InstrumentationRuntimeASanLibsanitizers *const instance = + static_cast<InstrumentationRuntimeASanLibsanitizers *>(baton); + + ProcessSP process_sp = instance->GetProcessSP(); + + return ReportRetriever::NotifyBreakpointHit(process_sp, context, break_id, + break_loc_id); +} + +void InstrumentationRuntimeASanLibsanitizers::Activate() { + if (IsActive()) + return; + + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return; + + Breakpoint *breakpoint = ReportRetriever::SetupBreakpoint( + GetRuntimeModuleSP(), process_sp, + ConstString("_Z22raise_sanitizers_error23sanitizer_error_context")); + + if (!breakpoint) + return; + + const bool sync = false; + + breakpoint->SetCallback( + InstrumentationRuntimeASanLibsanitizers::NotifyBreakpointHit, this, sync); + breakpoint->SetBreakpointKind("address-sanitizer-report"); + SetBreakpointID(breakpoint->GetID()); + + SetActive(true); +} + +void InstrumentationRuntimeASanLibsanitizers::Deactivate() { + SetActive(false); + + if (GetBreakpointID() == LLDB_INVALID_BREAK_ID) + return; + + if (ProcessSP process_sp = GetProcessSP()) { + process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID()); + SetBreakpointID(LLDB_INVALID_BREAK_ID); + } +} diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.h b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.h new file mode 100644 index 000000000000..abb445a9dd67 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.h @@ -0,0 +1,52 @@ +//===-- InstrumentationRuntimeASanLibsanitizers.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_INSTRUMENTATIONRUNTIME_ASANLIBSANITIZERS_INSTRUMENTATIONRUNTIMEASANLIBSANITIZERS_H +#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASANLIBSANITIZERS_INSTRUMENTATIONRUNTIMEASANLIBSANITIZERS_H + +#include "lldb/Target/InstrumentationRuntime.h" + +class InstrumentationRuntimeASanLibsanitizers + : public lldb_private::InstrumentationRuntime { +public: + ~InstrumentationRuntimeASanLibsanitizers() override; + + static lldb::InstrumentationRuntimeSP + CreateInstance(const lldb::ProcessSP &process_sp); + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "Libsanitizers-ASan"; } + + static lldb::InstrumentationRuntimeType GetTypeStatic(); + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); } + +private: + InstrumentationRuntimeASanLibsanitizers(const lldb::ProcessSP &process_sp) + : lldb_private::InstrumentationRuntime(process_sp) {} + + const lldb_private::RegularExpression &GetPatternForRuntimeLibrary() override; + + bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override; + + void Activate() override; + + void Deactivate(); + + static bool + NotifyBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); +}; + +#endif // LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASANLIBSANITIZERS_INSTRUMENTATIONRUNTIMEASANLIBSANITIZERS_H 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 8a5db3335266..2a35256a6fb0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -14,9 +14,9 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/ValueObject.h" #include "lldb/Expression/UserExpression.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index 2e3c053b97bc..1c58922e8d36 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -14,9 +14,9 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/ValueObject.h" #include "lldb/Expression/UserExpression.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp new file mode 100644 index 000000000000..ff58c4cababa --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp @@ -0,0 +1,252 @@ +//===-- ReportRetriever.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 "ReportRetriever.h" + +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Target/InstrumentationRuntimeStopInfo.h" + +using namespace lldb; +using namespace lldb_private; + +const char *address_sanitizer_retrieve_report_data_prefix = R"( +extern "C" +{ +int __asan_report_present(); +void *__asan_get_report_pc(); +void *__asan_get_report_bp(); +void *__asan_get_report_sp(); +void *__asan_get_report_address(); +const char *__asan_get_report_description(); +int __asan_get_report_access_type(); +size_t __asan_get_report_access_size(); +} +)"; + +const char *address_sanitizer_retrieve_report_data_command = R"( +struct { + int present; + int access_type; + void *pc; + void *bp; + void *sp; + void *address; + size_t access_size; + const char *description; +} t; + +t.present = __asan_report_present(); +t.access_type = __asan_get_report_access_type(); +t.pc = __asan_get_report_pc(); +t.bp = __asan_get_report_bp(); +t.sp = __asan_get_report_sp(); +t.address = __asan_get_report_address(); +t.access_size = __asan_get_report_access_size(); +t.description = __asan_get_report_description(); +t +)"; + +StructuredData::ObjectSP +ReportRetriever::RetrieveReportData(const ProcessSP process_sp) { + if (!process_sp) + return StructuredData::ObjectSP(); + + ThreadSP thread_sp = + process_sp->GetThreadList().GetExpressionExecutionThread(); + + if (!thread_sp) + return StructuredData::ObjectSP(); + + StackFrameSP frame_sp = + thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame); + + if (!frame_sp) + return StructuredData::ObjectSP(); + + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetTryAllThreads(true); + options.SetStopOthers(true); + options.SetIgnoreBreakpoints(true); + options.SetTimeout(process_sp->GetUtilityExpressionTimeout()); + options.SetPrefix(address_sanitizer_retrieve_report_data_prefix); + options.SetAutoApplyFixIts(false); + options.SetLanguage(eLanguageTypeObjC_plus_plus); + + ValueObjectSP return_value_sp; + ExecutionContext exe_ctx; + Status eval_error; + frame_sp->CalculateExecutionContext(exe_ctx); + ExpressionResults result = UserExpression::Evaluate( + exe_ctx, options, address_sanitizer_retrieve_report_data_command, "", + return_value_sp, eval_error); + if (result != eExpressionCompleted) { + StreamString ss; + ss << "cannot evaluate AddressSanitizer expression:\n"; + ss << eval_error.AsCString(); + Debugger::ReportWarning(ss.GetString().str(), + process_sp->GetTarget().GetDebugger().GetID()); + return StructuredData::ObjectSP(); + } + + int present = return_value_sp->GetValueForExpressionPath(".present") + ->GetValueAsUnsigned(0); + if (present != 1) + return StructuredData::ObjectSP(); + + addr_t pc = + return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0); + addr_t bp = + return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0); + addr_t sp = + return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0); + addr_t address = return_value_sp->GetValueForExpressionPath(".address") + ->GetValueAsUnsigned(0); + addr_t access_type = + return_value_sp->GetValueForExpressionPath(".access_type") + ->GetValueAsUnsigned(0); + addr_t access_size = + return_value_sp->GetValueForExpressionPath(".access_size") + ->GetValueAsUnsigned(0); + addr_t description_ptr = + return_value_sp->GetValueForExpressionPath(".description") + ->GetValueAsUnsigned(0); + std::string description; + Status error; + process_sp->ReadCStringFromMemory(description_ptr, description, error); + + auto dict = std::make_shared<StructuredData::Dictionary>(); + if (!dict) + return StructuredData::ObjectSP(); + + dict->AddStringItem("instrumentation_class", "AddressSanitizer"); + dict->AddStringItem("stop_type", "fatal_error"); + dict->AddIntegerItem("pc", pc); + dict->AddIntegerItem("bp", bp); + dict->AddIntegerItem("sp", sp); + dict->AddIntegerItem("address", address); + dict->AddIntegerItem("access_type", access_type); + dict->AddIntegerItem("access_size", access_size); + dict->AddStringItem("description", description); + + return StructuredData::ObjectSP(dict); +} + +std::string +ReportRetriever::FormatDescription(StructuredData::ObjectSP report) { + std::string description = std::string(report->GetAsDictionary() + ->GetValueForKey("description") + ->GetAsString() + ->GetValue()); + return llvm::StringSwitch<std::string>(description) + .Case("heap-use-after-free", "Use of deallocated memory") + .Case("heap-buffer-overflow", "Heap buffer overflow") + .Case("stack-buffer-underflow", "Stack buffer underflow") + .Case("initialization-order-fiasco", "Initialization order problem") + .Case("stack-buffer-overflow", "Stack buffer overflow") + .Case("stack-use-after-return", "Use of stack memory after return") + .Case("use-after-poison", "Use of poisoned memory") + .Case("container-overflow", "Container overflow") + .Case("stack-use-after-scope", "Use of out-of-scope stack memory") + .Case("global-buffer-overflow", "Global buffer overflow") + .Case("unknown-crash", "Invalid memory access") + .Case("stack-overflow", "Stack space exhausted") + .Case("null-deref", "Dereference of null pointer") + .Case("wild-jump", "Jump to non-executable address") + .Case("wild-addr-write", "Write through wild pointer") + .Case("wild-addr-read", "Read from wild pointer") + .Case("wild-addr", "Access through wild pointer") + .Case("signal", "Deadly signal") + .Case("double-free", "Deallocation of freed memory") + .Case("new-delete-type-mismatch", + "Deallocation size different from allocation size") + .Case("bad-free", "Deallocation of non-allocated memory") + .Case("alloc-dealloc-mismatch", + "Mismatch between allocation and deallocation APIs") + .Case("bad-malloc_usable_size", "Invalid argument to malloc_usable_size") + .Case("bad-__sanitizer_get_allocated_size", + "Invalid argument to __sanitizer_get_allocated_size") + .Case("param-overlap", + "Call to function disallowing overlapping memory ranges") + .Case("negative-size-param", "Negative size used when accessing memory") + .Case("bad-__sanitizer_annotate_contiguous_container", + "Invalid argument to __sanitizer_annotate_contiguous_container") + .Case("odr-violation", "Symbol defined in multiple translation units") + .Case( + "invalid-pointer-pair", + "Comparison or arithmetic on pointers from different memory regions") + // for unknown report codes just show the code + .Default("AddressSanitizer detected: " + description); +} + +bool ReportRetriever::NotifyBreakpointHit(ProcessSP process_sp, + StoppointCallbackContext *context, + user_id_t break_id, + user_id_t break_loc_id) { + // Make sure this is the right process + if (!process_sp || process_sp != context->exe_ctx_ref.GetProcessSP()) + return false; + + if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) + return false; + + StructuredData::ObjectSP report = RetrieveReportData(process_sp); + if (!report || report->GetType() != lldb::eStructuredDataTypeDictionary) + return false; + + std::string description = FormatDescription(report); + + if (ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP()) + thread_sp->SetStopInfo( + InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData( + *thread_sp, description, report)); + + if (StreamFileSP stream_sp = StreamFileSP( + process_sp->GetTarget().GetDebugger().GetOutputStreamSP())) + stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread " + "info -s' to get extended information about the " + "report.\n"); + + return true; // Return true to stop the target +} + +Breakpoint *ReportRetriever::SetupBreakpoint(ModuleSP module_sp, + ProcessSP process_sp, + ConstString symbol_name) { + if (!module_sp || !process_sp) + return nullptr; + + const Symbol *symbol = + module_sp->FindFirstSymbolWithNameAndType(symbol_name, eSymbolTypeCode); + + if (symbol == nullptr) + return nullptr; + + if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid()) + return nullptr; + + Target &target = process_sp->GetTarget(); + addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target); + + if (symbol_address == LLDB_INVALID_ADDRESS) + return nullptr; + + const bool internal = true; + const bool hardware = false; + + Breakpoint *breakpoint = + process_sp->GetTarget() + .CreateBreakpoint(symbol_address, internal, hardware) + .get(); + + return breakpoint; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.h b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.h new file mode 100644 index 000000000000..a45339a5809c --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.h @@ -0,0 +1,34 @@ +//===-- ReportRetriever.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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/Process.h" + +#ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_REPORTRETRIEVER_H +#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_REPORTRETRIEVER_H + +namespace lldb_private { + +class ReportRetriever { +private: + static StructuredData::ObjectSP + RetrieveReportData(const lldb::ProcessSP process_sp); + + static std::string FormatDescription(StructuredData::ObjectSP report); + +public: + static bool NotifyBreakpointHit(lldb::ProcessSP process_sp, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + static Breakpoint *SetupBreakpoint(lldb::ModuleSP, lldb::ProcessSP, + ConstString); +}; +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_REPORTRETRIEVER_H 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 97d401028d45..73763d9cf3b8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -91,8 +91,8 @@ enum { class PluginProperties : public Properties { public: - static ConstString GetSettingName() { - return ConstString(JITLoaderGDB::GetPluginNameStatic()); + static llvm::StringRef GetSettingName() { + return JITLoaderGDB::GetPluginNameStatic(); } PluginProperties() { 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 e780cd8285c4..314a4aca8d26 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -54,18 +54,6 @@ public: if (!clang_ast_context) return; - std::shared_ptr<ClangASTImporter> clang_ast_importer; - auto *state = target_sp->GetPersistentExpressionStateForLanguage( - lldb::eLanguageTypeC_plus_plus); - if (state) { - auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); - clang_ast_importer = persistent_vars->GetClangASTImporter(); - } - - if (!clang_ast_importer) { - return; - } - const char *const isa_name("__isa"); const CompilerType isa_type = clang_ast_context->GetBasicType(lldb::eBasicTypeObjCClass); 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 3d709e3d6759..586cc08a6f12 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -45,6 +45,7 @@ #include "LibCxxVariant.h" #include "LibStdcpp.h" #include "MSVCUndecoratedNameParser.h" +#include "lldb/lldb-enumerations.h" using namespace lldb; using namespace lldb_private; @@ -332,14 +333,12 @@ bool CPlusPlusLanguage::MethodName::ContainsPath(llvm::StringRef path) { // If we can't parse the incoming name, then just check that it contains path. if (m_parse_error) return m_full.GetStringRef().contains(path); - + llvm::StringRef identifier; llvm::StringRef context; std::string path_str = path.str(); - bool success - = CPlusPlusLanguage::ExtractContextAndIdentifier(path_str.c_str(), - context, - identifier); + bool success = CPlusPlusLanguage::ExtractContextAndIdentifier( + path_str.c_str(), context, identifier); if (!success) return m_full.GetStringRef().contains(path); @@ -372,7 +371,7 @@ bool CPlusPlusLanguage::MethodName::ContainsPath(llvm::StringRef path) { return false; if (haystack.empty() || !isalnum(haystack.back())) return true; - + return false; } @@ -388,7 +387,7 @@ bool CPlusPlusLanguage::IsCPPMangledName(llvm::StringRef name) { return true; } -bool CPlusPlusLanguage::DemangledNameContainsPath(llvm::StringRef path, +bool CPlusPlusLanguage::DemangledNameContainsPath(llvm::StringRef path, ConstString demangled) const { MethodName demangled_name(demangled); return demangled_name.ContainsPath(path); @@ -467,7 +466,7 @@ protected: } void trySubstitute(llvm::StringRef From, llvm::StringRef To) { - if (!llvm::StringRef(currentParserPos(), this->numLeft()).startswith(From)) + if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From)) return; // We found a match. Append unmodified input up to this point. @@ -981,6 +980,57 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "std::unordered_map iterator synthetic children", "^std::__[[:alnum:]]+::__hash_map_(const_)?iterator<.+>$", stl_synth_flags, true); + // Chrono duration typedefs + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::nanoseconds", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat( + eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} ns"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::microseconds", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat( + eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} µs"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::milliseconds", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat( + eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} ms"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::seconds", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat( + eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::minutes", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren | + eTypeOptionHideValue, + "${var.__rep_} min"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::hours", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat( + eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} h"))); + + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::days", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren | + eTypeOptionHideValue, + "${var.__rep_} days"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::weeks", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren | + eTypeOptionHideValue, + "${var.__rep_} weeks"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::months", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren | + eTypeOptionHideValue, + "${var.__rep_} months"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::years", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren | + eTypeOptionHideValue, + "${var.__rep_} years"))); + cpp_category_sp->AddTypeSummary( + "^std::__[[:alnum:]]+::chrono::seconds", eFormatterMatchRegex, + TypeSummaryImplSP(new StringSummaryFormat( + eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s"))); } static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { @@ -1009,7 +1059,7 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { cpp_category_sp->AddTypeSummary("std::string", eFormatterMatchExact, std_string_summary_sp); cpp_category_sp->AddTypeSummary("std::basic_string<char>", - eFormatterMatchRegex, std_string_summary_sp); + eFormatterMatchExact, std_string_summary_sp); cpp_category_sp->AddTypeSummary( "std::basic_string<char,std::char_traits<char>,std::allocator<char> >", eFormatterMatchExact, std_string_summary_sp); @@ -1104,6 +1154,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider"))); + cpp_category_sp->AddTypeSynthetic( + "^std::variant<.+>$", eFormatterMatchRegex, + SyntheticChildrenSP(new ScriptedSyntheticChildren( + stl_synth_flags, + "lldb.formatters.cpp.gnu_libstdcpp.VariantSynthProvider"))); stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); @@ -1148,6 +1203,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { TypeSummaryImplSP(new ScriptSummaryFormat( stl_summary_flags, "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider"))); + cpp_category_sp->AddTypeSummary( + "^std::variant<.+>$", eFormatterMatchRegex, + TypeSummaryImplSP(new ScriptSummaryFormat( + stl_summary_flags, + "lldb.formatters.cpp.gnu_libstdcpp.VariantSummaryProvider"))); AddCXXSynthetic( cpp_category_sp, @@ -1356,7 +1416,8 @@ CPlusPlusLanguage::GetHardcodedSummaries() { lldb_private::formatters::CXXFunctionPointerSummaryProvider, "Function pointer summary provider")); if (CompilerType CT = valobj.GetCompilerType(); - CT.IsFunctionPointerType() || CT.IsMemberFunctionPointerType()) { + CT.IsFunctionPointerType() || CT.IsMemberFunctionPointerType() || + valobj.GetValueType() == lldb::eValueTypeVTableEntry) { return formatter_sp; } return nullptr; 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 7712a60b7795..623d481bf117 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -103,6 +103,8 @@ public: return lldb::eLanguageTypeC_plus_plus; } + llvm::StringRef GetUserEntryPointName() const override { return "main"; } + std::unique_ptr<TypeScavenger> GetTypeScavenger() override; lldb::TypeCategoryImplSP GetFormatters() override; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp index cd3ac92ae4a8..2876efc5c41a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp @@ -38,7 +38,7 @@ public: ValueObjectSP GetChildAtIndex(size_t idx) override; private: - ConstString GetDataContainerMemberName(); + llvm::StringRef GetDataContainerMemberName(); // The lifetime of a ValueObject and all its derivative ValueObjects // (children, clones, etc.) is managed by a ClusterManager. These @@ -66,12 +66,14 @@ GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib) } } -ConstString GenericBitsetFrontEnd::GetDataContainerMemberName() { +llvm::StringRef GenericBitsetFrontEnd::GetDataContainerMemberName() { + static constexpr llvm::StringLiteral s_libcxx_case("__first_"); + static constexpr llvm::StringLiteral s_libstdcpp_case("_M_w"); switch (m_stdlib) { case StdLib::LibCxx: - return ConstString("__first_"); + return s_libcxx_case; case StdLib::LibStdcpp: - return ConstString("_M_w"); + return s_libstdcpp_case; } llvm_unreachable("Unknown StdLib enum"); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index 14776cdf8081..ff7043bdf97f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -84,7 +84,7 @@ static bool isStdTemplate(ConstString type_name, llvm::StringRef type) { // The type name may be prefixed with `std::__<inline-namespace>::`. if (name.consume_front("std::")) consumeInlineNamespace(name); - return name.consume_front(type) && name.startswith("<"); + return name.consume_front(type) && name.starts_with("<"); } static bool isUnorderedMap(ConstString type_name) { @@ -162,10 +162,27 @@ lldb::ValueObjectSP lldb_private::formatters:: if (!node_sp || error.Fail()) return nullptr; - value_sp = node_sp->GetChildMemberWithName("__value_"); hash_sp = node_sp->GetChildMemberWithName("__hash_"); - if (!value_sp || !hash_sp) + if (!hash_sp) return nullptr; + + value_sp = node_sp->GetChildMemberWithName("__value_"); + if (!value_sp) { + // clang-format off + // Since D101206 (ba79fb2e1f), libc++ wraps the `__value_` in an + // anonymous union. + // Child 0: __hash_node_base base class + // Child 1: __hash_ + // Child 2: anonymous union + // clang-format on + auto anon_union_sp = node_sp->GetChildAtIndex(2); + if (!anon_union_sp) + return nullptr; + + value_sp = anon_union_sp->GetChildMemberWithName("__value_"); + if (!value_sp) + return nullptr; + } } m_elements_cache.push_back( {value_sp.get(), hash_sp->GetValueAsUnsigned(0)}); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index c65bb9b6bc9b..23af50fdb712 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -377,9 +377,16 @@ lldb::ValueObjectSP LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { if (idx == 0) return m_ptr_obj->GetSP(); - if (idx == 1) - return m_obj_obj->GetSP(); - + if (idx == 1) { + if (m_ptr_obj && !m_obj_obj) { + Status error; + ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); + if (error.Success()) + m_obj_obj = obj_obj->Clone(ConstString("object")).get(); + } + if (m_obj_obj) + return m_obj_obj->GetSP(); + } return lldb::ValueObjectSP(); } @@ -397,14 +404,7 @@ bool LibStdcppSharedPtrSyntheticFrontEnd::Update() { return false; m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get(); - - if (m_ptr_obj) { - Status error; - ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); - if (error.Success()) { - m_obj_obj = obj_obj->Clone(ConstString("object")).get(); - } - } + m_obj_obj = nullptr; return false; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp index aef7cbac603f..f1bfeae5099b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp @@ -69,9 +69,9 @@ bool LibStdcppTupleSyntheticFrontEnd::Update() { for (size_t i = 0; i < child_count; ++i) { ValueObjectSP child_sp = current_child->GetChildAtIndex(i); llvm::StringRef name_str = child_sp->GetName().GetStringRef(); - if (name_str.startswith("std::_Tuple_impl<")) { + if (name_str.starts_with("std::_Tuple_impl<")) { next_child_sp = child_sp; - } else if (name_str.startswith("std::_Head_base<")) { + } else if (name_str.starts_with("std::_Head_base<")) { ValueObjectSP value_sp = child_sp->GetChildMemberWithName("_M_head_impl"); if (value_sp) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp index 7174e9102e1b..a84d641b57bc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp @@ -108,14 +108,7 @@ bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { if (del_obj) m_del_obj = del_obj->Clone(ConstString("deleter")).get(); } - - if (m_ptr_obj) { - Status error; - ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); - if (error.Success()) { - m_obj_obj = obj_obj->Clone(ConstString("object")).get(); - } - } + m_obj_obj = nullptr; return false; } @@ -128,8 +121,17 @@ LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { return m_ptr_obj->GetSP(); if (idx == 1 && m_del_obj) return m_del_obj->GetSP(); - if (idx == 2 && m_obj_obj) - return m_obj_obj->GetSP(); + if (idx == 2) { + if (m_ptr_obj && !m_obj_obj) { + Status error; + ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); + if (error.Success()) { + m_obj_obj = obj_obj->Clone(ConstString("object")).get(); + } + } + if (m_obj_obj) + return m_obj_obj->GetSP(); + } return lldb::ValueObjectSP(); } 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 374ac763ab18..f1a7e04bc9d1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -237,7 +237,8 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if (!process_sp) return false; - ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); + AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>( + ObjCLanguageRuntime::Get(*process_sp)); if (!runtime) return false; @@ -264,20 +265,56 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( do { if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") { + // Foundation version 2000 added a bitmask if the index set fit in 64 bits + // and a Tagged Pointer version if the bitmask is small enough to fit in + // the tagged pointer payload. + // It also changed the layout (but not the size) of the set descriptor. + + // First check whether this is a tagged pointer. The bitmask will be in + // the payload of the tagged pointer. + uint64_t payload; + if (runtime->GetFoundationVersion() >= 2000 + && descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { + count = llvm::popcount(payload); + break; + } + // The first 32 bits describe the index set in all cases: Status error; uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + ptr_size, 4, 0, error); + valobj_addr + ptr_size, 4, 0, error); if (error.Fail()) return false; - // this means the set is empty - count = 0 - if ((mode & 1) == 1) { - count = 0; - break; + // Now check if the index is held in a bitmask in the object: + if (runtime->GetFoundationVersion() >= 2000) { + // The first two bits are "isSingleRange" and "isBitfield". If this is + // a bitfield we handle it here, otherwise set mode appropriately and + // the rest of the treatment is in common. + if ((mode & 2) == 2) { + // The bitfield is a 64 bit uint at the beginning of the data var. + uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory( + valobj_addr + 2 * ptr_size, 8, 0, error); + if (error.Fail()) + return false; + count = llvm::popcount(bitfield); + break; + } + // It wasn't a bitfield, so read the isSingleRange from its new loc: + if ((mode & 1) == 1) + mode = 1; // this means the set only has one range + else + mode = 2; // this means the set has multiple ranges + } else { + // this means the set is empty - count = 0 + if ((mode & 1) == 1) { + count = 0; + break; + } + + if ((mode & 2) == 2) + mode = 1; // this means the set only has one range + else + mode = 2; // this means the set has multiple ranges } - if ((mode & 2) == 2) - mode = 1; // this means the set only has one range - else - mode = 2; // this means the set has multiple ranges if (mode == 1) { count = process_sp->ReadUnsignedIntegerFromMemory( valobj_addr + 3 * ptr_size, ptr_size, 0, error); 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 2e927eb8d856..5ae0751cb065 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -37,7 +37,7 @@ NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix( bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match( ConstString class_name) { - return class_name.GetStringRef().startswith(m_prefix.GetStringRef()); + return class_name.GetStringRef().starts_with(m_prefix.GetStringRef()); } NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n) @@ -78,7 +78,8 @@ static CompilerType GetLLDBNSPairType(TargetSP target_sp) { if (!compiler_type) { compiler_type = scratch_ts_sp->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, - g_lldb_autogen_nspair, clang::TTK_Struct, lldb::eLanguageTypeC); + g_lldb_autogen_nspair, llvm::to_underlying(clang::TagTypeKind::Struct), + lldb::eLanguageTypeC); if (compiler_type) { TypeSystemClang::StartTagDeclarationDefinition(compiler_type); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp index 82b037129c24..742ae7b14945 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -81,9 +81,9 @@ ObjCLanguage::MethodName::Create(llvm::StringRef name, bool strict) { // Figure out type Type type = eTypeUnspecified; - if (name.startswith("+[")) + if (name.starts_with("+[")) type = eTypeClassMethod; - else if (name.startswith("-[")) + else if (name.starts_with("-[")) type = eTypeInstanceMethod; // If there's no type and it's strict, this is invalid 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 bb8057846bb7..a50f4b036108 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h @@ -127,6 +127,8 @@ public: return lldb::eLanguageTypeObjC; } + llvm::StringRef GetUserEntryPointName() const override { return "main"; } + // Get all possible names for a method. Examples: // If method_name is "+[NSString(my_additions) myStringWithCString:]" // variant_names[0] => "+[NSString myStringWithCString:]" 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 b7c71b5dbb1c..1beab9348eb7 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 GetUserEntryPointName() const override { return "main"; } + llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; } bool IsSourceFile(llvm::StringRef file_path) const override; 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 c2488eaa9f5b..300ecc8e8ed5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -34,6 +34,9 @@ using namespace lldb; using namespace lldb_private; static ConstString g_this = ConstString("this"); +// Artificial coroutine-related variables emitted by clang. +static ConstString g_promise = ConstString("__promise"); +static ConstString g_coro_frame = ConstString("__coro_frame"); char CPPLanguageRuntime::ID = 0; @@ -41,7 +44,7 @@ CPPLanguageRuntime::CPPLanguageRuntime(Process *process) : LanguageRuntime(process) {} bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { - return name == g_this; + return name == g_this || name == g_promise || name == g_coro_frame; } bool CPPLanguageRuntime::GetObjectDescription(Stream &str, @@ -217,7 +220,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( llvm::StringRef vtable_name(symbol->GetName().GetStringRef()); bool found_expected_start_string = - vtable_name.startswith("vtable for std::__1::__function::__func<"); + vtable_name.starts_with("vtable for std::__1::__function::__func<"); if (!found_expected_start_string) return optional_info; @@ -274,7 +277,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( } // Case 4 or 5 - if (symbol && !symbol->GetName().GetStringRef().startswith("vtable for") && + if (symbol && !symbol->GetName().GetStringRef().starts_with("vtable for") && !contains_lambda_identifier(first_template_parameter) && !has_invoke) { optional_info.callable_case = LibCppStdFunctionCallableCase::FreeOrMemberFunction; @@ -309,7 +312,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( lldb::FunctionSP func_sp = vtable_cu->FindFunction([name_to_use](const FunctionSP &f) { auto name = f->GetName().GetStringRef(); - if (name.startswith(name_to_use) && name.contains("operator")) + if (name.starts_with(name_to_use) && name.contains("operator")) return true; return false; @@ -370,7 +373,7 @@ CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread, // step into the wrapped callable. // bool found_expected_start_string = - function_name.startswith("std::__1::function<"); + function_name.starts_with("std::__1::function<"); if (!found_expected_start_string) return ret_plan_sp; 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 711a696ff9b4..47b1db16f1e9 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 @@ -54,134 +54,237 @@ bool ItaniumABILanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { check_objc); } -TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( - ValueObject &in_value, lldb::addr_t original_ptr, - lldb::addr_t vtable_load_addr) { - if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS) { - // Find the symbol that contains the "vtable_load_addr" address - Address vtable_addr; - Target &target = m_process->GetTarget(); - if (!target.GetSectionLoadList().IsEmpty()) { - if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, - vtable_addr)) { - // See if we have cached info for this type already - TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr); - if (type_info) - return type_info; - - SymbolContext sc; - target.GetImages().ResolveSymbolContextForAddress( - vtable_addr, eSymbolContextSymbol, sc); - Symbol *symbol = sc.symbol; - if (symbol != nullptr) { - const char *name = - symbol->GetMangled().GetDemangledName().AsCString(); - if (name && strstr(name, vtable_demangled_prefix) == name) { - Log *log = GetLog(LLDBLog::Object); - LLDB_LOGF(log, - "0x%16.16" PRIx64 - ": static-type = '%s' has vtable symbol '%s'\n", - original_ptr, in_value.GetTypeName().GetCString(), name); - // We are a C++ class, that's good. Get the class name and look it - // up: - const char *class_name = name + strlen(vtable_demangled_prefix); - // We know the class name is absolute, so tell FindTypes that by - // prefixing it with the root namespace: - std::string lookup_name("::"); - lookup_name.append(class_name); - - type_info.SetName(class_name); - const bool exact_match = true; - TypeList class_types; - - // First look in the module that the vtable symbol came from and - // look for a single exact match. - llvm::DenseSet<SymbolFile *> searched_symbol_files; - if (sc.module_sp) - sc.module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, - searched_symbol_files, class_types); - - // If we didn't find a symbol, then move on to the entire module - // list in the target and get as many unique matches as possible - if (class_types.Empty()) - target.GetImages().FindTypes(nullptr, ConstString(lookup_name), - exact_match, UINT32_MAX, - searched_symbol_files, class_types); - - lldb::TypeSP type_sp; - if (class_types.Empty()) { - LLDB_LOGF(log, "0x%16.16" PRIx64 ": is not dynamic\n", - original_ptr); - return TypeAndOrName(); +TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfo( + ValueObject &in_value, const VTableInfo &vtable_info) { + if (vtable_info.addr.IsSectionOffset()) { + // See if we have cached info for this type already + TypeAndOrName type_info = GetDynamicTypeInfo(vtable_info.addr); + if (type_info) + return type_info; + + if (vtable_info.symbol) { + Log *log = GetLog(LLDBLog::Object); + llvm::StringRef symbol_name = + vtable_info.symbol->GetMangled().GetDemangledName().GetStringRef(); + LLDB_LOGF(log, + "0x%16.16" PRIx64 + ": static-type = '%s' has vtable symbol '%s'\n", + in_value.GetPointerValue(), + in_value.GetTypeName().GetCString(), + symbol_name.str().c_str()); + // We are a C++ class, that's good. Get the class name and look it + // up: + llvm::StringRef class_name = symbol_name; + class_name.consume_front(vtable_demangled_prefix); + // We know the class name is absolute, so tell FindTypes that by + // prefixing it with the root namespace: + std::string lookup_name("::"); + lookup_name.append(class_name.data(), class_name.size()); + + type_info.SetName(class_name); + ConstString const_lookup_name(lookup_name); + TypeList class_types; + ModuleSP module_sp = vtable_info.symbol->CalculateSymbolContextModule(); + // First look in the module that the vtable symbol came from and + // look for a single exact match. + TypeResults results; + TypeQuery query(const_lookup_name.GetStringRef(), + TypeQueryOptions::e_exact_match | + TypeQueryOptions::e_find_one); + if (module_sp) { + module_sp->FindTypes(query, results); + TypeSP type_sp = results.GetFirstType(); + if (type_sp) + class_types.Insert(type_sp); + } + + // If we didn't find a symbol, then move on to the entire module + // list in the target and get as many unique matches as possible + if (class_types.Empty()) { + query.SetFindOne(false); + m_process->GetTarget().GetImages().FindTypes(nullptr, query, results); + for (const auto &type_sp : results.GetTypeMap().Types()) + class_types.Insert(type_sp); + } + + lldb::TypeSP type_sp; + if (class_types.Empty()) { + LLDB_LOGF(log, "0x%16.16" PRIx64 ": is not dynamic\n", + in_value.GetPointerValue()); + return TypeAndOrName(); + } + if (class_types.GetSize() == 1) { + type_sp = class_types.GetTypeAtIndex(0); + if (type_sp) { + if (TypeSystemClang::IsCXXClassType( + type_sp->GetForwardCompilerType())) { + LLDB_LOGF( + log, + "0x%16.16" PRIx64 + ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 + "}, type-name='%s'\n", + in_value.GetPointerValue(), in_value.GetTypeName().AsCString(), + type_sp->GetID(), type_sp->GetName().GetCString()); + type_info.SetTypeSP(type_sp); + } + } + } else { + size_t i; + if (log) { + for (i = 0; i < class_types.GetSize(); i++) { + type_sp = class_types.GetTypeAtIndex(i); + if (type_sp) { + LLDB_LOGF( + log, + "0x%16.16" PRIx64 + ": static-type = '%s' has multiple matching dynamic " + "types: uid={0x%" PRIx64 "}, type-name='%s'\n", + in_value.GetPointerValue(), + in_value.GetTypeName().AsCString(), + type_sp->GetID(), type_sp->GetName().GetCString()); } - if (class_types.GetSize() == 1) { - type_sp = class_types.GetTypeAtIndex(0); - if (type_sp) { - if (TypeSystemClang::IsCXXClassType( - type_sp->GetForwardCompilerType())) { - LLDB_LOGF( - log, - "0x%16.16" PRIx64 - ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 - "}, type-name='%s'\n", - original_ptr, in_value.GetTypeName().AsCString(), - type_sp->GetID(), type_sp->GetName().GetCString()); - type_info.SetTypeSP(type_sp); - } - } - } else { - size_t i; - if (log) { - for (i = 0; i < class_types.GetSize(); i++) { - type_sp = class_types.GetTypeAtIndex(i); - if (type_sp) { - LLDB_LOGF( - log, - "0x%16.16" PRIx64 - ": static-type = '%s' has multiple matching dynamic " - "types: uid={0x%" PRIx64 "}, type-name='%s'\n", - original_ptr, in_value.GetTypeName().AsCString(), - type_sp->GetID(), type_sp->GetName().GetCString()); - } - } - } - - for (i = 0; i < class_types.GetSize(); i++) { - type_sp = class_types.GetTypeAtIndex(i); - if (type_sp) { - if (TypeSystemClang::IsCXXClassType( - type_sp->GetForwardCompilerType())) { - LLDB_LOGF( - log, - "0x%16.16" PRIx64 ": static-type = '%s' has multiple " - "matching dynamic types, picking " - "this one: uid={0x%" PRIx64 "}, type-name='%s'\n", - original_ptr, in_value.GetTypeName().AsCString(), - type_sp->GetID(), type_sp->GetName().GetCString()); - type_info.SetTypeSP(type_sp); - } - } - } - - if (log) { - LLDB_LOGF(log, - "0x%16.16" PRIx64 - ": static-type = '%s' has multiple matching dynamic " - "types, didn't find a C++ match\n", - original_ptr, in_value.GetTypeName().AsCString()); - } + } + } + + for (i = 0; i < class_types.GetSize(); i++) { + type_sp = class_types.GetTypeAtIndex(i); + if (type_sp) { + if (TypeSystemClang::IsCXXClassType( + type_sp->GetForwardCompilerType())) { + LLDB_LOGF( + log, + "0x%16.16" PRIx64 ": static-type = '%s' has multiple " + "matching dynamic types, picking " + "this one: uid={0x%" PRIx64 "}, type-name='%s'\n", + in_value.GetPointerValue(), + in_value.GetTypeName().AsCString(), + type_sp->GetID(), type_sp->GetName().GetCString()); + type_info.SetTypeSP(type_sp); } - if (type_info) - SetDynamicTypeInfo(vtable_addr, type_info); - return type_info; } } + + if (log) { + LLDB_LOGF(log, + "0x%16.16" PRIx64 + ": static-type = '%s' has multiple matching dynamic " + "types, didn't find a C++ match\n", + in_value.GetPointerValue(), + in_value.GetTypeName().AsCString()); + } } + if (type_info) + SetDynamicTypeInfo(vtable_info.addr, type_info); + return type_info; } } return TypeAndOrName(); } +llvm::Error ItaniumABILanguageRuntime::TypeHasVTable(CompilerType type) { + // Check to make sure the class has a vtable. + CompilerType original_type = type; + if (type.IsPointerOrReferenceType()) { + CompilerType pointee_type = type.GetPointeeType(); + if (pointee_type) + type = pointee_type; + } + + // Make sure this is a class or a struct first by checking the type class + // bitfield that gets returned. + if ((type.GetTypeClass() & (eTypeClassStruct | eTypeClassClass)) == 0) { + return llvm::createStringError(std::errc::invalid_argument, + "type \"%s\" is not a class or struct or a pointer to one", + original_type.GetTypeName().AsCString("<invalid>")); + } + + // Check if the type has virtual functions by asking it if it is polymorphic. + if (!type.IsPolymorphicClass()) { + return llvm::createStringError(std::errc::invalid_argument, + "type \"%s\" doesn't have a vtable", + type.GetTypeName().AsCString("<invalid>")); + } + return llvm::Error::success(); +} + +// This function can accept both pointers or references to classes as well as +// instances of classes. If you are using this function during dynamic type +// detection, only valid ValueObjects that return true to +// CouldHaveDynamicValue(...) should call this function and \a check_type +// should be set to false. This function is also used by ValueObjectVTable +// and is can pass in instances of classes which is not suitable for dynamic +// type detection, these cases should pass true for \a check_type. +llvm::Expected<LanguageRuntime::VTableInfo> + ItaniumABILanguageRuntime::GetVTableInfo(ValueObject &in_value, + bool check_type) { + + CompilerType type = in_value.GetCompilerType(); + if (check_type) { + if (llvm::Error err = TypeHasVTable(type)) + return std::move(err); + } + ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process == nullptr) + return llvm::createStringError(std::errc::invalid_argument, + "invalid process"); + + AddressType address_type; + lldb::addr_t original_ptr = LLDB_INVALID_ADDRESS; + if (type.IsPointerOrReferenceType()) + original_ptr = in_value.GetPointerValue(&address_type); + else + original_ptr = in_value.GetAddressOf(/*scalar_is_load_address=*/true, + &address_type); + if (original_ptr == LLDB_INVALID_ADDRESS || address_type != eAddressTypeLoad) + return llvm::createStringError(std::errc::invalid_argument, + "failed to get the address of the value"); + + Status error; + lldb::addr_t vtable_load_addr = + process->ReadPointerFromMemory(original_ptr, error); + + if (!error.Success() || vtable_load_addr == LLDB_INVALID_ADDRESS) + return llvm::createStringError(std::errc::invalid_argument, + "failed to read vtable pointer from memory at 0x%" PRIx64, + original_ptr); + + // The vtable load address can have authentication bits with + // AArch64 targets on Darwin. + vtable_load_addr = process->FixDataAddress(vtable_load_addr); + + // Find the symbol that contains the "vtable_load_addr" address + Address vtable_addr; + if (!process->GetTarget().ResolveLoadAddress(vtable_load_addr, vtable_addr)) + return llvm::createStringError(std::errc::invalid_argument, + "failed to resolve vtable pointer 0x%" + PRIx64 "to a section", vtable_load_addr); + + // Check our cache first to see if we already have this info + { + std::lock_guard<std::mutex> locker(m_mutex); + auto pos = m_vtable_info_map.find(vtable_addr); + if (pos != m_vtable_info_map.end()) + return pos->second; + } + + Symbol *symbol = vtable_addr.CalculateSymbolContextSymbol(); + if (symbol == nullptr) + return llvm::createStringError(std::errc::invalid_argument, + "no symbol found for 0x%" PRIx64, + vtable_load_addr); + llvm::StringRef name = symbol->GetMangled().GetDemangledName().GetStringRef(); + if (name.starts_with(vtable_demangled_prefix)) { + VTableInfo info = {vtable_addr, symbol}; + std::lock_guard<std::mutex> locker(m_mutex); + auto pos = m_vtable_info_map[vtable_addr] = info; + return info; + } + return llvm::createStringError(std::errc::invalid_argument, + "symbol found that contains 0x%" PRIx64 " is not a vtable symbol", + vtable_load_addr); +} + bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &dynamic_address, @@ -198,33 +301,23 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( class_type_or_name.Clear(); value_type = Value::ValueType::Scalar; - // Only a pointer or reference type can have a different dynamic and static - // type: if (!CouldHaveDynamicValue(in_value)) return false; - // First job, pull out the address at 0 offset from the object. - AddressType address_type; - lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); - if (original_ptr == LLDB_INVALID_ADDRESS) - return false; - - ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); - - Process *process = exe_ctx.GetProcessPtr(); - - if (process == nullptr) - return false; - - Status error; - const lldb::addr_t vtable_address_point = - process->ReadPointerFromMemory(original_ptr, error); - - if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) + // Check if we have a vtable pointer in this value. If we don't it will + // return an error, else it will return a valid resolved address. We don't + // want GetVTableInfo to check the type since we accept void * as a possible + // dynamic type and that won't pass the type check. We already checked the + // type above in CouldHaveDynamicValue(...). + llvm::Expected<VTableInfo> vtable_info_or_err = + GetVTableInfo(in_value, /*check_type=*/false); + if (!vtable_info_or_err) { + llvm::consumeError(vtable_info_or_err.takeError()); return false; + } - class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, - vtable_address_point); + const VTableInfo &vtable_info = vtable_info_or_err.get(); + class_type_or_name = GetTypeInfo(in_value, vtable_info); if (!class_type_or_name) return false; @@ -244,22 +337,27 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( } // The offset_to_top is two pointers above the vtable pointer. - const uint32_t addr_byte_size = process->GetAddressByteSize(); + Target &target = m_process->GetTarget(); + const addr_t vtable_load_addr = vtable_info.addr.GetLoadAddress(&target); + if (vtable_load_addr == LLDB_INVALID_ADDRESS) + return false; + const uint32_t addr_byte_size = m_process->GetAddressByteSize(); const lldb::addr_t offset_to_top_location = - vtable_address_point - 2 * addr_byte_size; + vtable_load_addr - 2 * addr_byte_size; // Watch for underflow, offset_to_top_location should be less than - // vtable_address_point - if (offset_to_top_location >= vtable_address_point) + // vtable_load_addr + if (offset_to_top_location >= vtable_load_addr) return false; - const int64_t offset_to_top = process->ReadSignedIntegerFromMemory( + Status error; + const int64_t offset_to_top = m_process->ReadSignedIntegerFromMemory( offset_to_top_location, addr_byte_size, INT64_MIN, error); if (offset_to_top == INT64_MIN) return false; // So the dynamic type is a value that starts at offset_to_top above // the original address. - lldb::addr_t dynamic_addr = original_ptr + offset_to_top; - if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress( + lldb::addr_t dynamic_addr = in_value.GetPointerValue() + offset_to_top; + if (!m_process->GetTarget().ResolveLoadAddress( dynamic_addr, dynamic_address)) { dynamic_address.SetRawAddress(dynamic_addr); } @@ -339,7 +437,7 @@ public: ~CommandObjectMultiwordItaniumABI_Demangle() override = default; protected: - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { bool demangled_any = false; bool error_any = false; for (auto &entry : command.entries()) { @@ -352,7 +450,7 @@ protected: // on behalf of the user. This is the moral equivalent of the -_/-n // options to c++filt auto name = entry.ref(); - if (name.startswith("__Z")) + if (name.starts_with("__Z")) name = name.drop_front(); Mangled mangled(name); @@ -372,7 +470,6 @@ protected: error_any ? lldb::eReturnStatusFailed : (demangled_any ? lldb::eReturnStatusSuccessFinishResult : lldb::eReturnStatusSuccessFinishNoResult)); - return result.Succeeded(); } }; @@ -516,7 +613,7 @@ bool ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop( return false; uint64_t break_site_id = stop_reason->GetValue(); - return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( + return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint( break_site_id, m_cxx_exception_bp_sp->GetID()); } @@ -583,10 +680,10 @@ ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( ValueObjectSP exception = ValueObject::CreateValueObjectFromData( "exception", exception_isw.GetAsData(m_process->GetByteOrder()), exe_ctx, voidstar); - ValueObjectSP dyn_exception + ValueObjectSP dyn_exception = exception->GetDynamicValue(eDynamicDontRunTarget); // If we succeed in making a dynamic value, return that: - if (dyn_exception) + if (dyn_exception) return dyn_exception; return exception; @@ -594,7 +691,7 @@ ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( TypeAndOrName ItaniumABILanguageRuntime::GetDynamicTypeInfo( const lldb_private::Address &vtable_addr) { - std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); + std::lock_guard<std::mutex> locker(m_mutex); DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr); if (pos == m_dynamic_type_map.end()) return TypeAndOrName(); @@ -604,6 +701,6 @@ TypeAndOrName ItaniumABILanguageRuntime::GetDynamicTypeInfo( void ItaniumABILanguageRuntime::SetDynamicTypeInfo( const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info) { - std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); + std::lock_guard<std::mutex> locker(m_mutex); m_dynamic_type_map[vtable_addr] = type_info; } diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h index ca8d5ab1a93a..0f7e73cfee07 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h @@ -47,6 +47,10 @@ public: return runtime->isA(&ID); } + + llvm::Expected<LanguageRuntime::VTableInfo> + GetVTableInfo(ValueObject &in_value, bool check_type) override; + bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, @@ -71,7 +75,7 @@ public: bool catch_bp, bool throw_bp) override; lldb::SearchFilterSP CreateExceptionSearchFilter() override; - + lldb::ValueObjectSP GetExceptionObjectForThread( lldb::ThreadSP thread_sp) override; @@ -89,24 +93,33 @@ protected: private: typedef std::map<lldb_private::Address, TypeAndOrName> DynamicTypeCache; + typedef std::map<lldb_private::Address, VTableInfo> VTableInfoCache; ItaniumABILanguageRuntime(Process *process) : // Call CreateInstance instead. - lldb_private::CPPLanguageRuntime(process), m_cxx_exception_bp_sp(), - m_dynamic_type_map(), m_dynamic_type_map_mutex() {} + lldb_private::CPPLanguageRuntime(process) {} lldb::BreakpointSP m_cxx_exception_bp_sp; DynamicTypeCache m_dynamic_type_map; - std::mutex m_dynamic_type_map_mutex; + VTableInfoCache m_vtable_info_map; + std::mutex m_mutex; - TypeAndOrName GetTypeInfoFromVTableAddress(ValueObject &in_value, - lldb::addr_t original_ptr, - lldb::addr_t vtable_addr); + TypeAndOrName GetTypeInfo(ValueObject &in_value, + const VTableInfo &vtable_info); TypeAndOrName GetDynamicTypeInfo(const lldb_private::Address &vtable_addr); void SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info); + + // Check if a compiler type has a vtable. + // + // If the compiler type is a pointer or a reference, this function will check + // if the pointee type has a vtable, else it will check the type passed in. + // + // Returns an error if the type of the value doesn't have a vtable with an + // explanation why, or returns an Error::success() if the type has a vtable. + llvm::Error TypeHasVTable(CompilerType compiler_type); }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h index d298af92ba5e..920a5eba20ab 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -77,7 +77,7 @@ protected: void GetIVarInformation(); private: - static const uint32_t RW_REALIZED = (1 << 31); + static const uint32_t RW_REALIZED = (1u << 31); struct objc_class_t { ObjCLanguageRuntime::ObjCISA m_isa = 0; // The class's metaclass. @@ -173,7 +173,8 @@ private: } bool Read(Process *process, lldb::addr_t addr, - lldb::addr_t relative_method_lists_base_addr, bool, bool); + lldb::addr_t relative_selector_base_addr, bool is_small, + bool has_direct_sel); }; struct ivar_list_t { diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index 2764a2aa39fa..5d7c5f38d180 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -311,8 +311,8 @@ public: const bool isSynthesizedAccessorStub = false; const bool isImplicitlyDeclared = true; const bool isDefined = false; - const clang::ObjCMethodDecl::ImplementationControl impControl = - clang::ObjCMethodDecl::None; + const clang::ObjCImplementationControl impControl = + clang::ObjCImplementationControl::None; const bool HasRelatedResultType = false; const bool for_expression = true; 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 80c7bd071d6b..f08f9f0f815d 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 @@ -445,7 +445,7 @@ bool AppleObjCRuntime::ExceptionBreakpointsExplainStop( return false; uint64_t break_site_id = stop_reason->GetValue(); - return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( + return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint( break_site_id, m_objc_exception_bp_sp->GetID()); } 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 65f00f5e4d02..93168c23f354 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 @@ -161,7 +161,7 @@ AppleObjCRuntimeV1::CreateObjectChecker(std::string name, " \n", name.c_str()); assert(strformatsize < (int)sizeof(buf->contents)); - (void)strformatsize; + UNUSED_IF_ASSERT_DISABLED(strformatsize); return GetTargetRef().CreateUtilityFunction(buf->contents, std::move(name), eLanguageTypeC, exe_ctx); 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 d5357b94d68e..dc492ac0f06d 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 @@ -917,7 +917,7 @@ public: Options *GetOptions() override { return &m_options; } protected: - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { std::unique_ptr<RegularExpression> regex_up; switch (command.GetArgumentCount()) { case 0: @@ -929,14 +929,14 @@ protected: result.AppendError( "invalid argument - please provide a valid regular expression"); result.SetStatus(lldb::eReturnStatusFailed); - return false; + return; } break; } default: { result.AppendError("please provide 0 or 1 arguments"); result.SetStatus(lldb::eReturnStatusFailed); - return false; + return; } } @@ -997,11 +997,10 @@ protected: } } result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - return true; + return; } result.AppendError("current process has no Objective-C runtime loaded"); result.SetStatus(lldb::eReturnStatusFailed); - return false; } CommandOptions m_options; @@ -1034,11 +1033,11 @@ public: ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default; protected: - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { if (command.GetArgumentCount() == 0) { result.AppendError("this command requires arguments"); result.SetStatus(lldb::eReturnStatusFailed); - return false; + return; } Process *process = m_exe_ctx.GetProcessPtr(); @@ -1048,7 +1047,7 @@ protected: if (!objc_runtime) { result.AppendError("current process has no Objective-C runtime loaded"); result.SetStatus(lldb::eReturnStatusFailed); - return false; + return; } ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor = @@ -1056,7 +1055,7 @@ protected: if (!tagged_ptr_vendor) { result.AppendError("current process has no tagged pointer support"); result.SetStatus(lldb::eReturnStatusFailed); - return false; + return; } for (size_t i = 0; i < command.GetArgumentCount(); i++) { @@ -1071,7 +1070,7 @@ protected: result.AppendErrorWithFormatv( "could not convert '{0}' to a valid address\n", arg_str); result.SetStatus(lldb::eReturnStatusFailed); - return false; + return; } if (!tagged_ptr_vendor->IsPossibleTaggedPointer(arg_addr)) { @@ -1084,7 +1083,7 @@ protected: result.AppendErrorWithFormatv( "could not get class descriptor for {0:x16}\n", arg_addr); result.SetStatus(lldb::eReturnStatusFailed); - return false; + return; } uint64_t info_bits = 0; @@ -1106,7 +1105,6 @@ protected: } result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - return true; } }; @@ -1399,7 +1397,7 @@ public: return *this; } - const element operator*() const { + element operator*() const { if (m_index == -1) { // TODO find a way to make this an error, but not an assert return element(); @@ -2643,7 +2641,7 @@ static bool DoesProcessHaveSharedCache(Process &process) { return true; // this should not happen llvm::StringRef platform_plugin_name_sr = platform_sp->GetPluginName(); - if (platform_plugin_name_sr.endswith("-simulator")) + if (platform_plugin_name_sr.ends_with("-simulator")) return false; return true; @@ -2733,13 +2731,13 @@ lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) { llvm::StringRef ivar_prefix("OBJC_IVAR_$_"); llvm::StringRef class_prefix("OBJC_CLASS_$_"); - if (name_strref.startswith(ivar_prefix)) { + if (name_strref.starts_with(ivar_prefix)) { llvm::StringRef ivar_skipped_prefix = name_strref.substr(ivar_prefix.size()); std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar = ivar_skipped_prefix.split('.'); - if (class_and_ivar.first.size() && class_and_ivar.second.size()) { + if (!class_and_ivar.first.empty() && !class_and_ivar.second.empty()) { const ConstString class_name_cs(class_and_ivar.first); ClassDescriptorSP descriptor = ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs); @@ -2766,7 +2764,7 @@ lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) { ivar_func); } } - } else if (name_strref.startswith(class_prefix)) { + } else if (name_strref.starts_with(class_prefix)) { llvm::StringRef class_skipped_prefix = name_strref.substr(class_prefix.size()); const ConstString class_name_cs(class_skipped_prefix); 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 678865ecd918..c9d0b3a907b5 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 @@ -65,12 +65,12 @@ public: return ObjCRuntimeVersions::eAppleObjC_V2; } - size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, + size_t GetByteOffsetForIvar(CompilerType &parent_ast_type, const char *ivar_name) override; void UpdateISAToDescriptorMapIfNeeded() override; - ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override; + ClassDescriptorSP GetClassDescriptor(ValueObject &valobj) override; ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) 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 940e66afa0c0..2b8adeae10d1 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 @@ -13,7 +13,6 @@ #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index 2cc5319c84bb..ca582cb1d5a4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -81,13 +81,13 @@ AppleObjCTypeEncodingParser::ReadStructElement(TypeSystemClang &ast_ctx, clang::QualType AppleObjCTypeEncodingParser::BuildStruct( TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) { return BuildAggregate(ast_ctx, type, for_expression, _C_STRUCT_B, _C_STRUCT_E, - clang::TTK_Struct); + llvm::to_underlying(clang::TagTypeKind::Struct)); } clang::QualType AppleObjCTypeEncodingParser::BuildUnion( TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) { return BuildAggregate(ast_ctx, type, for_expression, _C_UNION_B, _C_UNION_E, - clang::TTK_Union); + llvm::to_underlying(clang::TagTypeKind::Union)); } clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index 547a1f6db976..4093cbdd955f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -333,7 +333,7 @@ AppleThreadPlanStepThroughDirectDispatch::DoPlanExplainsStop(Event *event_ptr) { if (site_sp->IsBreakpointAtThisSite(break_sp->GetID())) { // If we aren't the only one with a breakpoint on this site, then we // should just stop and return control to the user. - if (site_sp->GetNumberOfOwners() > 1) { + if (site_sp->GetNumberOfConstituents() > 1) { SetPlanComplete(true); return false; } diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index 214642f654e2..ba52444f0c2f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -10,7 +10,6 @@ #include "ObjCLanguageRuntime.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Core/MappedHash.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" @@ -140,17 +139,10 @@ ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) { if (!module_sp) return TypeSP(); - const bool exact_match = true; - const uint32_t max_matches = UINT32_MAX; - TypeList types; - - llvm::DenseSet<SymbolFile *> searched_symbol_files; - module_sp->FindTypes(name, exact_match, max_matches, searched_symbol_files, - types); - - for (uint32_t i = 0; i < types.GetSize(); ++i) { - TypeSP type_sp(types.GetTypeAtIndex(i)); - + TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_exact_match); + TypeResults results; + module_sp->FindTypes(query, results); + for (const TypeSP &type_sp : results.GetTypeMap().Types()) { if (TypeSystemClang::IsObjCObjectOrInterfaceType( type_sp->GetForwardCompilerType())) { if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) { 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 957ecc223405..7aa5b8d81890 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 @@ -10,7 +10,6 @@ #if defined(_WIN32) || defined(__ANDROID__) // Defines from ar, missing on Windows -#define ARMAG "!<arch>\n" #define SARMAG 8 #define ARFMAG "`\n" @@ -32,9 +31,11 @@ typedef struct ar_hdr { #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" +#include "llvm/Object/Archive.h" #include "llvm/Support/MemoryBuffer.h" using namespace lldb; @@ -49,158 +50,19 @@ ObjectContainerBSDArchive::Object::Object() : ar_name() {} void ObjectContainerBSDArchive::Object::Clear() { ar_name.Clear(); modification_time = 0; - uid = 0; - gid = 0; - mode = 0; size = 0; file_offset = 0; file_size = 0; } -lldb::offset_t ObjectContainerBSDArchive::Object::ExtractFromThin( - const DataExtractor &data, lldb::offset_t offset, - llvm::StringRef stringTable) { - size_t ar_name_len = 0; - std::string str; - char *err; - - // File header - // - // The common format is as follows. - // - // Offset Length Name Format - // 0 16 File name ASCII right padded with spaces (no spaces - // allowed in file name) - // 16 12 File mod Decimal as cstring right padded with - // spaces - // 28 6 Owner ID Decimal as cstring right padded with - // spaces - // 34 6 Group ID Decimal as cstring right padded with - // spaces - // 40 8 File mode Octal as cstring right padded with - // spaces - // 48 10 File byte size Decimal as cstring right padded with - // spaces - // 58 2 File magic 0x60 0x0A - - // Make sure there is enough data for the file header and bail if not - if (!data.ValidOffsetForDataOfSize(offset, 60)) - return LLDB_INVALID_OFFSET; - - str.assign((const char *)data.GetData(&offset, 16), 16); - if (!(llvm::StringRef(str).startswith("//") || stringTable.empty())) { - // Strip off any trailing spaces. - const size_t last_pos = str.find_last_not_of(' '); - if (last_pos != std::string::npos) { - if (last_pos + 1 < 16) - str.erase(last_pos + 1); - } - int start = strtoul(str.c_str() + 1, &err, 10); - int end = stringTable.find('\n', start); - str.assign(stringTable.data() + start, end - start - 1); - ar_name.SetCString(str.c_str()); - } - - str.assign((const char *)data.GetData(&offset, 12), 12); - modification_time = strtoul(str.c_str(), &err, 10); - - str.assign((const char *)data.GetData(&offset, 6), 6); - uid = strtoul(str.c_str(), &err, 10); - - str.assign((const char *)data.GetData(&offset, 6), 6); - gid = strtoul(str.c_str(), &err, 10); - - str.assign((const char *)data.GetData(&offset, 8), 8); - mode = strtoul(str.c_str(), &err, 8); - - str.assign((const char *)data.GetData(&offset, 10), 10); - size = strtoul(str.c_str(), &err, 10); - - str.assign((const char *)data.GetData(&offset, 2), 2); - if (str == ARFMAG) { - file_offset = offset; - file_size = size - ar_name_len; - return offset; - } - return LLDB_INVALID_OFFSET; -} - -lldb::offset_t -ObjectContainerBSDArchive::Object::Extract(const DataExtractor &data, - lldb::offset_t offset) { - size_t ar_name_len = 0; - std::string str; - char *err; - - // File header - // - // The common format is as follows. - // - // Offset Length Name Format - // 0 16 File name ASCII right padded with spaces (no spaces - // allowed in file name) - // 16 12 File mod Decimal as cstring right padded with - // spaces - // 28 6 Owner ID Decimal as cstring right padded with - // spaces - // 34 6 Group ID Decimal as cstring right padded with - // spaces - // 40 8 File mode Octal as cstring right padded with - // spaces - // 48 10 File byte size Decimal as cstring right padded with - // spaces - // 58 2 File magic 0x60 0x0A - - // Make sure there is enough data for the file header and bail if not - if (!data.ValidOffsetForDataOfSize(offset, 60)) - return LLDB_INVALID_OFFSET; - - str.assign((const char *)data.GetData(&offset, 16), 16); - if (llvm::StringRef(str).startswith("#1/")) { - // If the name is longer than 16 bytes, or contains an embedded space then - // it will use this format where the length of the name is here and the - // name characters are after this header. - ar_name_len = strtoul(str.c_str() + 3, &err, 10); - } else { - // Strip off any trailing spaces. - const size_t last_pos = str.find_last_not_of(' '); - if (last_pos != std::string::npos) { - if (last_pos + 1 < 16) - str.erase(last_pos + 1); - } - ar_name.SetCString(str.c_str()); - } - - str.assign((const char *)data.GetData(&offset, 12), 12); - modification_time = strtoul(str.c_str(), &err, 10); - - str.assign((const char *)data.GetData(&offset, 6), 6); - uid = strtoul(str.c_str(), &err, 10); - - str.assign((const char *)data.GetData(&offset, 6), 6); - gid = strtoul(str.c_str(), &err, 10); - - str.assign((const char *)data.GetData(&offset, 8), 8); - mode = strtoul(str.c_str(), &err, 8); - - str.assign((const char *)data.GetData(&offset, 10), 10); - size = strtoul(str.c_str(), &err, 10); - - str.assign((const char *)data.GetData(&offset, 2), 2); - if (str == ARFMAG) { - if (ar_name_len > 0) { - const void *ar_name_ptr = data.GetData(&offset, ar_name_len); - // Make sure there was enough data for the string value and bail if not - if (ar_name_ptr == nullptr) - return LLDB_INVALID_OFFSET; - str.assign((const char *)ar_name_ptr, ar_name_len); - ar_name.SetCString(str.c_str()); - } - file_offset = offset; - file_size = size - ar_name_len; - return offset; - } - return LLDB_INVALID_OFFSET; +void ObjectContainerBSDArchive::Object::Dump() const { + printf("name = \"%s\"\n", ar_name.GetCString()); + printf("mtime = 0x%8.8" PRIx32 "\n", modification_time); + printf("size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n", size, size); + printf("file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n", file_offset, + file_offset); + printf("file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n", file_size, + file_size); } ObjectContainerBSDArchive::Archive::Archive(const lldb_private::ArchSpec &arch, @@ -211,72 +73,79 @@ ObjectContainerBSDArchive::Archive::Archive(const lldb_private::ArchSpec &arch, : m_arch(arch), m_modification_time(time), m_file_offset(file_offset), m_objects(), m_data(data), m_archive_type(archive_type) {} +Log *l = GetLog(LLDBLog::Object); ObjectContainerBSDArchive::Archive::~Archive() = default; size_t ObjectContainerBSDArchive::Archive::ParseObjects() { DataExtractor &data = m_data; - std::string str; - lldb::offset_t offset = 0; - str.assign((const char *)data.GetData(&offset, SARMAG), SARMAG); - if (str == ARMAG) { - Object obj; - do { - offset = obj.Extract(data, offset); - if (offset == LLDB_INVALID_OFFSET) - break; - size_t obj_idx = m_objects.size(); - m_objects.push_back(obj); - // Insert all of the C strings out of order for now... - m_object_name_to_index_map.Append(obj.ar_name, obj_idx); - offset += obj.file_size; - obj.Clear(); - } while (data.ValidOffset(offset)); - - // Now sort all of the object name pointers - m_object_name_to_index_map.Sort(); - } else if (str == ThinArchiveMagic) { - Object obj; - size_t obj_idx; - - // Retrieve symbol table - offset = obj.ExtractFromThin(data, offset, ""); - if (offset == LLDB_INVALID_OFFSET) - return m_objects.size(); - obj_idx = m_objects.size(); - m_objects.push_back(obj); - // Insert all of the C strings out of order for now... - m_object_name_to_index_map.Append(obj.ar_name, obj_idx); - offset += obj.file_size; - obj.Clear(); - // Retrieve string table - offset = obj.ExtractFromThin(data, offset, ""); - if (offset == LLDB_INVALID_OFFSET) - return m_objects.size(); - obj_idx = m_objects.size(); - m_objects.push_back(obj); - // Insert all of the C strings out of order for now... - m_object_name_to_index_map.Append(obj.ar_name, obj_idx); - // Extract string table - llvm::StringRef strtab((const char *)data.GetData(&offset, obj.size), - obj.size); + std::unique_ptr<llvm::MemoryBuffer> mem_buffer = + llvm::MemoryBuffer::getMemBuffer( + llvm::StringRef((const char *)data.GetDataStart(), + data.GetByteSize()), + llvm::StringRef(), + /*RequiresNullTerminator=*/false); + + auto exp_ar = llvm::object::Archive::create(mem_buffer->getMemBufferRef()); + if (!exp_ar) { + LLDB_LOG_ERROR(l, exp_ar.takeError(), "failed to create archive: {0}"); + return 0; + } + auto llvm_archive = std::move(exp_ar.get()); + + llvm::Error iter_err = llvm::Error::success(); + Object obj; + for (const auto &child: llvm_archive->children(iter_err)) { obj.Clear(); + auto exp_name = child.getName(); + if (exp_name) { + obj.ar_name = ConstString(exp_name.get()); + } else { + LLDB_LOG_ERROR(l, exp_name.takeError(), + "failed to get archive object name: {0}"); + continue; + } + + auto exp_mtime = child.getLastModified(); + if (exp_mtime) { + obj.modification_time = + std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::time_point_cast<std::chrono::seconds>( + exp_mtime.get()).time_since_epoch()).count(); + } else { + LLDB_LOG_ERROR(l, exp_mtime.takeError(), + "failed to get archive object time: {0}"); + continue; + } - // Retrieve object files - do { - offset = obj.ExtractFromThin(data, offset, strtab); - if (offset == LLDB_INVALID_OFFSET) - break; - obj_idx = m_objects.size(); - m_objects.push_back(obj); - // Insert all of the C strings out of order for now... - m_object_name_to_index_map.Append(obj.ar_name, obj_idx); - obj.Clear(); - } while (data.ValidOffset(offset)); - - // Now sort all of the object name pointers - m_object_name_to_index_map.Sort(); + auto exp_size = child.getRawSize(); + if (exp_size) { + obj.size = exp_size.get(); + } else { + LLDB_LOG_ERROR(l, exp_size.takeError(), + "failed to get archive object size: {0}"); + continue; + } + + obj.file_offset = child.getDataOffset(); + + auto exp_file_size = child.getSize(); + if (exp_file_size) { + obj.file_size = exp_file_size.get(); + } else { + LLDB_LOG_ERROR(l, exp_file_size.takeError(), + "failed to get archive object file size: {0}"); + continue; + } + m_object_name_to_index_map.Append(obj.ar_name, m_objects.size()); + m_objects.push_back(obj); + } + if (iter_err) { + LLDB_LOG_ERROR(l, std::move(iter_err), + "failed to iterate over archive objects: {0}"); } + // Now sort all of the object name pointers + m_object_name_to_index_map.Sort(); return m_objects.size(); } @@ -462,20 +331,21 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( ArchiveType ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) { uint32_t offset = 0; - const char *armag = (const char *)data.PeekData(offset, sizeof(ar_hdr)); + const char *armag = (const char *)data.PeekData(offset, + sizeof(ar_hdr) + SARMAG); if (armag == nullptr) return ArchiveType::Invalid; - if (::strncmp(armag, ARMAG, SARMAG) == 0) { - armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; - if (strncmp(armag, ARFMAG, 2) == 0) - return ArchiveType::Archive; - } else if (::strncmp(armag, ThinArchiveMagic, strlen(ThinArchiveMagic)) == - 0) { - armag += offsetof(struct ar_hdr, ar_fmag) + strlen(ThinArchiveMagic); - if (strncmp(armag, ARFMAG, 2) == 0) { - return ArchiveType::ThinArchive; - } - } + ArchiveType result = ArchiveType::Invalid; + if (strncmp(armag, ArchiveMagic, SARMAG) == 0) + result = ArchiveType::Archive; + else if (strncmp(armag, ThinArchiveMagic, SARMAG) == 0) + result = ArchiveType::ThinArchive; + else + return ArchiveType::Invalid; + + armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; + if (strncmp(armag, ARFMAG, 2) == 0) + return result; return ArchiveType::Invalid; } @@ -540,7 +410,8 @@ ObjectFileSP ObjectContainerBSDArchive::GetObjectFile(const FileSpec *file) { std::shared_ptr<DataBuffer> child_data_sp = FileSystem::Instance().CreateDataBuffer(child, file_size, file_offset); - if (child_data_sp->GetByteSize() != object->file_size) + if (!child_data_sp || + child_data_sp->GetByteSize() != object->file_size) return ObjectFileSP(); lldb::offset_t data_offset = 0; return ObjectFile::FindPlugin( @@ -622,7 +493,7 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( std::chrono::seconds(object->modification_time)); spec.GetObjectName() = object->ar_name; spec.SetObjectOffset(object_file_offset); - spec.SetObjectSize(file_size - object_file_offset); + spec.SetObjectSize(object->file_size); spec.GetObjectModificationTime() = object_mod_time; } } diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h index 1e2ffce3e5e2..fbecd1d27063 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h @@ -93,15 +93,6 @@ protected: /// Object modification time in the archive. uint32_t modification_time = 0; - /// Object user id in the archive. - uint16_t uid = 0; - - /// Object group id in the archive. - uint16_t gid = 0; - - /// Object octal file permissions in the archive. - uint16_t mode = 0; - /// Object size in bytes in the archive. uint32_t size = 0; @@ -110,6 +101,8 @@ protected: /// Length of the object data. lldb::offset_t file_size = 0; + + void Dump() const; }; class Archive { diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp index 4f9661eb0cdf..2dc71d85777c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp @@ -158,7 +158,7 @@ ParseFileset(DataExtractor &data, mach_header header, if (lc.cmd == LC_FILESET_ENTRY) { fileset_entry_command entry; data.CopyData(load_cmd_offset, sizeof(fileset_entry_command), &entry); - lldb::offset_t entry_id_offset = load_cmd_offset + entry.entry_id; + lldb::offset_t entry_id_offset = load_cmd_offset + entry.entry_id.offset; const char *id = data.GetCStr(&entry_id_offset); entries.emplace_back(entry.vmaddr + slide, entry.fileoff, std::string(id)); diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp index b0afe0394622..d40f87b1a7b4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h" +#include "lldb/lldb-defines.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Endian.h" @@ -119,7 +120,7 @@ static UUID parseModuleId(llvm::Triple::OSType os, llvm::StringRef str) { uint32_t age; bool success = to_integer(age_str, age, 16); assert(success); - (void)success; + UNUSED_IF_ASSERT_DISABLED(success); data.age = age; // On non-windows, the age field should always be zero, so we don't include to diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp index 03c454bf3efa..a7ad5d27b237 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp @@ -271,9 +271,9 @@ void ObjectFileCOFF::ParseSymtab(lldb_private::Symtab &symtab) { const auto COFFSymRef = m_object->getCOFFSymbol(SymRef); Expected<StringRef> NameOrErr = SymRef.getName(); - if (auto error = NameOrErr.takeError()) { - LLDB_LOG(log, "ObjectFileCOFF: failed to get symbol name: {0}", - llvm::fmt_consume(std::move(error))); + if (!NameOrErr) { + LLDB_LOG_ERROR(log, NameOrErr.takeError(), + "ObjectFileCOFF: failed to get symbol name: {0}"); continue; } 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 700af84a14c0..43ab87f08e19 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -935,6 +935,16 @@ lldb_private::Address ObjectFileELF::GetEntryPointAddress() { } Address ObjectFileELF::GetBaseAddress() { + if (GetType() == ObjectFile::eTypeObjectFile) { + for (SectionHeaderCollIter I = std::next(m_section_headers.begin()); + I != m_section_headers.end(); ++I) { + const ELFSectionHeaderInfo &header = *I; + if (header.sh_flags & SHF_ALLOC) + return Address(GetSectionList()->FindSectionByID(SectionIndex(I)), 0); + } + return LLDB_INVALID_ADDRESS; + } + for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) { const ELFProgramHeader &H = EnumPHdr.value(); if (H.p_type != PT_LOAD) @@ -1679,6 +1689,7 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) { .Case(".gnu_debugaltlink", eSectionTypeDWARFGNUDebugAltLink) .Case(".gosymtab", eSectionTypeGoSymtab) .Case(".text", eSectionTypeCode) + .Case(".swift_ast", eSectionTypeSwiftModules) .Default(eSectionTypeOther); } @@ -1763,7 +1774,12 @@ class VMAddressProvider { VMRange GetVMRange(const ELFSectionHeader &H) { addr_t Address = H.sh_addr; addr_t Size = H.sh_flags & SHF_ALLOC ? H.sh_size : 0; - if (ObjectType == ObjectFile::Type::eTypeObjectFile && Segments.empty() && (H.sh_flags & SHF_ALLOC)) { + + // When this is a debug file for relocatable file, the address is all zero + // and thus needs to use accumulate method + if ((ObjectType == ObjectFile::Type::eTypeObjectFile || + (ObjectType == ObjectFile::Type::eTypeDebugInfo && H.sh_addr == 0)) && + Segments.empty() && (H.sh_flags & SHF_ALLOC)) { NextVMAddress = llvm::alignTo(NextVMAddress, std::max<addr_t>(H.sh_addralign, 1)); Address = NextVMAddress; @@ -3453,10 +3469,28 @@ ObjectFile::Strata ObjectFileELF::CalculateStrata() { case llvm::ELF::ET_EXEC: // 2 - Executable file - // TODO: is there any way to detect that an executable is a kernel - // related executable by inspecting the program headers, section headers, - // symbols, or any other flag bits??? - return eStrataUser; + { + SectionList *section_list = GetSectionList(); + if (section_list) { + static ConstString loader_section_name(".interp"); + SectionSP loader_section = + section_list->FindSectionByName(loader_section_name); + if (loader_section) { + char buffer[256]; + size_t read_size = + ReadSectionData(loader_section.get(), 0, buffer, sizeof(buffer)); + + // We compare the content of .interp section + // It will contains \0 when counting read_size, so the size needs to + // decrease by one + llvm::StringRef loader_name(buffer, read_size - 1); + llvm::StringRef freebsd_kernel_loader_name("/red/herring"); + if (loader_name.equals(freebsd_kernel_loader_name)) + return eStrataKernel; + } + } + return eStrataUser; + } case llvm::ELF::ET_DYN: // 3 - Shared object file diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index c396cb061c01..50d1b563f469 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -8,6 +8,7 @@ #include "MinidumpFileBuilder.h" +#include "Plugins/Process/minidump/RegisterContextMinidump_ARM64.h" #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" #include "lldb/Core/Module.h" @@ -293,7 +294,7 @@ Status MinidumpFileBuilder::AddModuleList(Target &target) { } uint16_t read_register_u16_raw(RegisterContext *reg_ctx, - const std::string ®_name) { + llvm::StringRef reg_name) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); if (!reg_info) return 0; @@ -305,7 +306,7 @@ uint16_t read_register_u16_raw(RegisterContext *reg_ctx, } uint32_t read_register_u32_raw(RegisterContext *reg_ctx, - const std::string ®_name) { + llvm::StringRef reg_name) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); if (!reg_info) return 0; @@ -317,7 +318,7 @@ uint32_t read_register_u32_raw(RegisterContext *reg_ctx, } uint64_t read_register_u64_raw(RegisterContext *reg_ctx, - const std::string ®_name) { + llvm::StringRef reg_name) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); if (!reg_info) return 0; @@ -329,25 +330,42 @@ uint64_t read_register_u64_raw(RegisterContext *reg_ctx, } llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx, - const std::string ®_name) { + llvm::StringRef reg_name) { return static_cast<llvm::support::ulittle16_t>( read_register_u16_raw(reg_ctx, reg_name)); } llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx, - const std::string ®_name) { + llvm::StringRef reg_name) { return static_cast<llvm::support::ulittle32_t>( read_register_u32_raw(reg_ctx, reg_name)); } llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx, - const std::string ®_name) { + llvm::StringRef reg_name) { return static_cast<llvm::support::ulittle64_t>( read_register_u64_raw(reg_ctx, reg_name)); } +void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name, + uint8_t *dst) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); + if (reg_info) { + lldb_private::RegisterValue reg_value; + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + Status error; + uint32_t bytes_copied = reg_value.GetAsMemoryData( + *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error); + if (bytes_copied == 16) + return; + } + } + // If anything goes wrong, then zero out the register value. + memset(dst, 0, 16); +} + lldb_private::minidump::MinidumpContext_x86_64 -GetThreadContext_64(RegisterContext *reg_ctx) { +GetThreadContext_x86_64(RegisterContext *reg_ctx) { lldb_private::minidump::MinidumpContext_x86_64 thread_context = {}; thread_context.p1_home = {}; thread_context.context_flags = static_cast<uint32_t>( @@ -381,6 +399,71 @@ GetThreadContext_64(RegisterContext *reg_ctx) { return thread_context; } +minidump::RegisterContextMinidump_ARM64::Context +GetThreadContext_ARM64(RegisterContext *reg_ctx) { + minidump::RegisterContextMinidump_ARM64::Context thread_context = {}; + thread_context.context_flags = static_cast<uint32_t>( + minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag | + minidump::RegisterContextMinidump_ARM64::Flags::Integer | + minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint); + char reg_name[16]; + for (uint32_t i = 0; i < 31; ++i) { + snprintf(reg_name, sizeof(reg_name), "x%u", i); + thread_context.x[i] = read_register_u64(reg_ctx, reg_name); + } + // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt + // name set to "x31" + thread_context.x[31] = read_register_u64(reg_ctx, "sp"); + thread_context.pc = read_register_u64(reg_ctx, "pc"); + thread_context.cpsr = read_register_u32(reg_ctx, "cpsr"); + thread_context.fpsr = read_register_u32(reg_ctx, "fpsr"); + thread_context.fpcr = read_register_u32(reg_ctx, "fpcr"); + for (uint32_t i = 0; i < 32; ++i) { + snprintf(reg_name, sizeof(reg_name), "v%u", i); + read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]); + } + return thread_context; +} + +class ArchThreadContexts { + llvm::Triple::ArchType m_arch; + union { + lldb_private::minidump::MinidumpContext_x86_64 x86_64; + lldb_private::minidump::RegisterContextMinidump_ARM64::Context arm64; + }; + +public: + ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {} + + bool prepareRegisterContext(RegisterContext *reg_ctx) { + switch (m_arch) { + case llvm::Triple::ArchType::x86_64: + x86_64 = GetThreadContext_x86_64(reg_ctx); + return true; + case llvm::Triple::ArchType::aarch64: + arm64 = GetThreadContext_ARM64(reg_ctx); + return true; + default: + break; + } + return false; + } + + const void *data() const { return &x86_64; } + + size_t size() const { + switch (m_arch) { + case llvm::Triple::ArchType::x86_64: + return sizeof(x86_64); + case llvm::Triple::ArchType::aarch64: + return sizeof(arm64); + default: + break; + } + return 0; + } +}; + // Function returns start and size of the memory region that contains // memory location pointed to by the current stack pointer. llvm::Expected<std::pair<addr_t, addr_t>> @@ -434,11 +517,20 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { return error; } RegisterContext *reg_ctx = reg_ctx_sp.get(); - auto thread_context = GetThreadContext_64(reg_ctx); - uint64_t rsp = read_register_u64_raw(reg_ctx, "rsp"); - auto expected_address_range = findStackHelper(process_sp, rsp); + Target &target = process_sp->GetTarget(); + const ArchSpec &arch = target.GetArchitecture(); + ArchThreadContexts thread_context(arch.GetMachine()); + if (!thread_context.prepareRegisterContext(reg_ctx)) { + error.SetErrorStringWithFormat( + "architecture %s not supported.", + arch.GetTriple().getArchName().str().c_str()); + return error; + } + uint64_t sp = reg_ctx->GetSP(); + auto expected_address_range = findStackHelper(process_sp, sp); if (!expected_address_range) { + consumeError(expected_address_range.takeError()); error.SetErrorString("Unable to get the stack address."); return error; } @@ -468,13 +560,13 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { LocationDescriptor thread_context_memory_locator; thread_context_memory_locator.DataSize = - static_cast<llvm::support::ulittle32_t>(sizeof(thread_context)); + static_cast<llvm::support::ulittle32_t>(thread_context.size()); thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( size_before + thread_stream_size + helper_data.GetByteSize()); + // Cache thie thread context memory so we can reuse for exceptions. + m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator; - helper_data.AppendData( - &thread_context, - sizeof(lldb_private::minidump::MinidumpContext_x86_64)); + helper_data.AppendData(thread_context.data(), thread_context.size()); llvm::minidump::Thread t; t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); @@ -492,108 +584,76 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { return Status(); } -Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) { - Status error; +void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) { lldb_private::ThreadList thread_list = process_sp->GetThreadList(); const uint32_t num_threads = thread_list.GetSize(); - uint32_t stop_reason_thread_idx = 0; - for (stop_reason_thread_idx = 0; stop_reason_thread_idx < num_threads; - ++stop_reason_thread_idx) { - ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx)); + for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { + ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); - - if (stop_info_sp && stop_info_sp->IsValid()) - break; - } - - if (stop_reason_thread_idx == num_threads) { - error.SetErrorString("No stop reason thread found."); - return error; + bool add_exception = false; + if (stop_info_sp) { + switch (stop_info_sp->GetStopReason()) { + case eStopReasonSignal: + case eStopReasonException: + add_exception = true; + break; + default: + break; + } + } + if (add_exception) { + constexpr size_t minidump_exception_size = + sizeof(llvm::minidump::ExceptionStream); + AddDirectory(StreamType::Exception, minidump_exception_size); + StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); + RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); + Exception exp_record = {}; + exp_record.ExceptionCode = + static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue()); + exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0); + exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0); + exp_record.ExceptionAddress = reg_ctx_sp->GetPC(); + exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0); + exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); + // exp_record.ExceptionInformation; + + ExceptionStream exp_stream; + exp_stream.ThreadId = + static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); + exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); + exp_stream.ExceptionRecord = exp_record; + auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID()); + if (Iter != m_tid_to_reg_ctx.end()) { + exp_stream.ThreadContext = Iter->second; + } else { + exp_stream.ThreadContext.DataSize = 0; + exp_stream.ThreadContext.RVA = 0; + } + m_data.AppendData(&exp_stream, minidump_exception_size); + } } - - constexpr size_t minidump_exception_size = - sizeof(llvm::minidump::ExceptionStream); - AddDirectory(StreamType::Exception, minidump_exception_size); - size_t size_before = GetCurrentDataEndOffset(); - - ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx)); - RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); - RegisterContext *reg_ctx = reg_ctx_sp.get(); - auto thread_context = GetThreadContext_64(reg_ctx); - StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); - - DataBufferHeap helper_data; - - LocationDescriptor thread_context_memory_locator; - thread_context_memory_locator.DataSize = - static_cast<llvm::support::ulittle32_t>(sizeof(thread_context)); - thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( - size_before + minidump_exception_size + helper_data.GetByteSize()); - - helper_data.AppendData( - &thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64)); - - Exception exp_record = {}; - exp_record.ExceptionCode = - static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue()); - exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0); - exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0); - exp_record.ExceptionAddress = read_register_u64(reg_ctx, "rip"); - exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0); - exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); - // exp_record.ExceptionInformation; - - ExceptionStream exp_stream; - exp_stream.ThreadId = - static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); - exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); - exp_stream.ExceptionRecord = exp_record; - exp_stream.ThreadContext = thread_context_memory_locator; - - m_data.AppendData(&exp_stream, minidump_exception_size); - m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); - return error; } lldb_private::Status -MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp) { +MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp, + lldb::SaveCoreStyle core_style) { Status error; - + Process::CoreFileMemoryRanges core_ranges; + error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges); if (error.Fail()) { error.SetErrorString("Process doesn't support getting memory region info."); return error; } - // Get interesting addresses - std::vector<size_t> interesting_addresses; - auto thread_list = process_sp->GetThreadList(); - for (size_t i = 0; i < thread_list.GetSize(); ++i) { - ThreadSP thread_sp(thread_list.GetThreadAtIndex(i)); - RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); - RegisterContext *reg_ctx = reg_ctx_sp.get(); - - interesting_addresses.push_back(read_register_u64(reg_ctx, "rsp")); - interesting_addresses.push_back(read_register_u64(reg_ctx, "rip")); - } - DataBufferHeap helper_data; std::vector<MemoryDescriptor> mem_descriptors; - - std::set<addr_t> visited_region_base_addresses; - for (size_t interesting_address : interesting_addresses) { - MemoryRegionInfo range_info; - error = process_sp->GetMemoryRegionInfo(interesting_address, range_info); - // Skip failed memory region requests or any regions with no permissions. - if (error.Fail() || range_info.GetLLDBPermissions() == 0) - continue; - const addr_t addr = range_info.GetRange().GetRangeBase(); - // Skip any regions we have already saved out. - if (visited_region_base_addresses.insert(addr).second == false) - continue; - const addr_t size = range_info.GetRange().GetByteSize(); - if (size == 0) + for (const auto &core_range : core_ranges) { + // Skip empty memory regions or any regions with no permissions. + if (core_range.range.empty() || core_range.lldb_permissions == 0) continue; + const addr_t addr = core_range.range.start(); + const addr_t size = core_range.range.size(); auto data_up = std::make_unique<DataBufferHeap>(size, 0); const size_t bytes_read = process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h index f4017fb66384..b2e984191983 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h @@ -17,6 +17,7 @@ #define LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H #include <cstddef> +#include <map> #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" @@ -59,12 +60,11 @@ public: // at the moment of core saving. Contains information about thread // contexts. lldb_private::Status AddThreadList(const lldb::ProcessSP &process_sp); - // Add Exception stream, this contains information about the exception - // that stopped the process. In case no thread made exception it return - // failed status. - lldb_private::Status AddException(const lldb::ProcessSP &process_sp); + // Add Exception streams for any threads that stopped with exceptions. + void AddExceptions(const lldb::ProcessSP &process_sp); // Add MemoryList stream, containing dumps of important memory segments - lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp); + lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp, + lldb::SaveCoreStyle core_style); // Add MiscInfo stream, mainly providing ProcessId void AddMiscInfo(const lldb::ProcessSP &process_sp); // Add informative files about a Linux process @@ -87,6 +87,11 @@ private: // Main data buffer consisting of data without the minidump header and // directories lldb_private::DataBufferHeap m_data; + + // More that one place can mention the register thread context locations, + // so when we emit the thread contents, remember where it is so we don't have + // to duplicate it in the exception data. + std::map<lldb::tid_t, llvm::minidump::LocationDescriptor> m_tid_to_reg_ctx; }; #endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index 17b37afe557d..fe609c7f3d20 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -57,10 +57,9 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp, const lldb_private::FileSpec &outfile, lldb::SaveCoreStyle &core_style, lldb_private::Status &error) { - if (core_style != SaveCoreStyle::eSaveCoreStackOnly) { - error.SetErrorString("Only stack minidumps supported yet."); - return false; - } + // Set default core style if it isn't set. + if (core_style == SaveCoreStyle::eSaveCoreUnspecified) + core_style = SaveCoreStyle::eSaveCoreStackOnly; if (!process_sp) return false; @@ -79,19 +78,16 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp, builder.AddMiscInfo(process_sp); - if (target.GetArchitecture().GetMachine() == llvm::Triple::ArchType::x86_64) { - error = builder.AddThreadList(process_sp); - if (error.Fail()) - return false; + error = builder.AddThreadList(process_sp); + if (error.Fail()) + return false; - error = builder.AddException(process_sp); - if (error.Fail()) - return false; + // Add any exceptions but only if there are any in any threads. + builder.AddExceptions(process_sp); - error = builder.AddMemoryList(process_sp); - if (error.Fail()) - return false; - } + error = builder.AddMemoryList(process_sp, core_style); + if (error.Fail()) + return false; if (target.GetArchitecture().GetTriple().getOS() == llvm::Triple::OSType::Linux) { diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index a3b91fc37dac..f0832dbf0734 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -179,7 +179,7 @@ ObjectFilePDB::loadPDBFile(std::string PdbPath, llvm::StringRef Path = Buffer->getBufferIdentifier(); auto Stream = std::make_unique<llvm::MemoryBufferByteStream>( - std::move(Buffer), llvm::support::little); + std::move(Buffer), llvm::endianness::little); auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator); if (auto EC = File->parseFileHeaders()) { 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 9560ae108f3e..81ee7e328b6c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -74,47 +74,71 @@ llvm::StringRef OperatingSystemPython::GetPluginDescriptionStatic() { OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process, const FileSpec &python_module_path) : OperatingSystem(process), m_thread_list_valobj_sp(), m_register_info_up(), - m_interpreter(nullptr), m_python_object_sp() { + m_interpreter(nullptr), m_script_object_sp() { if (!process) return; TargetSP target_sp = process->CalculateTarget(); if (!target_sp) return; m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); - if (m_interpreter) { - - std::string os_plugin_class_name( - python_module_path.GetFilename().AsCString("")); - if (!os_plugin_class_name.empty()) { - LoadScriptOptions options; - char python_module_path_cstr[PATH_MAX]; - python_module_path.GetPath(python_module_path_cstr, - sizeof(python_module_path_cstr)); - Status error; - if (m_interpreter->LoadScriptingModule(python_module_path_cstr, options, - error)) { - // Strip the ".py" extension if there is one - size_t py_extension_pos = os_plugin_class_name.rfind(".py"); - if (py_extension_pos != std::string::npos) - os_plugin_class_name.erase(py_extension_pos); - // Add ".OperatingSystemPlugIn" to the module name to get a string like - // "modulename.OperatingSystemPlugIn" - os_plugin_class_name += ".OperatingSystemPlugIn"; - StructuredData::ObjectSP object_sp = - m_interpreter->OSPlugin_CreatePluginObject( - os_plugin_class_name.c_str(), process->CalculateProcess()); - if (object_sp && object_sp->IsValid()) - m_python_object_sp = object_sp; - } - } + if (!m_interpreter) + return; + + std::string os_plugin_class_name( + python_module_path.GetFilename().AsCString("")); + if (os_plugin_class_name.empty()) + return; + + LoadScriptOptions options; + char python_module_path_cstr[PATH_MAX]; + python_module_path.GetPath(python_module_path_cstr, + sizeof(python_module_path_cstr)); + Status error; + if (!m_interpreter->LoadScriptingModule(python_module_path_cstr, options, + error)) + return; + + // Strip the ".py" extension if there is one + size_t py_extension_pos = os_plugin_class_name.rfind(".py"); + if (py_extension_pos != std::string::npos) + os_plugin_class_name.erase(py_extension_pos); + // Add ".OperatingSystemPlugIn" to the module name to get a string like + // "modulename.OperatingSystemPlugIn" + os_plugin_class_name += ".OperatingSystemPlugIn"; + + auto operating_system_interface = + m_interpreter->CreateOperatingSystemInterface(); + if (!operating_system_interface) + // FIXME: We should pass an Status& to raise the error to the user. + // return llvm::createStringError( + // llvm::inconvertibleErrorCode(), + // "Failed to create scripted thread interface."); + return; + + ExecutionContext exe_ctx(process); + auto obj_or_err = operating_system_interface->CreatePluginObject( + os_plugin_class_name, exe_ctx, nullptr); + + if (!obj_or_err) { + llvm::consumeError(obj_or_err.takeError()); + return; } + + StructuredData::GenericSP owned_script_object_sp = *obj_or_err; + if (!owned_script_object_sp->IsValid()) + // return llvm::createStringError(llvm::inconvertibleErrorCode(), + // "Created script object is invalid."); + return; + + m_script_object_sp = owned_script_object_sp; + m_operating_system_interface_sp = operating_system_interface; } OperatingSystemPython::~OperatingSystemPython() = default; DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() { if (m_register_info_up == nullptr) { - if (!m_interpreter || !m_python_object_sp) + if (!m_interpreter || !m_operating_system_interface_sp) return nullptr; Log *log = GetLog(LLDBLog::OS); @@ -124,7 +148,7 @@ DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() { m_process->GetID()); StructuredData::DictionarySP dictionary = - m_interpreter->OSPlugin_RegisterInfo(m_python_object_sp); + m_operating_system_interface_sp->GetRegisterInfo(); if (!dictionary) return nullptr; @@ -140,27 +164,11 @@ DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() { bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, ThreadList &core_thread_list, ThreadList &new_thread_list) { - if (!m_interpreter || !m_python_object_sp) + if (!m_interpreter || !m_operating_system_interface_sp) return false; Log *log = GetLog(LLDBLog::OS); - // First thing we have to do is to try to get the API lock, and the - // interpreter lock. We're going to change the thread content of the process, - // and we're going to use python, which requires the API lock to do it. We - // need the interpreter lock to make sure thread_info_dict stays alive. - // - // If someone already has the API lock, that is ok, we just want to avoid - // external code from making new API calls while this call is happening. - // - // This is a recursive lock so we can grant it to any Python code called on - // the stack below us. - Target &target = m_process->GetTarget(); - std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), - std::defer_lock); - (void)api_lock.try_lock(); // See above. - auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); - LLDB_LOGF(log, "OperatingSystemPython::UpdateThreadList() fetching thread " "data from python for pid %" PRIu64, @@ -170,7 +178,7 @@ bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, // the lldb_private::Process subclass, no memory threads will be in this // list. StructuredData::ArraySP threads_list = - m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp); + m_operating_system_interface_sp->GetThreadInfo(); const uint32_t num_cores = core_thread_list.GetSize(false); @@ -281,28 +289,12 @@ RegisterContextSP OperatingSystemPython::CreateRegisterContextForThread(Thread *thread, addr_t reg_data_addr) { RegisterContextSP reg_ctx_sp; - if (!m_interpreter || !m_python_object_sp || !thread) + if (!m_interpreter || !m_script_object_sp || !thread) return reg_ctx_sp; if (!IsOperatingSystemPluginThread(thread->shared_from_this())) return reg_ctx_sp; - // First thing we have to do is to try to get the API lock, and the - // interpreter lock. We're going to change the thread content of the process, - // and we're going to use python, which requires the API lock to do it. We - // need the interpreter lock to make sure thread_info_dict stays alive. - // - // If someone already has the API lock, that is ok, we just want to avoid - // external code from making new API calls while this call is happening. - // - // This is a recursive lock so we can grant it to any Python code called on - // the stack below us. - Target &target = m_process->GetTarget(); - std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), - std::defer_lock); - (void)api_lock.try_lock(); // See above. - auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); - Log *log = GetLog(LLDBLog::Thread); if (reg_data_addr != LLDB_INVALID_ADDRESS) { @@ -324,11 +316,11 @@ OperatingSystemPython::CreateRegisterContextForThread(Thread *thread, ") fetching register data from python", thread->GetID(), thread->GetProtocolID()); - StructuredData::StringSP reg_context_data = - m_interpreter->OSPlugin_RegisterContextData(m_python_object_sp, - thread->GetID()); + std::optional<std::string> reg_context_data = + m_operating_system_interface_sp->GetRegisterContextForTID( + thread->GetID()); if (reg_context_data) { - std::string value = std::string(reg_context_data->GetValue()); + std::string value = *reg_context_data; DataBufferSP data_sp(new DataBufferHeap(value.c_str(), value.length())); if (data_sp->GetByteSize()) { RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory( @@ -347,6 +339,7 @@ OperatingSystemPython::CreateRegisterContextForThread(Thread *thread, "OperatingSystemPython::CreateRegisterContextForThread (tid " "= 0x%" PRIx64 ") forcing a dummy register context", thread->GetID()); + Target &target = m_process->GetTarget(); reg_ctx_sp = std::make_shared<RegisterContextDummy>( *thread, 0, target.GetArchitecture().GetAddressByteSize()); } @@ -372,26 +365,11 @@ lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid, ", context = 0x%" PRIx64 ") fetching register data from python", tid, context); - if (m_interpreter && m_python_object_sp) { - // First thing we have to do is to try to get the API lock, and the - // interpreter lock. We're going to change the thread content of the - // process, and we're going to use python, which requires the API lock to - // do it. We need the interpreter lock to make sure thread_info_dict stays - // alive. - // - // If someone already has the API lock, that is ok, we just want to avoid - // external code from making new API calls while this call is happening. - // - // This is a recursive lock so we can grant it to any Python code called on - // the stack below us. - Target &target = m_process->GetTarget(); - std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), - std::defer_lock); - (void)api_lock.try_lock(); // See above. - auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); + if (m_interpreter && m_script_object_sp) { StructuredData::DictionarySP thread_info_dict = - m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context); + m_operating_system_interface_sp->CreateThread(tid, context); + std::vector<bool> core_used_map; if (thread_info_dict) { ThreadList core_threads(m_process); diff --git a/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h index 7800cf03af8e..90973acde3eb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h +++ b/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h @@ -62,7 +62,7 @@ public: protected: bool IsValid() const { - return m_python_object_sp && m_python_object_sp->IsValid(); + return m_script_object_sp && m_script_object_sp->IsValid(); } lldb::ThreadSP CreateThreadFromThreadInfo( @@ -75,8 +75,9 @@ protected: lldb::ValueObjectSP m_thread_list_valobj_sp; std::unique_ptr<lldb_private::DynamicRegisterInfo> m_register_info_up; - lldb_private::ScriptInterpreter *m_interpreter; - lldb_private::StructuredData::ObjectSP m_python_object_sp; + lldb_private::ScriptInterpreter *m_interpreter = nullptr; + lldb::OperatingSystemInterfaceSP m_operating_system_interface_sp = nullptr; + lldb_private::StructuredData::GenericSP m_script_object_sp = nullptr; }; #endif // LLDB_ENABLE_PYTHON 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 7abc71a1c53f..d7584be2b95e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -206,7 +206,7 @@ CompilerType PlatformFreeBSD::GetSiginfoType(const llvm::Triple &triple) { CompilerType sigval_type = ast->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", - clang::TTK_Union, lldb::eLanguageTypeC); + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); ast->StartTagDeclarationDefinition(sigval_type); ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, lldb::eAccessPublic, 0); @@ -217,7 +217,7 @@ CompilerType PlatformFreeBSD::GetSiginfoType(const llvm::Triple &triple) { // siginfo_t CompilerType siginfo_type = ast->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", - clang::TTK_Struct, lldb::eLanguageTypeC); + llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); ast->StartTagDeclarationDefinition(siginfo_type); ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, lldb::eAccessPublic, 0); @@ -239,7 +239,7 @@ CompilerType PlatformFreeBSD::GetSiginfoType(const llvm::Triple &triple) { // union used to hold the signal data CompilerType union_type = ast->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - clang::TTK_Union, lldb::eLanguageTypeC); + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); ast->StartTagDeclarationDefinition(union_type); ast->AddFieldToRecordType( 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 393519d708d3..ce81aab55706 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -228,7 +228,7 @@ CompilerType PlatformNetBSD::GetSiginfoType(const llvm::Triple &triple) { CompilerType sigval_type = ast->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", - clang::TTK_Union, lldb::eLanguageTypeC); + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); ast->StartTagDeclarationDefinition(sigval_type); ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, lldb::eAccessPublic, 0); @@ -238,7 +238,7 @@ CompilerType PlatformNetBSD::GetSiginfoType(const llvm::Triple &triple) { CompilerType ptrace_option_type = ast->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - clang::TTK_Union, lldb::eLanguageTypeC); + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); ast->StartTagDeclarationDefinition(ptrace_option_type); ast->AddFieldToRecordType(ptrace_option_type, "_pe_other_pid", pid_type, lldb::eAccessPublic, 0); @@ -249,13 +249,13 @@ CompilerType PlatformNetBSD::GetSiginfoType(const llvm::Triple &triple) { // siginfo_t CompilerType siginfo_type = ast->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", - clang::TTK_Union, lldb::eLanguageTypeC); + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); ast->StartTagDeclarationDefinition(siginfo_type); // struct _ksiginfo CompilerType ksiginfo_type = ast->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - clang::TTK_Struct, lldb::eLanguageTypeC); + llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); ast->StartTagDeclarationDefinition(ksiginfo_type); ast->AddFieldToRecordType(ksiginfo_type, "_signo", int_type, lldb::eAccessPublic, 0); @@ -272,7 +272,7 @@ CompilerType PlatformNetBSD::GetSiginfoType(const llvm::Triple &triple) { // union used to hold the signal data CompilerType union_type = ast->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - clang::TTK_Union, lldb::eLanguageTypeC); + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); ast->StartTagDeclarationDefinition(union_type); ast->AddFieldToRecordType( 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 1e91f2ccd198..b4f1b76c39db 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -949,7 +949,7 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, Status PlatformPOSIX::UnloadImage(lldb_private::Process *process, uint32_t image_token) { const addr_t image_addr = process->GetImagePtrFromToken(image_token); - if (image_addr == LLDB_INVALID_ADDRESS) + if (image_addr == LLDB_INVALID_IMAGE_TOKEN) return Status("Invalid image token"); StreamString expr; diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/QemuUser/PlatformQemuUser.cpp b/contrib/llvm-project/lldb/source/Plugins/Platform/QemuUser/PlatformQemuUser.cpp index 72a039d18872..460f5560573d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/QemuUser/PlatformQemuUser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/QemuUser/PlatformQemuUser.cpp @@ -36,7 +36,7 @@ class PluginProperties : public Properties { public: PluginProperties() { m_collection_sp = std::make_shared<OptionValueProperties>( - ConstString(PlatformQemuUser::GetPluginNameStatic())); + PlatformQemuUser::GetPluginNameStatic()); m_collection_sp->Initialize(g_platformqemuuser_properties); } @@ -89,8 +89,8 @@ void PlatformQemuUser::Terminate() { } void PlatformQemuUser::DebuggerInitialize(Debugger &debugger) { - if (!PluginManager::GetSettingForPlatformPlugin( - debugger, ConstString(GetPluginNameStatic()))) { + if (!PluginManager::GetSettingForPlatformPlugin(debugger, + GetPluginNameStatic())) { PluginManager::CreateSettingForPlatformPlugin( debugger, GetGlobalProperties().GetValueProperties(), "Properties for the qemu-user platform plugin.", @@ -162,9 +162,18 @@ lldb::ProcessSP PlatformQemuUser::DebugProcess(ProcessLaunchInfo &launch_info, Target &target, Status &error) { Log *log = GetLog(LLDBLog::Platform); + // If platform.plugin.qemu-user.emulator-path is set, use it. FileSpec qemu = GetGlobalProperties().GetEmulatorPath(); - if (!qemu) - qemu.SetPath(("qemu-" + GetGlobalProperties().GetArchitecture()).str()); + // If platform.plugin.qemu-user.emulator-path is not set, build the + // executable name from platform.plugin.qemu-user.architecture. + if (!qemu) { + llvm::StringRef arch = GetGlobalProperties().GetArchitecture(); + // If platform.plugin.qemu-user.architecture is not set, build the + // executable name from the target Triple's ArchName + if (arch.empty()) + arch = target.GetArchitecture().GetTriple().getArchName(); + qemu.SetPath(("qemu-" + arch).str()); + } FileSystem::Instance().ResolveExecutableLocation(qemu); llvm::SmallString<0> socket_model, socket_path; 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 053d79b8c3b5..88f1ad15b6b4 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 @@ -15,7 +15,6 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" @@ -29,10 +28,12 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/UriParser.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/FormatAdapters.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" +#include <mutex> #include <optional> using namespace lldb; @@ -42,6 +43,11 @@ using namespace lldb_private::platform_gdb_server; LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB) static bool g_initialized = false; +// UnixSignals does not store the signal names or descriptions itself. +// It holds onto StringRefs. Becaue we may get signal information dynamically +// from the remote, these strings need persistent storage client-side. +static std::mutex g_signal_string_mutex; +static llvm::StringSet<> g_signal_string_storage; void PlatformRemoteGDBServer::Initialize() { Platform::Initialize(); @@ -750,8 +756,18 @@ const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() { if (object_sp && object_sp->IsValid()) description = std::string(object_sp->GetStringValue()); - remote_signals_sp->AddSignal(signo, name.str().c_str(), suppress, stop, - notify, description.c_str()); + llvm::StringRef name_backed, description_backed; + { + std::lock_guard<std::mutex> guard(g_signal_string_mutex); + name_backed = + g_signal_string_storage.insert(name).first->getKeyData(); + if (!description.empty()) + description_backed = + g_signal_string_storage.insert(description).first->getKeyData(); + } + + remote_signals_sp->AddSignal(signo, name_backed, suppress, stop, notify, + description_backed); return true; }); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp index 84a009be50bf..19e0986ace31 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp @@ -69,7 +69,7 @@ NativeProcessFreeBSD::Manager::Launch(ProcessLaunchInfo &launch_info, int wstatus; ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); assert(wpid == pid); - (void)wpid; + UNUSED_IF_ASSERT_DISABLED(wpid); if (!WIFSTOPPED(wstatus)) { LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", WaitStatus::Decode(wstatus)); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp index 30eace1ba94f..0019b4d65f15 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp @@ -10,7 +10,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Target/DynamicLoader.h" -#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" +#include "Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h" #include "ProcessFreeBSDKernel.h" #include "ThreadFreeBSDKernel.h" @@ -267,7 +267,7 @@ Status ProcessFreeBSDKernel::DoLoadCore() { DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() { if (m_dyld_up.get() == nullptr) m_dyld_up.reset(DynamicLoader::FindPlugin( - this, DynamicLoaderStatic::GetPluginNameStatic())); + this, DynamicLoaderFreeBSDKernel::GetPluginNameStatic())); return m_dyld_up.get(); } 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 26c562bd4790..451bb4866037 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -379,6 +379,29 @@ void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) { SetState(StateType::eStateStopped, true); } +Status NativeProcessNetBSD::StopProcess(lldb::pid_t pid) { +#ifdef PT_STOP + return PtraceWrapper(PT_STOP, pid); +#else + Log *log = GetLog(POSIXLog::Ptrace); + Status error; + int ret; + + errno = 0; + ret = kill(pid, SIGSTOP); + + if (ret == -1) + error.SetErrorToErrno(); + + LLDB_LOG(log, "kill({0}, SIGSTOP)", pid); + + if (error.Fail()) + LLDB_LOG(log, "kill() failed: {0}", error); + + return error; +#endif +} + Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, int *result) { Log *log = GetLog(POSIXLog::Ptrace); @@ -531,7 +554,7 @@ Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) { return ret; } -Status NativeProcessNetBSD::Halt() { return PtraceWrapper(PT_STOP, GetID()); } +Status NativeProcessNetBSD::Halt() { return StopProcess(GetID()); } Status NativeProcessNetBSD::Detach() { Status error; @@ -555,9 +578,7 @@ Status NativeProcessNetBSD::Signal(int signo) { return error; } -Status NativeProcessNetBSD::Interrupt() { - return PtraceWrapper(PT_STOP, GetID()); -} +Status NativeProcessNetBSD::Interrupt() { return StopProcess(GetID()); } Status NativeProcessNetBSD::Kill() { Log *log = GetLog(POSIXLog::Process); 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 86724fdd5b7e..f3d07651384f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -88,6 +88,7 @@ public: // Interface used by NativeRegisterContext-derived classes. static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, int data = 0, int *result = nullptr); + static Status StopProcess(lldb::pid_t pid); llvm::Expected<std::string> SaveCore(llvm::StringRef path_hint) override; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 0a1f34ec6b4e..32c71d87c7f5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -9,7 +9,6 @@ #include "InferiorCallPOSIX.h" #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/ValueObject.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Host/Config.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 index 817dca336de7..8b5393ca1888 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h @@ -152,6 +152,8 @@ struct user_sve_header { uint16_t reserved; }; +using user_za_header = user_sve_header; + /* Definitions for user_sve_header.flags: */ const uint16_t ptrace_regs_mask = 1 << 0; const uint16_t ptrace_regs_fpsimd = 0; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.h index e6740a304a02..94bad7c19a49 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.h @@ -1,4 +1,4 @@ -//===-- NetBSDSignals.h ----------------------------------------*- C++ -*-===// +//===-- NetBSDSignals.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. diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp index ba089190bd22..a160c87db6cf 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp @@ -1,10 +1,10 @@ -//===-- RegisterContextNetBSD_i386.cpp -------------------------*- C++ -*-===// +//===-- RegisterContextNetBSD_i386.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 "RegisterContextNetBSD_i386.h" #include "RegisterContextPOSIX_x86.h" diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h index b7b8d33b7c37..6f9787506013 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h @@ -1,4 +1,4 @@ -//===-- RegisterContextNetBSD_x86_64.h -------------------------*- C++ -*-===// +//===-- RegisterContextNetBSD_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. 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 d306c818e89f..50e25568f2ae 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 @@ -43,6 +43,10 @@ bool RegisterContextPOSIX_arm64::IsSVE(unsigned reg) const { return m_register_info_up->IsSVEReg(reg); } +bool RegisterContextPOSIX_arm64::IsSME(unsigned reg) const { + return m_register_info_up->IsSMEReg(reg); +} + bool RegisterContextPOSIX_arm64::IsPAuth(unsigned reg) const { return m_register_info_up->IsPAuthReg(reg); } @@ -51,6 +55,10 @@ bool RegisterContextPOSIX_arm64::IsTLS(unsigned reg) const { return m_register_info_up->IsTLSReg(reg); } +bool RegisterContextPOSIX_arm64::IsMTE(unsigned reg) const { + return m_register_info_up->IsMTEReg(reg); +} + RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64( lldb_private::Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info) 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 6a935274fc40..b1226b25b4be 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 @@ -56,12 +56,17 @@ protected: bool IsSVE(unsigned reg) const; bool IsPAuth(unsigned reg) const; bool IsTLS(unsigned reg) const; + bool IsSME(unsigned reg) const; + bool IsMTE(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); } + bool IsSMEZA(unsigned reg) const { + return m_register_info_up->IsSMERegZA(reg); + } uint32_t GetRegNumSVEZ0() const { return m_register_info_up->GetRegNumSVEZ0(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp new file mode 100644 index 000000000000..51553817921f --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp @@ -0,0 +1,202 @@ +//===-- RegisterFlagsLinux_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 "RegisterFlagsLinux_arm64.h" +#include "lldb/lldb-private-types.h" + +// This file is built on all systems because it is used by native processes and +// core files, so we manually define the needed HWCAP values here. + +#define HWCAP_FPHP (1ULL << 9) +#define HWCAP_ASIMDHP (1ULL << 10) +#define HWCAP_DIT (1ULL << 24) +#define HWCAP_SSBS (1ULL << 28) + +#define HWCAP2_BTI (1ULL << 17) +#define HWCAP2_MTE (1ULL << 18) +#define HWCAP2_AFP (1ULL << 20) +#define HWCAP2_EBF16 (1ULL << 32) + +using namespace lldb_private; + +LinuxArm64RegisterFlags::Fields +LinuxArm64RegisterFlags::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) { + (void)hwcap; + (void)hwcap2; + // Represents the pseudo register that lldb-server builds, which itself + // matches the architectural register SCVR. The fields match SVCR in the Arm + // manual. + return { + {"ZA", 1}, + {"SM", 0}, + }; +} + +LinuxArm64RegisterFlags::Fields +LinuxArm64RegisterFlags::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2) { + (void)hwcap; + (void)hwcap2; + // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed + // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines + // used to build the value. + return {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT. + {"TCF_ASYNC", 2}, + {"TCF_SYNC", 1}, + {"TAGGED_ADDR_ENABLE", 0}}; +} + +LinuxArm64RegisterFlags::Fields +LinuxArm64RegisterFlags::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) { + std::vector<RegisterFlags::Field> fpcr_fields{ + {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23}, + // Bits 21-20 are "Stride" which is unused in AArch64 state. + }; + + // FEAT_FP16 is indicated by the presence of FPHP (floating point half + // precision) and ASIMDHP (Advanced SIMD half precision) features. + if ((hwcap & HWCAP_FPHP) && (hwcap & HWCAP_ASIMDHP)) + fpcr_fields.push_back({"FZ16", 19}); + + // Bits 18-16 are "Len" which is unused in AArch64 state. + + fpcr_fields.push_back({"IDE", 15}); + + // Bit 14 is unused. + if (hwcap2 & HWCAP2_EBF16) + fpcr_fields.push_back({"EBF", 13}); + + fpcr_fields.push_back({"IXE", 12}); + fpcr_fields.push_back({"UFE", 11}); + fpcr_fields.push_back({"OFE", 10}); + fpcr_fields.push_back({"DZE", 9}); + fpcr_fields.push_back({"IOE", 8}); + // Bits 7-3 reserved. + + if (hwcap2 & HWCAP2_AFP) { + fpcr_fields.push_back({"NEP", 2}); + fpcr_fields.push_back({"AH", 1}); + fpcr_fields.push_back({"FIZ", 0}); + } + + return fpcr_fields; +} + +LinuxArm64RegisterFlags::Fields +LinuxArm64RegisterFlags::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) { + // fpsr's contents are constant. + (void)hwcap; + (void)hwcap2; + + return { + // Bits 31-28 are N/Z/C/V, only used by AArch32. + {"QC", 27}, + // Bits 26-8 reserved. + {"IDC", 7}, + // Bits 6-5 reserved. + {"IXC", 4}, + {"UFC", 3}, + {"OFC", 2}, + {"DZC", 1}, + {"IOC", 0}, + }; +} + +LinuxArm64RegisterFlags::Fields +LinuxArm64RegisterFlags::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) { + // The fields here are a combination of the Arm manual's SPSR_EL1, + // plus a few changes where Linux has decided not to make use of them at all, + // or at least not from userspace. + + // Status bits that are always present. + std::vector<RegisterFlags::Field> cpsr_fields{ + {"N", 31}, {"Z", 30}, {"C", 29}, {"V", 28}, + // Bits 27-26 reserved. + }; + + if (hwcap2 & HWCAP2_MTE) + cpsr_fields.push_back({"TCO", 25}); + if (hwcap & HWCAP_DIT) + cpsr_fields.push_back({"DIT", 24}); + + // UAO and PAN are bits 23 and 22 and have no meaning for userspace so + // are treated as reserved by the kernel. + + cpsr_fields.push_back({"SS", 21}); + cpsr_fields.push_back({"IL", 20}); + // Bits 19-14 reserved. + + // Bit 13, ALLINT, requires FEAT_NMI that isn't relevant to userspace, and we + // can't detect either, don't show this field. + if (hwcap & HWCAP_SSBS) + cpsr_fields.push_back({"SSBS", 12}); + if (hwcap2 & HWCAP2_BTI) + cpsr_fields.push_back({"BTYPE", 10, 11}); + + cpsr_fields.push_back({"D", 9}); + cpsr_fields.push_back({"A", 8}); + cpsr_fields.push_back({"I", 7}); + cpsr_fields.push_back({"F", 6}); + // Bit 5 reserved + // Called "M" in the ARMARM. + cpsr_fields.push_back({"nRW", 4}); + // This is a 4 bit field M[3:0] in the ARMARM, we split it into parts. + cpsr_fields.push_back({"EL", 2, 3}); + // Bit 1 is unused and expected to be 0. + cpsr_fields.push_back({"SP", 0}); + + return cpsr_fields; +} + +void LinuxArm64RegisterFlags::DetectFields(uint64_t hwcap, uint64_t hwcap2) { + for (auto ® : m_registers) + reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2)); + m_has_detected = true; +} + +void LinuxArm64RegisterFlags::UpdateRegisterInfo(const RegisterInfo *reg_info, + uint32_t num_regs) { + assert(m_has_detected && + "Must call DetectFields before updating register info."); + + // Register names will not be duplicated, so we do not want to compare against + // one if it has already been found. Each time we find one, we erase it from + // this list. + std::vector<std::pair<llvm::StringRef, const RegisterFlags *>> + search_registers; + for (const auto ® : m_registers) { + // It is possible that a register is all extension dependent fields, and + // none of them are present. + if (reg.m_flags.GetFields().size()) + search_registers.push_back({reg.m_name, ®.m_flags}); + } + + // Walk register information while there are registers we know need + // to be updated. Example: + // Register information: [a, b, c, d] + // To be patched: [b, c] + // * a != b, a != c, do nothing and move on. + // * b == b, patch b, new patch list is [c], move on. + // * c == c, patch c, patch list is empty, exit early without looking at d. + for (uint32_t idx = 0; idx < num_regs && search_registers.size(); + ++idx, ++reg_info) { + auto reg_it = std::find_if( + search_registers.cbegin(), search_registers.cend(), + [reg_info](auto reg) { return reg.first == reg_info->name; }); + + if (reg_it != search_registers.end()) { + // Attach the field information. + reg_info->flags_type = reg_it->second; + // We do not expect to see this name again so don't look for it again. + search_registers.erase(reg_it); + } + } + + // We do not assert that search_registers is empty here, because it may + // contain registers from optional extensions that are not present on the + // current target. +}
\ No newline at end of file diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h new file mode 100644 index 000000000000..660bef08700f --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h @@ -0,0 +1,86 @@ +//===-- RegisterFlagsLinux_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_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H + +#include "lldb/Target/RegisterFlags.h" +#include "llvm/ADT/StringRef.h" +#include <functional> + +namespace lldb_private { + +struct RegisterInfo; + +/// This class manages the storage and detection of register field information +/// for Arm64 Linux registers. The same register may have different fields on +/// different CPUs. This class abstracts out the field detection process so we +/// can use it on live processes and core files. +/// +/// The general way to use this class is: +/// * Make an instance somewhere that will last as long as the debug session +/// (because your final register info will point to this instance). +/// * Read hardware capabilities from a core note, binary, prctl, etc. +/// * Pass those to DetectFields. +/// * Call UpdateRegisterInfo with your RegisterInfo to add pointers +/// to the detected fields for all registers listed in this class. +/// +/// This must be done in that order, and you should ensure that if multiple +/// threads will reference the information, a mutex is used to make sure only +/// one calls DetectFields. +class LinuxArm64RegisterFlags { +public: + /// For the registers listed in this class, detect which fields are + /// present. Must be called before UpdateRegisterInfos. + /// If called more than once, fields will be redetected each time from + /// scratch. If you do not have access to hwcap, just pass 0 for each one, you + /// will only get unconditional fields. + void DetectFields(uint64_t hwcap, uint64_t hwcap2); + + /// Add the field information of any registers named in this class, + /// to the relevant RegisterInfo instances. Note that this will be done + /// with a pointer to the instance of this class that you call this on, so + /// the lifetime of that instance must be at least that of the register info. + void UpdateRegisterInfo(const RegisterInfo *reg_info, uint32_t num_regs); + + /// Returns true if field detection has been run at least once. + bool HasDetected() const { return m_has_detected; } + +private: + using Fields = std::vector<RegisterFlags::Field>; + using DetectorFn = std::function<Fields(uint64_t, uint64_t)>; + + static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2); + static Fields DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2); + static Fields DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2); + static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2); + static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2); + + struct RegisterEntry { + RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector) + : m_name(name), m_flags(std::string(name) + "_flags", size, {{"", 0}}), + m_detector(detector) {} + + llvm::StringRef m_name; + RegisterFlags m_flags; + DetectorFn m_detector; + } m_registers[5] = { + RegisterEntry("cpsr", 4, DetectCPSRFields), + RegisterEntry("fpsr", 4, DetectFPSRFields), + RegisterEntry("fpcr", 4, DetectFPCRFields), + RegisterEntry("mte_ctrl", 8, DetectMTECtrlFields), + RegisterEntry("svcr", 8, DetectSVCRFields), + }; + + // Becomes true once field detection has been run for all registers. + bool m_has_detected = false; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H
\ No newline at end of file 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 af5bbda7bfcf..054b7d9b2ec5 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 @@ -79,7 +79,20 @@ static lldb_private::RegisterInfo g_register_infos_mte[] = { DEFINE_EXTENSION_REG(mte_ctrl)}; static lldb_private::RegisterInfo g_register_infos_tls[] = { - DEFINE_EXTENSION_REG(tpidr)}; + DEFINE_EXTENSION_REG(tpidr), + // Only present when SME is present + DEFINE_EXTENSION_REG(tpidr2)}; + +static lldb_private::RegisterInfo g_register_infos_sme[] = { + DEFINE_EXTENSION_REG(svcr), + DEFINE_EXTENSION_REG(svg), + // 16 is a default size we will change later. + {"za", nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, + KIND_ALL_INVALID, nullptr, nullptr, nullptr}}; + +static lldb_private::RegisterInfo g_register_infos_sme2[] = { + {"zt0", nullptr, 64, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, + KIND_ALL_INVALID, nullptr, nullptr, nullptr}}; // Number of register sets provided by this context. enum { @@ -87,8 +100,11 @@ enum { k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1, k_num_sve_registers = sve_ffr - sve_vg + 1, k_num_mte_register = 1, - k_num_tls_register = 1, + // Number of TLS registers is dynamic so it is not listed here. k_num_pauth_register = 2, + // SME2's ZT0 will also be added to this set if present. So this number is + // only for SME1 registers. + k_num_sme_register = 3, k_num_register_sets_default = 2, k_num_register_sets = 3 }; @@ -193,8 +209,10 @@ static const lldb_private::RegisterSet g_reg_set_pauth_arm64 = { static const lldb_private::RegisterSet g_reg_set_mte_arm64 = { "MTE Control Register", "mte", k_num_mte_register, nullptr}; -static const lldb_private::RegisterSet g_reg_set_tls_arm64 = { - "Thread Local Storage Registers", "tls", k_num_tls_register, nullptr}; +// The size of the TLS set is dynamic, so not listed here. + +static const lldb_private::RegisterSet g_reg_set_sme_arm64 = { + "Scalable Matrix Extension Registers", "sme", k_num_sme_register, nullptr}; RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets) @@ -212,7 +230,7 @@ RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( // dynamic register set like MTE, Pointer Authentication regset then we need // to create dynamic register infos and regset array. Push back all optional // register infos and regset and calculate register offsets accordingly. - if (m_opt_regsets.AllSet(eRegsetMaskSVE)) { + if (m_opt_regsets.AnySet(eRegsetMaskSVE | eRegsetMaskSSVE)) { m_register_info_p = g_register_infos_arm64_sve_le; m_register_info_count = sve_ffr + 1; m_per_regset_regnum_range[m_register_set_count++] = @@ -236,9 +254,12 @@ RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( if (m_opt_regsets.AllSet(eRegsetMaskMTE)) AddRegSetMTE(); - // tpidr is always present, but in future there will be others so this is - // done as a dynamic set. - AddRegSetTLS(); + // The TLS set always contains tpidr but only has tpidr2 when SME is + // present. + AddRegSetTLS(m_opt_regsets.AllSet(eRegsetMaskSSVE)); + + if (m_opt_regsets.AnySet(eRegsetMaskSSVE)) + AddRegSetSME(m_opt_regsets.AnySet(eRegsetMaskZT)); m_register_info_count = m_dynamic_reg_infos.size(); m_register_info_p = m_dynamic_reg_infos.data(); @@ -323,22 +344,70 @@ void RegisterInfoPOSIX_arm64::AddRegSetMTE() { m_dynamic_reg_sets.back().registers = m_mte_regnum_collection.data(); } -void RegisterInfoPOSIX_arm64::AddRegSetTLS() { +void RegisterInfoPOSIX_arm64::AddRegSetTLS(bool has_tpidr2) { uint32_t tls_regnum = m_dynamic_reg_infos.size(); - m_tls_regnum_collection.push_back(tls_regnum); - m_dynamic_reg_infos.push_back(g_register_infos_tls[0]); - m_dynamic_reg_infos[tls_regnum].byte_offset = - m_dynamic_reg_infos[tls_regnum - 1].byte_offset + - m_dynamic_reg_infos[tls_regnum - 1].byte_size; - m_dynamic_reg_infos[tls_regnum].kinds[lldb::eRegisterKindLLDB] = tls_regnum; + uint32_t num_regs = has_tpidr2 ? 2 : 1; + for (uint32_t i = 0; i < num_regs; i++) { + m_tls_regnum_collection.push_back(tls_regnum + i); + m_dynamic_reg_infos.push_back(g_register_infos_tls[i]); + m_dynamic_reg_infos[tls_regnum + i].byte_offset = + m_dynamic_reg_infos[tls_regnum + i - 1].byte_offset + + m_dynamic_reg_infos[tls_regnum + i - 1].byte_size; + m_dynamic_reg_infos[tls_regnum + i].kinds[lldb::eRegisterKindLLDB] = + tls_regnum + i; + } m_per_regset_regnum_range[m_register_set_count] = - std::make_pair(tls_regnum, tls_regnum + 1); - m_dynamic_reg_sets.push_back(g_reg_set_tls_arm64); + std::make_pair(tls_regnum, m_dynamic_reg_infos.size()); + m_dynamic_reg_sets.push_back( + {"Thread Local Storage Registers", "tls", num_regs, nullptr}); m_dynamic_reg_sets.back().registers = m_tls_regnum_collection.data(); } -uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLength(uint32_t sve_vq) { +void RegisterInfoPOSIX_arm64::AddRegSetSME(bool has_zt) { + const uint32_t first_sme_regnum = m_dynamic_reg_infos.size(); + uint32_t sme_regnum = first_sme_regnum; + + for (uint32_t i = 0; i < k_num_sme_register; ++i, ++sme_regnum) { + m_sme_regnum_collection.push_back(sme_regnum); + m_dynamic_reg_infos.push_back(g_register_infos_sme[i]); + m_dynamic_reg_infos[sme_regnum].byte_offset = + m_dynamic_reg_infos[sme_regnum - 1].byte_offset + + m_dynamic_reg_infos[sme_regnum - 1].byte_size; + m_dynamic_reg_infos[sme_regnum].kinds[lldb::eRegisterKindLLDB] = sme_regnum; + } + + lldb_private::RegisterSet sme_regset = g_reg_set_sme_arm64; + + if (has_zt) { + m_sme_regnum_collection.push_back(sme_regnum); + m_dynamic_reg_infos.push_back(g_register_infos_sme2[0]); + m_dynamic_reg_infos[sme_regnum].byte_offset = + m_dynamic_reg_infos[sme_regnum - 1].byte_offset + + m_dynamic_reg_infos[sme_regnum - 1].byte_size; + m_dynamic_reg_infos[sme_regnum].kinds[lldb::eRegisterKindLLDB] = sme_regnum; + + sme_regset.num_registers += 1; + } + + m_per_regset_regnum_range[m_register_set_count] = + std::make_pair(first_sme_regnum, m_dynamic_reg_infos.size()); + m_dynamic_reg_sets.push_back(sme_regset); + m_dynamic_reg_sets.back().registers = m_sme_regnum_collection.data(); + + // When vg is written during streaming mode, svg will also change, as vg and + // svg in this state are both showing the streaming vector length. + // We model this as vg invalidating svg. In non-streaming mode this doesn't + // happen but to keep things simple we will invalidate svg anyway. + // + // This must be added now, rather than when vg is defined because SME is a + // dynamic set that may or may not be present. + static uint32_t vg_invalidates[] = {sme_regnum + 1 /*svg*/, + LLDB_INVALID_REGNUM}; + m_dynamic_reg_infos[GetRegNumSVEVG()].invalidate_regs = vg_invalidates; +} + +uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLengthSVE(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 @@ -402,6 +471,20 @@ uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLength(uint32_t sve_vq) { return m_vector_reg_vq; } +void RegisterInfoPOSIX_arm64::ConfigureVectorLengthZA(uint32_t za_vq) { + if (!VectorSizeIsValid(za_vq) || m_za_reg_vq == za_vq) + return; + + m_za_reg_vq = za_vq; + + // For SVE changes, we replace m_register_info_p completely. ZA is in a + // dynamic set and is just 1 register so we make an exception to const here. + lldb_private::RegisterInfo *non_const_reginfo = + const_cast<lldb_private::RegisterInfo *>(m_register_info_p); + non_const_reginfo[m_sme_regnum_collection[2]].byte_size = + (za_vq * 16) * (za_vq * 16); +} + bool RegisterInfoPOSIX_arm64::IsSVEReg(unsigned reg) const { if (m_vector_reg_vq > eVectorQuadwordAArch64) return (sve_vg <= reg && reg <= sve_ffr); @@ -421,6 +504,16 @@ bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const { return sve_vg == reg; } +bool RegisterInfoPOSIX_arm64::IsSMERegZA(unsigned reg) const { + return reg == m_sme_regnum_collection[2]; +} + +bool RegisterInfoPOSIX_arm64::IsSMERegZT(unsigned reg) const { + // ZT0 is part of the SME register set only if SME2 is present. + return m_sme_regnum_collection.size() >= 4 && + reg == m_sme_regnum_collection[3]; +} + bool RegisterInfoPOSIX_arm64::IsPAuthReg(unsigned reg) const { return llvm::is_contained(pauth_regnum_collection, reg); } @@ -433,6 +526,10 @@ bool RegisterInfoPOSIX_arm64::IsTLSReg(unsigned reg) const { return llvm::is_contained(m_tls_regnum_collection, reg); } +bool RegisterInfoPOSIX_arm64::IsSMEReg(unsigned reg) const { + return llvm::is_contained(m_sme_regnum_collection, reg); +} + uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; } uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; } @@ -443,6 +540,10 @@ uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; } uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEVG() const { return sve_vg; } +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSMESVG() const { + return m_sme_regnum_collection[1]; +} + uint32_t RegisterInfoPOSIX_arm64::GetPAuthOffset() const { return m_register_info_p[pauth_regnum_collection[0]].byte_offset; } @@ -454,3 +555,7 @@ uint32_t RegisterInfoPOSIX_arm64::GetMTEOffset() const { uint32_t RegisterInfoPOSIX_arm64::GetTLSOffset() const { return m_register_info_p[m_tls_regnum_collection[0]].byte_offset; } + +uint32_t RegisterInfoPOSIX_arm64::GetSMEOffset() const { + return m_register_info_p[m_sme_regnum_collection[0]].byte_offset; +} 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 20cfe732c6c2..3b8171042c73 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 @@ -15,7 +15,7 @@ #include "lldb/lldb-private.h" #include <map> -enum class SVEState { Unknown, Disabled, FPSIMD, Full }; +enum class SVEState : uint8_t { Unknown, Disabled, FPSIMD, Full, Streaming }; class RegisterInfoPOSIX_arm64 : public lldb_private::RegisterInfoAndSetInterface { @@ -26,9 +26,12 @@ public: enum { eRegsetMaskDefault = 0, eRegsetMaskSVE = 1, - eRegsetMaskPAuth = 2, - eRegsetMaskMTE = 4, - eRegsetMaskTLS = 8, + eRegsetMaskSSVE = 2, + eRegsetMaskPAuth = 4, + eRegsetMaskMTE = 8, + eRegsetMaskTLS = 16, + eRegsetMaskZA = 32, + eRegsetMaskZT = 64, eRegsetMaskDynamic = ~1, }; @@ -103,9 +106,13 @@ public: void AddRegSetMTE(); - void AddRegSetTLS(); + void AddRegSetTLS(bool has_tpidr2); - uint32_t ConfigureVectorLength(uint32_t sve_vq); + void AddRegSetSME(bool has_zt); + + uint32_t ConfigureVectorLengthSVE(uint32_t sve_vq); + + void ConfigureVectorLengthZA(uint32_t za_vq); bool VectorSizeIsValid(uint32_t vq) { // coverity[unsigned_compare] @@ -114,10 +121,13 @@ public: return false; } - bool IsSVEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskSVE); } - bool IsPAuthEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskPAuth); } - bool IsMTEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskMTE); } - bool IsTLSEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskTLS); } + bool IsSVEPresent() const { return m_opt_regsets.AnySet(eRegsetMaskSVE); } + bool IsSSVEPresent() const { return m_opt_regsets.AnySet(eRegsetMaskSSVE); } + bool IsZAPresent() const { return m_opt_regsets.AnySet(eRegsetMaskZA); } + bool IsZTPresent() const { return m_opt_regsets.AnySet(eRegsetMaskZT); } + bool IsPAuthPresent() const { return m_opt_regsets.AnySet(eRegsetMaskPAuth); } + bool IsMTEPresent() const { return m_opt_regsets.AnySet(eRegsetMaskMTE); } + bool IsTLSPresent() const { return m_opt_regsets.AnySet(eRegsetMaskTLS); } bool IsSVEReg(unsigned reg) const; bool IsSVEZReg(unsigned reg) const; @@ -126,15 +136,20 @@ public: bool IsPAuthReg(unsigned reg) const; bool IsMTEReg(unsigned reg) const; bool IsTLSReg(unsigned reg) const; + bool IsSMEReg(unsigned reg) const; + bool IsSMERegZA(unsigned reg) const; + bool IsSMERegZT(unsigned reg) const; uint32_t GetRegNumSVEZ0() const; uint32_t GetRegNumSVEFFR() const; uint32_t GetRegNumFPCR() const; uint32_t GetRegNumFPSR() const; uint32_t GetRegNumSVEVG() const; + uint32_t GetRegNumSMESVG() const; uint32_t GetPAuthOffset() const; uint32_t GetMTEOffset() const; uint32_t GetTLSOffset() const; + uint32_t GetSMEOffset() const; private: typedef std::map<uint32_t, std::vector<lldb_private::RegisterInfo>> @@ -143,7 +158,10 @@ private: per_vq_register_infos m_per_vq_reg_infos; uint32_t m_vector_reg_vq = eVectorQuadwordAArch64; + uint32_t m_za_reg_vq = eVectorQuadwordAArch64; + // In normal operation this is const. Only when SVE or SME registers change + // size is it either replaced or the content modified. const lldb_private::RegisterInfo *m_register_info_p; uint32_t m_register_info_count; @@ -162,6 +180,7 @@ private: std::vector<uint32_t> pauth_regnum_collection; std::vector<uint32_t> m_mte_regnum_collection; std::vector<uint32_t> m_tls_regnum_collection; + std::vector<uint32_t> m_sme_regnum_collection; }; #endif diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h index 39428bdd0a08..b111d8f62d1f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h @@ -71,15 +71,6 @@ nullptr, nullptr, \ } -// Note that the size and offset will be updated by platform-specific classes. -#define DEFINE_GPR_WITH_BASE(reg, alt, kind1, kind2, kind3, kind4) \ - { \ - #reg, alt, sizeof(((GPR *)nullptr)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, \ - {kind1, kind2, kind3, kind4, x86_64_with_base::lldb_##reg}, nullptr, \ - nullptr, nullptr, \ - } - #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ { \ #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ @@ -224,8 +215,8 @@ static RegisterInfo g_register_infos_x86_64_with_base[] = { DEFINE_GPR(fs, nullptr, dwarf_fs_x86_64, dwarf_fs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(gs, nullptr, dwarf_gs_x86_64, dwarf_gs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ss, nullptr, dwarf_ss_x86_64, dwarf_ss_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(fs_base, nullptr, dwarf_fs_base_x86_64, dwarf_fs_base_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(gs_base, nullptr, dwarf_gs_base_x86_64, dwarf_gs_base_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(fs_base,nullptr, dwarf_fs_base_x86_64, dwarf_fs_base_x86_64, LLDB_REGNUM_GENERIC_TP, LLDB_INVALID_REGNUM), + DEFINE_GPR(gs_base,nullptr, dwarf_gs_base_x86_64, dwarf_gs_base_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ds, nullptr, dwarf_ds_x86_64, dwarf_ds_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(es, nullptr, dwarf_es_x86_64, dwarf_es_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index d60e6250c7c0..565941d3168f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -491,14 +491,13 @@ static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target, uint64_t exc_sub_sub_code) { // Try hardware watchpoint. if (target) { + // LWP_TODO: We need to find the WatchpointResource that matches + // the address, and evaluate its Watchpoints. + // The exc_sub_code indicates the data break address. lldb::WatchpointSP wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); if (wp_sp && wp_sp->IsEnabled()) { - // Debugserver may piggyback the hardware index of the fired watchpoint - // in the exception data. Set the hardware index if that's the case. - if (exc_data_count >= 3) - wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); } } @@ -511,10 +510,6 @@ static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target, process_sp->GetBreakpointSiteList().FindByAddress( (lldb::addr_t)exc_sub_code); if (bp_sp && bp_sp->IsEnabled()) { - // Debugserver may piggyback the hardware index of the fired breakpoint - // in the exception data. Set the hardware index if that's the case. - if (exc_data_count >= 3) - bp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithBreakpointSiteID(thread, bp_sp->GetID()); } @@ -674,6 +669,9 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( case llvm::Triple::thumb: if (exc_code == 0x102) // EXC_ARM_DA_DEBUG { + // LWP_TODO: We need to find the WatchpointResource that matches + // the address, and evaluate its Watchpoints. + // It's a watchpoint, then, if the exc_sub_code indicates a // known/enabled data break address from our watchpoint list. lldb::WatchpointSP wp_sp; @@ -681,11 +679,6 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( wp_sp = target->GetWatchpointList().FindByAddress( (lldb::addr_t)exc_sub_code); if (wp_sp && wp_sp->IsEnabled()) { - // Debugserver may piggyback the hardware index of the fired - // watchpoint in the exception data. Set the hardware index if - // that's the case. - if (exc_data_count >= 3) - wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); } else { @@ -755,6 +748,9 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( } if (exc_code == 0x102) // EXC_ARM_DA_DEBUG { + // LWP_TODO: We need to find the WatchpointResource that matches + // the address, and evaluate its Watchpoints. + // It's a watchpoint, then, if the exc_sub_code indicates a // known/enabled data break address from our watchpoint list. lldb::WatchpointSP wp_sp; @@ -762,11 +758,6 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( wp_sp = target->GetWatchpointList().FindByAddress( (lldb::addr_t)exc_sub_code); if (wp_sp && wp_sp->IsEnabled()) { - // Debugserver may piggyback the hardware index of the fired - // watchpoint in the exception data. Set the hardware index if - // that's the case. - if (exc_data_count >= 3) - wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); } 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 bfb59eceb2d0..7723009787f7 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 @@ -53,7 +53,7 @@ lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp, bool can_connect) { lldb::ProcessSP process_sp; if (crash_file && !can_connect) { - // Read enough data for a ELF32 header or ELF64 header Note: Here we care + // Read enough data for an 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. const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr); @@ -108,7 +108,7 @@ ProcessElfCore::~ProcessElfCore() { // make sure all of the broadcaster cleanup goes as planned. If we destruct // this class, then Process::~Process() might have problems trying to fully // destroy the broadcaster. - Finalize(); + Finalize(true /* destructing */); } lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment( @@ -131,7 +131,7 @@ lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment( m_core_aranges.Append(range_entry); } } - // Keep a separate map of permissions that that isn't coalesced so all ranges + // Keep a separate map of permissions that isn't coalesced so all ranges // are maintained. const uint32_t permissions = ((header.p_flags & llvm::ELF::PF_R) ? lldb::ePermissionsReadable : 0u) | @@ -832,7 +832,7 @@ llvm::Error ProcessElfCore::parseOpenBSDNotes(llvm::ArrayRef<CoreNote> notes) { for (const auto ¬e : notes) { // OpenBSD per-thread information is stored in notes named "OpenBSD@nnn" so // match on the initial part of the string. - if (!llvm::StringRef(note.info.n_name).startswith("OpenBSD")) + if (!llvm::StringRef(note.info.n_name).starts_with("OpenBSD")) continue; switch (note.info.n_type) { 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 38abd8f8f2b1..07501c10ec3c 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 @@ -9,6 +9,9 @@ #include "RegisterContextPOSIXCore_arm64.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" +#include "Plugins/Process/Utility/AuxVector.h" +#include "Plugins/Process/Utility/RegisterFlagsLinux_arm64.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/RegisterValue.h" @@ -23,8 +26,13 @@ RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch, llvm::ArrayRef<CoreNote> notes) { Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskDefault; + DataExtractor ssve_data = + getRegset(notes, arch.GetTriple(), AARCH64_SSVE_Desc); + if (ssve_data.GetByteSize() >= sizeof(sve::user_sve_header)) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSSVE); + DataExtractor sve_data = getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc); - if (sve_data.GetByteSize() > sizeof(sve::user_sve_header)) + if (sve_data.GetByteSize() >= sizeof(sve::user_sve_header)) opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE); // Pointer Authentication register set data is based on struct @@ -40,6 +48,22 @@ RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch, if (tls_data.GetByteSize() >= sizeof(uint64_t)) opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS); + DataExtractor za_data = getRegset(notes, arch.GetTriple(), AARCH64_ZA_Desc); + // Nothing if ZA is not present, just the header if it is disabled. + if (za_data.GetByteSize() >= sizeof(sve::user_za_header)) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZA); + + DataExtractor mte_data = getRegset(notes, arch.GetTriple(), AARCH64_MTE_Desc); + if (mte_data.GetByteSize() >= sizeof(uint64_t)) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE); + + DataExtractor zt_data = getRegset(notes, arch.GetTriple(), AARCH64_ZT_Desc); + // Although ZT0 can be in a disabled state like ZA can, the kernel reports + // its content as 0s in that state. Therefore even a disabled ZT0 will have + // a note containing those 0s. ZT0 is a 512 bit / 64 byte register. + if (zt_data.GetByteSize() >= 64) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZT); + auto register_info_up = std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets); return std::unique_ptr<RegisterContextCorePOSIX_arm64>( @@ -51,6 +75,23 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info, const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes) : RegisterContextPOSIX_arm64(thread, std::move(register_info)) { + ::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs)); + + ProcessElfCore *process = + static_cast<ProcessElfCore *>(thread.GetProcess().get()); + if (process->GetArchitecture().GetTriple().getOS() == llvm::Triple::Linux) { + AuxVector aux_vec(process->GetAuxvData()); + std::optional<uint64_t> auxv_at_hwcap = + aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP); + std::optional<uint64_t> auxv_at_hwcap2 = + aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2); + + m_linux_register_flags.DetectFields(auxv_at_hwcap.value_or(0), + auxv_at_hwcap2.value_or(0)); + m_linux_register_flags.UpdateRegisterInfo(GetRegisterInfo(), + GetRegisterCount()); + } + m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(), gpregset.GetByteSize())); m_gpr_data.SetByteOrder(gpregset.GetByteOrder()); @@ -59,15 +100,32 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( m_register_info_up->GetTargetArchitecture().GetTriple(); m_fpr_data = getRegset(notes, target_triple, FPR_Desc); - if (m_register_info_up->IsSVEEnabled()) + if (m_register_info_up->IsSSVEPresent()) { + m_sve_data = getRegset(notes, target_triple, AARCH64_SSVE_Desc); + lldb::offset_t flags_offset = 12; + uint16_t flags = m_sve_data.GetU32(&flags_offset); + if ((flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve) + m_sve_state = SVEState::Streaming; + } + + if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent()) m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc); - if (m_register_info_up->IsPAuthEnabled()) + if (m_register_info_up->IsPAuthPresent()) m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc); - if (m_register_info_up->IsTLSEnabled()) + if (m_register_info_up->IsTLSPresent()) m_tls_data = getRegset(notes, target_triple, AARCH64_TLS_Desc); + if (m_register_info_up->IsZAPresent()) + m_za_data = getRegset(notes, target_triple, AARCH64_ZA_Desc); + + if (m_register_info_up->IsMTEPresent()) + m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc); + + if (m_register_info_up->IsZTPresent()) + m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc); + ConfigureRegisterContext(); } @@ -95,15 +153,18 @@ void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) { uint64_t sve_header_field_offset = 8; m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset); - sve_header_field_offset = 12; - uint16_t sve_header_flags_field = - m_sve_data.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 (m_sve_state != SVEState::Streaming) { + sve_header_field_offset = 12; + uint16_t sve_header_flags_field = + m_sve_data.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_sve_state = SVEState::Disabled; @@ -113,8 +174,25 @@ void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { m_sve_state = SVEState::Disabled; if (m_sve_state != SVEState::Disabled) - m_register_info_up->ConfigureVectorLength( + m_register_info_up->ConfigureVectorLengthSVE( sve::vq_from_vl(m_sve_vector_length)); + + if (m_sve_state == SVEState::Streaming) + m_sme_pseudo_regs.ctrl_reg |= 1; + + if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) { + lldb::offset_t vlen_offset = 8; + uint16_t svl = m_za_data.GetU16(&vlen_offset); + m_sme_pseudo_regs.svg_reg = svl / 8; + m_register_info_up->ConfigureVectorLengthZA(svl / 16); + + // If there is register data then ZA is active. The size of the note may be + // misleading here so we use the size field of the embedded header. + lldb::offset_t size_offset = 0; + uint32_t size = m_za_data.GetU32(&size_offset); + if (size > sizeof(sve::user_za_header)) + m_sme_pseudo_regs.ctrl_reg |= 1 << 1; + } } uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset( @@ -124,7 +202,8 @@ uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset( 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) { + } else if (m_sve_state == SVEState::Full || + m_sve_state == SVEState::Streaming) { uint32_t sve_z0_offset = GetGPRSize() + 16; sve_reg_offset = sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset; @@ -140,11 +219,9 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, offset = reg_info->byte_offset; if (offset + reg_info->byte_size <= GetGPRSize()) { - uint64_t v = m_gpr_data.GetMaxU64(&offset, reg_info->byte_size); - if (offset == reg_info->byte_offset + reg_info->byte_size) { - value = v; - return true; - } + value.SetFromMemoryData(*reg_info, m_gpr_data.GetDataStart() + offset, + reg_info->byte_size, lldb::eByteOrderLittle, error); + return error.Success(); } const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; @@ -163,19 +240,19 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, } } 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. + // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming 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) + if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming) 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) + if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming) 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; @@ -217,6 +294,7 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, error); } break; case SVEState::Full: + case SVEState::Streaming: offset = CalculateSVEOffset(reg_info); assert(offset < m_sve_data.GetByteSize()); value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset), @@ -237,6 +315,59 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, assert(offset < m_tls_data.GetByteSize()); value.SetFromMemoryData(*reg_info, m_tls_data.GetDataStart() + offset, reg_info->byte_size, lldb::eByteOrderLittle, error); + } else if (IsMTE(reg)) { + offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset(); + assert(offset < m_mte_data.GetByteSize()); + value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset, + reg_info->byte_size, lldb::eByteOrderLittle, error); + } else if (IsSME(reg)) { + // If you had SME in the process, active or otherwise, there will at least + // be a ZA header. No header, no SME at all. + if (m_za_data.GetByteSize() < sizeof(sve::user_za_header)) + return false; + + if (m_register_info_up->IsSMERegZA(reg)) { + // Don't use the size of the note to tell whether ZA is enabled. There may + // be non-register padding data after the header. Use the embedded + // header's size field instead. + lldb::offset_t size_offset = 0; + uint32_t size = m_za_data.GetU32(&size_offset); + bool za_enabled = size > sizeof(sve::user_za_header); + + size_t za_note_size = m_za_data.GetByteSize(); + // For a disabled ZA we fake a value of all 0s. + if (!za_enabled) { + uint64_t svl = m_sme_pseudo_regs.svg_reg * 8; + za_note_size = sizeof(sve::user_za_header) + (svl * svl); + } + + const uint8_t *src = nullptr; + std::vector<uint8_t> disabled_za_data; + + if (za_enabled) + src = m_za_data.GetDataStart(); + else { + disabled_za_data.resize(za_note_size); + std::fill(disabled_za_data.begin(), disabled_za_data.end(), 0); + src = disabled_za_data.data(); + } + + value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header), + reg_info->byte_size, lldb::eByteOrderLittle, + error); + } else if (m_register_info_up->IsSMERegZT(reg)) { + value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(), + reg_info->byte_size, lldb::eByteOrderLittle, + error); + } else { + offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset(); + assert(offset < sizeof(m_sme_pseudo_regs)); + // Host endian since these values are derived instead of being read from a + // core file note. + value.SetFromMemoryData( + *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset, + reg_info->byte_size, lldb_private::endian::InlHostByteOrder(), error); + } } else return false; 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 5e0e29f0de7f..38e958851dfe 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 @@ -11,6 +11,7 @@ #include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" +#include "Plugins/Process/Utility/RegisterFlagsLinux_arm64.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Utility/DataBufferHeap.h" @@ -58,10 +59,24 @@ private: lldb_private::DataExtractor m_sve_data; lldb_private::DataExtractor m_pac_data; lldb_private::DataExtractor m_tls_data; + lldb_private::DataExtractor m_za_data; + lldb_private::DataExtractor m_mte_data; + lldb_private::DataExtractor m_zt_data; - SVEState m_sve_state; + SVEState m_sve_state = SVEState::Unknown; uint16_t m_sve_vector_length = 0; + // These are pseudo registers derived from the values in SSVE and ZA data. + struct __attribute__((packed)) sme_pseudo_regs { + uint64_t ctrl_reg; + uint64_t svg_reg; + }; + static_assert(sizeof(sme_pseudo_regs) == 16); + + struct sme_pseudo_regs m_sme_pseudo_regs; + + lldb_private::LinuxArm64RegisterFlags m_linux_register_flags; + const uint8_t *GetSVEBuffer(uint64_t offset = 0); void ConfigureRegisterContext(); 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 3d53a5795ef3..12aa5f72371c 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 @@ -119,6 +119,18 @@ constexpr RegsetDesc AARCH64_SVE_Desc[] = { {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SVE}, }; +constexpr RegsetDesc AARCH64_SSVE_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SSVE}, +}; + +constexpr RegsetDesc AARCH64_ZA_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_ZA}, +}; + +constexpr RegsetDesc AARCH64_ZT_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_ZT}, +}; + constexpr RegsetDesc AARCH64_PAC_Desc[] = { {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_PAC_MASK}, }; @@ -127,6 +139,11 @@ constexpr RegsetDesc AARCH64_TLS_Desc[] = { {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_TLS}, }; +constexpr RegsetDesc AARCH64_MTE_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, + llvm::ELF::NT_ARM_TAGGED_ADDR_CTRL}, +}; + 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/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 7daf003fec7b..8a47eed3d7cb 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 @@ -13,7 +13,6 @@ #include <future> #include <sys/stat.h> -#include "lldb/Core/StreamFile.h" #include "lldb/Host/Config.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSystem.h" 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 c6503129685a..ad72b3d121e6 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 @@ -1265,7 +1265,14 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { if (!value.getAsInteger(0, pointer_byte_size)) ++num_keys_decoded; } else if (name.equals("addressing_bits")) { - if (!value.getAsInteger(0, m_addressing_bits)) + if (!value.getAsInteger(0, m_low_mem_addressing_bits)) { + ++num_keys_decoded; + } + } else if (name.equals("high_mem_addressing_bits")) { + if (!value.getAsInteger(0, m_high_mem_addressing_bits)) + ++num_keys_decoded; + } else if (name.equals("low_mem_addressing_bits")) { + if (!value.getAsInteger(0, m_low_mem_addressing_bits)) ++num_keys_decoded; } else if (name.equals("os_version") || name.equals("version")) // Older debugserver binaries used @@ -1407,11 +1414,19 @@ GDBRemoteCommunicationClient::GetHostArchitecture() { return m_host_arch; } -uint32_t GDBRemoteCommunicationClient::GetAddressingBits() { +AddressableBits GDBRemoteCommunicationClient::GetAddressableBits() { + AddressableBits addressable_bits; if (m_qHostInfo_is_valid == eLazyBoolCalculate) GetHostInfo(); - return m_addressing_bits; + + if (m_low_mem_addressing_bits == m_high_mem_addressing_bits) + addressable_bits.SetAddressableBits(m_low_mem_addressing_bits); + else + addressable_bits.SetAddressableBits(m_low_mem_addressing_bits, + m_high_mem_addressing_bits); + return addressable_bits; } + seconds GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout() { if (m_qHostInfo_is_valid == eLazyBoolCalculate) GetHostInfo(); @@ -2634,10 +2649,12 @@ size_t GDBRemoteCommunicationClient::QueryGDBServer( return 0; for (size_t i = 0, count = array->GetSize(); i < count; ++i) { - StructuredData::Dictionary *element = nullptr; - if (!array->GetItemAtIndexAsDictionary(i, element)) + std::optional<StructuredData::Dictionary *> maybe_element = + array->GetItemAtIndexAsDictionary(i); + if (!maybe_element) continue; + StructuredData::Dictionary *element = *maybe_element; uint16_t port = 0; if (StructuredData::ObjectSP port_osp = element->GetValueForKey(llvm::StringRef("port"))) @@ -4025,7 +4042,7 @@ void GDBRemoteCommunicationClient::ServeSymbolLookups( return; } else { llvm::StringRef response_str(response.GetStringRef()); - if (response_str.startswith("qSymbol:")) { + if (response_str.starts_with("qSymbol:")) { response.SetFilePos(strlen("qSymbol:")); std::string symbol_name; if (response.GetHexByteString(symbol_name)) { 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 6cf5de68911b..866b0773d86d 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 @@ -19,6 +19,7 @@ #include <vector> #include "lldb/Host/File.h" +#include "lldb/Utility/AddressableBits.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/GDBRemote.h" #include "lldb/Utility/ProcessInfo.h" @@ -237,7 +238,7 @@ public: ArchSpec GetSystemArchitecture(); - uint32_t GetAddressingBits(); + lldb_private::AddressableBits GetAddressableBits(); bool GetHostname(std::string &s); @@ -580,7 +581,8 @@ protected: lldb::tid_t m_curr_tid_run = LLDB_INVALID_THREAD_ID; uint32_t m_num_supported_hardware_watchpoints = 0; - uint32_t m_addressing_bits = 0; + uint32_t m_low_mem_addressing_bits = 0; + uint32_t m_high_mem_addressing_bits = 0; ArchSpec m_host_arch; std::string m_host_distribution_id; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp index a3477caea7d8..5d4a537befeb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp @@ -9,7 +9,6 @@ #include "GDBRemoteCommunicationHistory.h" // Other libraries and framework includes -#include "lldb/Core/StreamFile.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Log.h" 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 4efc454967a1..3d37bb226a65 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 @@ -595,6 +595,8 @@ static llvm::StringRef GetKindGenericOrEmpty(const RegisterInfo ®_info) { return "arg7"; case LLDB_REGNUM_GENERIC_ARG8: return "arg8"; + case LLDB_REGNUM_GENERIC_TP: + return "tp"; default: return ""; } @@ -631,7 +633,7 @@ static void WriteRegisterValueInHexFixedWidth( } else { // Zero-out any unreadable values. if (reg_info.byte_size > 0) { - std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0'); + std::vector<uint8_t> zeros(reg_info.byte_size, '\0'); AppendHexValue(response, zeros.data(), zeros.size(), false); } } @@ -2304,7 +2306,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { // Build the reginfos response. StreamGDBRemote response; - RegisterValue reg_value(ArrayRef(m_reg_bytes, reg_size), + RegisterValue reg_value(ArrayRef<uint8_t>(m_reg_bytes, reg_size), m_current_process->GetArchitecture().GetByteOrder()); Status error = reg_context.WriteRegister(reg_info, reg_value); if (error.Fail()) { @@ -3092,6 +3094,12 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { continue; } + if (reg_info->flags_type) { + response.IndentMore(); + reg_info->flags_type->ToXML(response); + response.IndentLess(); + } + response.Indent(); response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" regnum=\"%d\" ", @@ -3111,6 +3119,9 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { if (!format.empty()) response << "format=\"" << format << "\" "; + if (reg_info->flags_type) + response << "type=\"" << reg_info->flags_type->GetID() << "\" "; + const char *const register_set_name = reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index); if (register_set_name) @@ -3910,7 +3921,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qSaveCore( std::string path_hint; StringRef packet_str{packet.GetStringRef()}; - assert(packet_str.startswith("qSaveCore")); + assert(packet_str.starts_with("qSaveCore")); if (packet_str.consume_front("qSaveCore;")) { for (auto x : llvm::split(packet_str, ';')) { if (x.consume_front("path-hint:")) @@ -3936,7 +3947,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QNonStop( Log *log = GetLog(LLDBLog::Process); StringRef packet_str{packet.GetStringRef()}; - assert(packet_str.startswith("QNonStop:")); + assert(packet_str.starts_with("QNonStop:")); packet_str.consume_front("QNonStop:"); if (packet_str == "0") { if (m_non_stop) @@ -4295,7 +4306,7 @@ lldb_private::process_gdb_remote::LLGSArgToURL(llvm::StringRef url_arg, std::string host_port = url_arg.str(); // If host_and_port starts with ':', default the host to be "localhost" and // expect the remainder to be the port. - if (url_arg.startswith(":")) + if (url_arg.starts_with(":")) host_port.insert(0, "localhost"); // Try parsing the (preprocessed) argument as host:port pair. 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 4ffa7faa4942..391abdae2752 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 @@ -500,7 +500,7 @@ GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo( auto dictionary = std::make_shared<StructuredData::Dictionary>(); dictionary->AddIntegerItem("signo", signo); - dictionary->AddStringItem("name", signals->GetSignalAsCString(signo)); + dictionary->AddStringItem("name", signals->GetSignalAsStringRef(signo)); bool suppress, stop, notify; signals->GetSignalInfo(signo, suppress, stop, notify); 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 e8606ddae567..e9bd65fad150 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 @@ -8,6 +8,12 @@ #include "GDBRemoteRegisterContext.h" +#include "ProcessGDBRemote.h" +#include "ProcessGDBRemoteLog.h" +#include "ThreadGDBRemote.h" +#include "Utility/ARM_DWARF_Registers.h" +#include "Utility/ARM_ehframe_Registers.h" +#include "lldb/Core/Architecture.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" @@ -15,11 +21,6 @@ #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Scalar.h" #include "lldb/Utility/StreamString.h" -#include "ProcessGDBRemote.h" -#include "ProcessGDBRemoteLog.h" -#include "ThreadGDBRemote.h" -#include "Utility/ARM_DWARF_Registers.h" -#include "Utility/ARM_ehframe_Registers.h" #include "lldb/Utility/StringExtractorGDBRemote.h" #include <memory> @@ -227,7 +228,9 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info) { SetAllRegisterValid(true); return true; } else if (buffer_sp->GetByteSize() > 0) { - for (auto x : llvm::enumerate(m_reg_info_sp->registers())) { + for (auto x : llvm::enumerate( + m_reg_info_sp->registers< + DynamicRegisterInfo::reg_collection_const_range>())) { const struct RegisterInfo ®info = x.value(); m_reg_valid[x.index()] = (reginfo.byte_offset + reginfo.byte_size <= @@ -373,14 +376,8 @@ 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; + const bool should_reconfigure_registers = + RegisterWriteCausesReconfigure(reg_info->name); if (data.CopyByteOrderedData(data_offset, // src offset reg_info->byte_size, // src length @@ -400,10 +397,10 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, {m_reg_data.GetDataStart(), size_t(m_reg_data.GetByteSize())})) { - SetAllRegisterValid(false); + if (should_reconfigure_registers) + ReconfigureRegisterInfo(); - if (do_reconfigure_arm64_sve) - AArch64SVEReconfigure(); + InvalidateAllRegisters(); return true; } @@ -434,9 +431,6 @@ 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 @@ -450,6 +444,10 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, false); } + if (success && should_reconfigure_registers && + ReconfigureRegisterInfo()) + InvalidateAllRegisters(); + return success; } } else { @@ -760,58 +758,20 @@ uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber( 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 GDBRemoteRegisterContext::RegisterWriteCausesReconfigure( + const llvm::StringRef name) { + ExecutionContext exe_ctx(CalculateThread()); + const Architecture *architecture = + exe_ctx.GetProcessRef().GetTarget().GetArchitecturePlugin(); + return architecture && architecture->RegisterWriteCausesReconfigure(name); } -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; +bool GDBRemoteRegisterContext::ReconfigureRegisterInfo() { + ExecutionContext exe_ctx(CalculateThread()); + const Architecture *architecture = + exe_ctx.GetProcessRef().GetTarget().GetArchitecturePlugin(); + if (architecture) + return architecture->ReconfigureRegisterInfo(*(m_reg_info_sp.get()), + m_reg_data, *this); + return false; } 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 d185cb5aede1..6a90f911353f 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 @@ -38,7 +38,8 @@ public: ~GDBRemoteDynamicRegisterInfo() override = default; - bool UpdateARM64SVERegistersInfos(uint64_t vg); + void UpdateARM64SVERegistersInfos(uint64_t vg); + void UpdateARM64SMERegistersInfos(uint64_t svg); }; class GDBRemoteRegisterContext : public RegisterContext { @@ -77,7 +78,9 @@ public: uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) override; - bool AArch64SVEReconfigure(); + bool RegisterWriteCausesReconfigure(const llvm::StringRef name) override; + + bool ReconfigureRegisterInfo() override; protected: friend class ThreadGDBRemote; 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 b6f146fd872e..316be471df92 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 @@ -24,11 +24,11 @@ #include <sys/types.h> #include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Breakpoint/WatchpointResource.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" #include "lldb/DataFormatters/FormatManager.h" #include "lldb/Host/ConnectionFileDescriptor.h" @@ -36,6 +36,7 @@ #include "lldb/Host/HostThread.h" #include "lldb/Host/PosixApi.h" #include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/XML.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -48,7 +49,6 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/Property.h" -#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" @@ -129,8 +129,8 @@ enum { class PluginProperties : public Properties { public: - static ConstString GetSettingName() { - return ConstString(ProcessGDBRemote::GetPluginNameStatic()); + static llvm::StringRef GetSettingName() { + return ProcessGDBRemote::GetPluginNameStatic(); } PluginProperties() : Properties() { @@ -303,7 +303,7 @@ ProcessGDBRemote::~ProcessGDBRemote() { // make sure all of the broadcaster cleanup goes as planned. If we destruct // this class, then Process::~Process() might have problems trying to fully // destroy the broadcaster. - Finalize(); + Finalize(true /* destructing */); // The general Finalize is going to try to destroy the process and that // SHOULD shut down the async thread. However, if we don't kill it it will @@ -899,11 +899,8 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { process_arch.GetTriple().getTriple()); } - if (int addressable_bits = m_gdb_comm.GetAddressingBits()) { - lldb::addr_t address_mask = ~((1ULL << addressable_bits) - 1); - SetCodeAddressMask(address_mask); - SetDataAddressMask(address_mask); - } + AddressableBits addressable_bits = m_gdb_comm.GetAddressableBits(); + addressable_bits.SetProcessMasks(*this); if (process_arch.IsValid()) { const ArchSpec &target_arch = GetTarget().GetArchitecture(); @@ -1001,10 +998,11 @@ void ProcessGDBRemote::LoadStubBinaries() { const bool force_symbol_search = true; const bool notify = true; const bool set_address_in_target = true; + const bool allow_memory_image_last_resort = false; DynamicLoader::LoadBinaryWithUUIDAndAddress( this, "", standalone_uuid, standalone_value, standalone_value_is_offset, force_symbol_search, notify, - set_address_in_target); + set_address_in_target, allow_memory_image_last_resort); } } @@ -1033,10 +1031,12 @@ void ProcessGDBRemote::LoadStubBinaries() { const bool force_symbol_search = true; const bool set_address_in_target = true; + const bool allow_memory_image_last_resort = false; // Second manually load this binary into the Target. DynamicLoader::LoadBinaryWithUUIDAndAddress( this, llvm::StringRef(), uuid, addr, value_is_slide, - force_symbol_search, notify, set_address_in_target); + force_symbol_search, notify, set_address_in_target, + allow_memory_image_last_resort); } } } @@ -1612,6 +1612,22 @@ bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) { return false; } +void ProcessGDBRemote::ParseExpeditedRegisters( + ExpeditedRegisterMap &expedited_register_map, ThreadSP thread_sp) { + ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread_sp.get()); + RegisterContextSP gdb_reg_ctx_sp(gdb_thread->GetRegisterContext()); + + for (const auto &pair : expedited_register_map) { + StringExtractor reg_value_extractor(pair.second); + WritableDataBufferSP buffer_sp( + new DataBufferHeap(reg_value_extractor.GetStringRef().size() / 2, 0)); + reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); + uint32_t lldb_regnum = gdb_reg_ctx_sp->ConvertRegisterKindToRegisterNumber( + eRegisterKindProcessPlugin, pair.first); + gdb_thread->PrivateSetRegisterValue(lldb_regnum, buffer_sp->GetData()); + } +} + ThreadSP ProcessGDBRemote::SetThreadStopInfo( lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map, uint8_t signo, const std::string &thread_name, const std::string &reason, @@ -1642,35 +1658,24 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( } ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread_sp.get()); - RegisterContextSP gdb_reg_ctx_sp(gdb_thread->GetRegisterContext()); + RegisterContextSP reg_ctx_sp(gdb_thread->GetRegisterContext()); - gdb_reg_ctx_sp->InvalidateIfNeeded(true); + reg_ctx_sp->InvalidateIfNeeded(true); auto iter = std::find(m_thread_ids.begin(), m_thread_ids.end(), tid); if (iter != m_thread_ids.end()) SetThreadPc(thread_sp, iter - m_thread_ids.begin()); - for (const auto &pair : expedited_register_map) { - StringExtractor reg_value_extractor(pair.second); - WritableDataBufferSP buffer_sp( - new DataBufferHeap(reg_value_extractor.GetStringRef().size() / 2, 0)); - reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); - uint32_t lldb_regnum = gdb_reg_ctx_sp->ConvertRegisterKindToRegisterNumber( - eRegisterKindProcessPlugin, pair.first); - gdb_thread->PrivateSetRegisterValue(lldb_regnum, 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()); + ParseExpeditedRegisters(expedited_register_map, thread_sp); - if (reg_ctx_sp) - reg_ctx_sp->AArch64SVEReconfigure(); + if (reg_ctx_sp->ReconfigureRegisterInfo()) { + // Now we have changed the offsets of all the registers, so the values + // will be corrupted. + reg_ctx_sp->InvalidateAllRegisters(); + // Expedited registers values will never contain registers that would be + // resized by a reconfigure. So we are safe to continue using these + // values. + ParseExpeditedRegisters(expedited_register_map, thread_sp); } thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str()); @@ -1785,30 +1790,38 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( // disable/step/re-enable it, so one of the valid watchpoint // addresses should be provided as \a wp_addr. StringExtractor desc_extractor(description.c_str()); + // FIXME NativeThreadLinux::SetStoppedByWatchpoint sends this + // up as + // <address within wp range> <wp hw index> <actual accessed addr> + // but this is not reading the <wp hw index>. Seems like it + // wouldn't work on MIPS, where that third field is important. addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); - uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); watch_id_t watch_id = LLDB_INVALID_WATCH_ID; bool silently_continue = false; - WatchpointSP wp_sp; + WatchpointResourceSP wp_resource_sp; if (wp_hit_addr != LLDB_INVALID_ADDRESS) { - wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr); + wp_resource_sp = + m_watchpoint_resource_list.FindByAddress(wp_hit_addr); // On MIPS, \a wp_hit_addr outside the range of a watched // region means we should silently continue, it is a false hit. ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); - if (!wp_sp && core >= ArchSpec::kCore_mips_first && + if (!wp_resource_sp && core >= ArchSpec::kCore_mips_first && core <= ArchSpec::kCore_mips_last) silently_continue = true; } - if (!wp_sp && wp_addr != LLDB_INVALID_ADDRESS) - wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); - if (wp_sp) { - wp_sp->SetHardwareIndex(wp_index); - watch_id = wp_sp->GetID(); - } - if (watch_id == LLDB_INVALID_WATCH_ID) { + if (!wp_resource_sp && wp_addr != LLDB_INVALID_ADDRESS) + wp_resource_sp = m_watchpoint_resource_list.FindByAddress(wp_addr); + if (!wp_resource_sp) { Log *log(GetLog(GDBRLog::Watchpoints)); LLDB_LOGF(log, "failed to find watchpoint"); + watch_id = LLDB_INVALID_SITE_ID; + } else { + // LWP_TODO: This is hardcoding a single Watchpoint in a + // Resource, need to add + // StopInfo::CreateStopReasonWithWatchpointResource which + // represents all watchpoints that were tripped at this stop. + watch_id = wp_resource_sp->GetConstituentAtIndex(0)->GetID(); } thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID( *thread_sp, watch_id, silently_continue)); @@ -1926,24 +1939,23 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( lldb::ThreadSP ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { - static ConstString g_key_tid("tid"); - static ConstString g_key_name("name"); - static ConstString g_key_reason("reason"); - static ConstString g_key_metype("metype"); - static ConstString g_key_medata("medata"); - static ConstString g_key_qaddr("qaddr"); - static ConstString g_key_dispatch_queue_t("dispatch_queue_t"); - static ConstString g_key_associated_with_dispatch_queue( + static constexpr llvm::StringLiteral g_key_tid("tid"); + static constexpr llvm::StringLiteral g_key_name("name"); + static constexpr llvm::StringLiteral g_key_reason("reason"); + static constexpr llvm::StringLiteral g_key_metype("metype"); + static constexpr llvm::StringLiteral g_key_medata("medata"); + static constexpr llvm::StringLiteral g_key_qaddr("qaddr"); + static constexpr llvm::StringLiteral g_key_dispatch_queue_t( + "dispatch_queue_t"); + static constexpr llvm::StringLiteral g_key_associated_with_dispatch_queue( "associated_with_dispatch_queue"); - static ConstString g_key_queue_name("qname"); - static ConstString g_key_queue_kind("qkind"); - static ConstString g_key_queue_serial_number("qserialnum"); - static ConstString g_key_registers("registers"); - static ConstString g_key_memory("memory"); - static ConstString g_key_address("address"); - static ConstString g_key_bytes("bytes"); - static ConstString g_key_description("description"); - static ConstString g_key_signal("signal"); + static constexpr llvm::StringLiteral g_key_queue_name("qname"); + static constexpr llvm::StringLiteral g_key_queue_kind("qkind"); + static constexpr llvm::StringLiteral g_key_queue_serial_number("qserialnum"); + static constexpr llvm::StringLiteral g_key_registers("registers"); + static constexpr llvm::StringLiteral g_key_memory("memory"); + static constexpr llvm::StringLiteral g_key_description("description"); + static constexpr llvm::StringLiteral g_key_signal("signal"); // Stop with signal and thread info lldb::tid_t tid = LLDB_INVALID_THREAD_ID; @@ -1971,7 +1983,7 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { &thread_dispatch_qaddr, &queue_vars_valid, &associated_with_dispatch_queue, &dispatch_queue_t, &queue_name, &queue_kind, &queue_serial_number]( - ConstString key, + llvm::StringRef key, StructuredData::Object *object) -> bool { if (key == g_key_tid) { // thread in big endian hex @@ -2029,10 +2041,10 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { if (registers_dict) { registers_dict->ForEach( - [&expedited_register_map](ConstString key, + [&expedited_register_map](llvm::StringRef key, StructuredData::Object *object) -> bool { uint32_t reg; - if (llvm::to_integer(key.AsCString(), reg)) + if (llvm::to_integer(key, reg)) expedited_register_map[reg] = std::string(object->GetStringValue()); return true; // Keep iterating through all array items @@ -2089,7 +2101,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { switch (stop_type) { case 'T': case 'S': { - // This is a bit of a hack, but is is required. If we did exec, we need to + // This is a bit of a hack, but it is required. If we did exec, we need to // clear our thread lists and also know to rebuild our dynamic register // info before we lookup and threads and populate the expedited register // values so we need to know this right away so we can cleanup and update @@ -2122,6 +2134,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { QueueKind queue_kind = eQueueKindUnknown; uint64_t queue_serial_number = 0; ExpeditedRegisterMap expedited_register_map; + AddressableBits addressable_bits; while (stop_packet.GetNameColonValue(key, value)) { if (key.compare("metype") == 0) { // exception type in big endian hex @@ -2232,19 +2245,15 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { lldb::addr_t wp_addr = LLDB_INVALID_ADDRESS; value.getAsInteger(16, wp_addr); - WatchpointSP wp_sp = - GetTarget().GetWatchpointList().FindByAddress(wp_addr); - uint32_t wp_index = LLDB_INVALID_INDEX32; - - if (wp_sp) - wp_index = wp_sp->GetHardwareIndex(); + WatchpointResourceSP wp_resource_sp = + m_watchpoint_resource_list.FindByAddress(wp_addr); // Rewrite gdb standard watch/rwatch/awatch to // "reason:watchpoint" + "description:ADDR", // which is parsed in SetThreadStopInfo. reason = "watchpoint"; StreamString ostr; - ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index); + ostr.Printf("%" PRIu64, wp_addr); description = std::string(ostr.GetString()); } else if (key.compare("library") == 0) { auto error = LoadModules(); @@ -2269,9 +2278,17 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { } else if (key.compare("addressing_bits") == 0) { uint64_t addressing_bits; if (!value.getAsInteger(0, addressing_bits)) { - addr_t address_mask = ~((1ULL << addressing_bits) - 1); - SetCodeAddressMask(address_mask); - SetDataAddressMask(address_mask); + addressable_bits.SetAddressableBits(addressing_bits); + } + } else if (key.compare("low_mem_addressing_bits") == 0) { + uint64_t addressing_bits; + if (!value.getAsInteger(0, addressing_bits)) { + addressable_bits.SetLowmemAddressableBits(addressing_bits); + } + } else if (key.compare("high_mem_addressing_bits") == 0) { + uint64_t addressing_bits; + if (!value.getAsInteger(0, addressing_bits)) { + addressable_bits.SetHighmemAddressableBits(addressing_bits); } } else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) { uint32_t reg = UINT32_MAX; @@ -2300,6 +2317,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { } } + addressable_bits.SetProcessMasks(*this); + ThreadSP thread_sp = SetThreadStopInfo( tid, expedited_register_map, signo, thread_name, reason, description, exc_type, exc_data, thread_dispatch_qaddr, queue_vars_valid, @@ -2358,8 +2377,10 @@ Status ProcessGDBRemote::DoHalt(bool &caused_stop) { Status error; if (m_public_state.GetValue() == eStateAttaching) { - // We are being asked to halt during an attach. We need to just close our - // file handle and debugserver will go away, and we can be done... + // We are being asked to halt during an attach. We used to just close our + // file handle and debugserver will go away, but with remote proxies, it + // is better to send a positive signal, so let's send the interrupt first... + caused_stop = m_gdb_comm.Interrupt(GetInterruptTimeout()); m_gdb_comm.Disconnect(); } else caused_stop = m_gdb_comm.Interrupt(GetInterruptTimeout()); @@ -3094,100 +3115,182 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) { } // Pre-requisite: wp != NULL. -static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) { - assert(wp); - bool watch_read = wp->WatchpointRead(); - bool watch_write = wp->WatchpointWrite(); - - // watch_read and watch_write cannot both be false. - assert(watch_read || watch_write); - if (watch_read && watch_write) +static GDBStoppointType +GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) { + assert(wp_res_sp); + bool read = wp_res_sp->WatchpointResourceRead(); + bool write = wp_res_sp->WatchpointResourceWrite(); + + assert((read || write) && + "WatchpointResource type is neither read nor write"); + if (read && write) return eWatchpointReadWrite; - else if (watch_read) + else if (read) return eWatchpointRead; - else // Must be watch_write, then. + else return eWatchpointWrite; } -Status ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) { +Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) { Status error; - if (wp) { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log(GetLog(GDBRLog::Watchpoints)); - LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", - watchID); - if (wp->IsEnabled()) { - LLDB_LOGF(log, - "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", - watchID, (uint64_t)addr); - return error; - } + if (!wp_sp) { + error.SetErrorString("No watchpoint specified"); + return error; + } + user_id_t watchID = wp_sp->GetID(); + addr_t addr = wp_sp->GetLoadAddress(); + Log *log(GetLog(GDBRLog::Watchpoints)); + LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (wp_sp->IsEnabled()) { + LLDB_LOGF(log, + "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", + watchID, (uint64_t)addr); + return error; + } - GDBStoppointType type = GetGDBStoppointType(wp); - // Pass down an appropriate z/Z packet... - if (m_gdb_comm.SupportsGDBStoppointPacket(type)) { - if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, - wp->GetByteSize(), - GetInterruptTimeout()) == 0) { - wp->SetEnabled(true, notify); - return error; - } else - error.SetErrorString("sending gdb watchpoint packet failed"); - } else - error.SetErrorString("watchpoints not supported"); + bool read = wp_sp->WatchpointRead(); + bool write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify(); + size_t size = wp_sp->GetByteSize(); + + // New WatchpointResources needed to implement this Watchpoint. + std::vector<WatchpointResourceSP> resources; + + // LWP_TODO: Break up the user's request into pieces that can be watched + // given the capabilities of the target cpu / stub software. + // As a default, breaking the watched region up into target-pointer-sized, + // aligned, groups. + // + // Beyond the default, a stub can / should inform us of its capabilities, + // e.g. a stub that can do AArch64 power-of-2 MASK watchpoints. + // + // And the cpu may have unique capabilities. AArch64 BAS watchpoints + // can watch any sequential bytes in a doubleword, but Intel watchpoints + // can only watch 1, 2, 4, 8 bytes within a doubleword. + WatchpointResourceSP wp_res_sp = + std::make_shared<WatchpointResource>(addr, size, read, write); + resources.push_back(wp_res_sp); + + // LWP_TODO: Now that we know the WP Resources needed to implement this + // Watchpoint, we need to look at currently allocated Resources in the + // Process and if they match, or are within the same memory granule, or + // overlapping memory ranges, then we need to combine them. e.g. one + // Watchpoint watching 1 byte at 0x1002 and a second watchpoint watching 1 + // byte at 0x1003, they must use the same hardware watchpoint register + // (Resource) to watch them. + + // This may mean that an existing resource changes its type (read to + // read+write) or address range it is watching, in which case the old + // watchpoint needs to be disabled and the new Resource addr/size/type + // watchpoint enabled. + + // If we modify a shared Resource to accomodate this newly added Watchpoint, + // and we are unable to set all of the Resources for it in the inferior, we + // will return an error for this Watchpoint and the shared Resource should + // be restored. e.g. this Watchpoint requires three Resources, one which + // is shared with another Watchpoint. We extend the shared Resouce to + // handle both Watchpoints and we try to set two new ones. But if we don't + // have sufficient watchpoint register for all 3, we need to show an error + // for creating this Watchpoint and we should reset the shared Resource to + // its original configuration because it is no longer shared. + + bool set_all_resources = true; + std::vector<WatchpointResourceSP> succesfully_set_resources; + for (const auto &wp_res_sp : resources) { + addr_t addr = wp_res_sp->GetLoadAddress(); + size_t size = wp_res_sp->GetByteSize(); + GDBStoppointType type = GetGDBStoppointType(wp_res_sp); + if (!m_gdb_comm.SupportsGDBStoppointPacket(type) || + m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size, + GetInterruptTimeout())) { + set_all_resources = false; + break; + } else { + succesfully_set_resources.push_back(wp_res_sp); + } + } + if (set_all_resources) { + wp_sp->SetEnabled(true, notify); + for (const auto &wp_res_sp : resources) { + // LWP_TODO: If we expanded/reused an existing Resource, + // it's already in the WatchpointResourceList. + wp_res_sp->AddConstituent(wp_sp); + m_watchpoint_resource_list.Add(wp_res_sp); + } + return error; } else { - error.SetErrorString("Watchpoint argument was NULL."); + // We failed to allocate one of the resources. Unset all + // of the new resources we did successfully set in the + // process. + for (const auto &wp_res_sp : succesfully_set_resources) { + addr_t addr = wp_res_sp->GetLoadAddress(); + size_t size = wp_res_sp->GetByteSize(); + GDBStoppointType type = GetGDBStoppointType(wp_res_sp); + m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size, + GetInterruptTimeout()); + } + error.SetErrorString("Setting one of the watchpoint resources failed"); } - if (error.Success()) - error.SetErrorToGenericError(); return error; } -Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) { +Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) { Status error; - if (wp) { - user_id_t watchID = wp->GetID(); + if (!wp_sp) { + error.SetErrorString("Watchpoint argument was NULL."); + return error; + } + + user_id_t watchID = wp_sp->GetID(); + + Log *log(GetLog(GDBRLog::Watchpoints)); - Log *log(GetLog(GDBRLog::Watchpoints)); + addr_t addr = wp_sp->GetLoadAddress(); - addr_t addr = wp->GetLoadAddress(); + LLDB_LOGF(log, + "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64, + watchID, (uint64_t)addr); + if (!wp_sp->IsEnabled()) { LLDB_LOGF(log, "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64, + ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr); + // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling + // attempt might come from the user-supplied actions, we'll route it in + // order for the watchpoint object to intelligently process this action. + wp_sp->SetEnabled(false, notify); + return error; + } - if (!wp->IsEnabled()) { - LLDB_LOGF(log, - "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", - watchID, (uint64_t)addr); - // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling - // attempt might come from the user-supplied actions, we'll route it in - // order for the watchpoint object to intelligently process this action. - wp->SetEnabled(false, notify); - return error; - } + if (wp_sp->IsHardware()) { + bool disabled_all = true; - if (wp->IsHardware()) { - GDBStoppointType type = GetGDBStoppointType(wp); - // Pass down an appropriate z/Z packet... - if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, - wp->GetByteSize(), - GetInterruptTimeout()) == 0) { - wp->SetEnabled(false, notify); - return error; - } else - error.SetErrorString("sending gdb watchpoint packet failed"); + std::vector<WatchpointResourceSP> unused_resources; + for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) { + if (wp_res_sp->ConstituentsContains(wp_sp)) { + GDBStoppointType type = GetGDBStoppointType(wp_res_sp); + addr_t addr = wp_res_sp->GetLoadAddress(); + size_t size = wp_res_sp->GetByteSize(); + if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size, + GetInterruptTimeout())) { + disabled_all = false; + } else { + wp_res_sp->RemoveConstituent(wp_sp); + if (wp_res_sp->GetNumberOfConstituents() == 0) + unused_resources.push_back(wp_res_sp); + } + } } - // TODO: clear software watchpoints if we implement them - } else { - error.SetErrorString("Watchpoint argument was NULL."); + for (auto &wp_res_sp : unused_resources) + m_watchpoint_resource_list.Remove(wp_res_sp->GetID()); + + wp_sp->SetEnabled(false, notify); + if (!disabled_all) + error.SetErrorString("Failure disabling one of the watchpoint locations"); } - if (error.Success()) - error.SetErrorToGenericError(); return error; } @@ -3368,23 +3471,20 @@ void ProcessGDBRemote::MonitorDebugserverProcess( if (state != eStateInvalid && state != eStateUnloaded && state != eStateExited && state != eStateDetached) { - char error_str[1024]; - if (signo) { - const char *signal_cstr = - process_sp->GetUnixSignals()->GetSignalAsCString(signo); - if (signal_cstr) - ::snprintf(error_str, sizeof(error_str), - DEBUGSERVER_BASENAME " died with signal %s", signal_cstr); + StreamString stream; + if (signo == 0) + stream.Format(DEBUGSERVER_BASENAME " died with an exit status of {0:x8}", + exit_status); + else { + llvm::StringRef signal_name = + process_sp->GetUnixSignals()->GetSignalAsStringRef(signo); + const char *format_str = DEBUGSERVER_BASENAME " died with signal {0}"; + if (!signal_name.empty()) + stream.Format(format_str, signal_name); else - ::snprintf(error_str, sizeof(error_str), - DEBUGSERVER_BASENAME " died with signal %i", signo); - } else { - ::snprintf(error_str, sizeof(error_str), - DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", - exit_status); + stream.Format(format_str, signo); } - - process_sp->SetExitStatus(-1, error_str); + process_sp->SetExitStatus(-1, stream.GetString()); } // Debugserver has exited we need to let our ProcessGDBRemote know that it no // longer has a debugserver instance @@ -4372,7 +4472,7 @@ bool ParseRegisters( // and a simple type. Just in case, look for that too (setting both // does no harm). if (!gdb_type.empty() && !(encoding_set || format_set)) { - if (llvm::StringRef(gdb_type).startswith("int")) { + if (llvm::StringRef(gdb_type).starts_with("int")) { reg_info.format = eFormatHex; reg_info.encoding = eEncodingUint; } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") { @@ -4382,7 +4482,7 @@ bool ParseRegisters( reg_info.format = eFormatFloat; reg_info.encoding = eEncodingIEEE754; } else if (gdb_type == "aarch64v" || - llvm::StringRef(gdb_type).startswith("vec") || + llvm::StringRef(gdb_type).starts_with("vec") || gdb_type == "i387_ext" || gdb_type == "uint128") { // lldb doesn't handle 128-bit uints correctly (for ymm*h), so // treat them as vector (similarly to xmm/ymm) @@ -5169,7 +5269,7 @@ public: Options *GetOptions() override { return &m_option_group; } - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) { ProcessGDBRemote *process = @@ -5191,14 +5291,13 @@ public: num_packets, max_send, max_recv, k_recv_amount, json, output_stream_sp ? *output_stream_sp : result.GetOutputStream()); result.SetStatus(eReturnStatusSuccessFinishResult); - return true; + return; } } else { result.AppendErrorWithFormat("'%s' takes no arguments", m_cmd_name.c_str()); } result.SetStatus(eReturnStatusFailed); - return false; } protected: @@ -5218,16 +5317,15 @@ public: ~CommandObjectProcessGDBRemotePacketHistory() override = default; - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); if (process) { process->DumpPluginHistory(result.GetOutputStream()); result.SetStatus(eReturnStatusSuccessFinishResult); - return true; + return; } result.SetStatus(eReturnStatusFailed); - return false; } }; @@ -5245,14 +5343,14 @@ public: ~CommandObjectProcessGDBRemotePacketXferSize() override = default; - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) { result.AppendErrorWithFormat("'%s' takes an argument to specify the max " "amount to be transferred when " "reading/writing", m_cmd_name.c_str()); - return false; + return; } ProcessGDBRemote *process = @@ -5264,11 +5362,10 @@ public: if (errno == 0 && user_specified_max != 0) { process->SetUserSpecifiedMaxMemoryTransferSize(user_specified_max); result.SetStatus(eReturnStatusSuccessFinishResult); - return true; + return; } } result.SetStatus(eReturnStatusFailed); - return false; } }; @@ -5289,13 +5386,13 @@ public: ~CommandObjectProcessGDBRemotePacketSend() override = default; - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) { result.AppendErrorWithFormat( "'%s' takes a one or more packet content arguments", m_cmd_name.c_str()); - return false; + return; } ProcessGDBRemote *process = @@ -5321,7 +5418,6 @@ public: output_strm.Printf("response: %s\n", response.GetStringRef().data()); } } - return true; } }; @@ -5338,12 +5434,12 @@ public: ~CommandObjectProcessGDBRemotePacketMonitor() override = default; - bool DoExecute(llvm::StringRef command, + void DoExecute(llvm::StringRef command, CommandReturnObject &result) override { if (command.empty()) { result.AppendErrorWithFormat("'%s' takes a command string argument", m_cmd_name.c_str()); - return false; + return; } ProcessGDBRemote *process = @@ -5367,7 +5463,6 @@ public: else output_strm.Printf("response: %s\n", response.GetStringRef().data()); } - return true; } }; @@ -5447,16 +5542,12 @@ void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) { }); } - WatchpointList &wps = GetTarget().GetWatchpointList(); - size_t wp_count = wps.GetSize(); - for (size_t i = 0; i < wp_count; ++i) { - WatchpointSP wp = wps.GetByIndex(i); - if (wp->IsEnabled()) { - GDBStoppointType type = GetGDBStoppointType(wp.get()); - m_gdb_comm.SendGDBStoppointTypePacket(type, enable, wp->GetLoadAddress(), - wp->GetByteSize(), - GetInterruptTimeout()); - } + for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) { + addr_t addr = wp_res_sp->GetLoadAddress(); + size_t size = wp_res_sp->GetByteSize(); + GDBStoppointType type = GetGDBStoppointType(wp_res_sp); + m_gdb_comm.SendGDBStoppointTypePacket(type, enable, addr, size, + GetInterruptTimeout()); } } 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 f0ead4c38c23..c1ea1cc79055 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 @@ -158,9 +158,11 @@ public: Status DisableBreakpointSite(BreakpointSite *bp_site) override; // Process Watchpoints - Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override; + Status EnableWatchpoint(lldb::WatchpointSP wp_sp, + bool notify = true) override; - Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override; + Status DisableWatchpoint(lldb::WatchpointSP wp_sp, + bool notify = true) override; std::optional<uint32_t> GetWatchpointSlotCount() override; @@ -470,6 +472,9 @@ private: void DidForkSwitchSoftwareBreakpoints(bool enable); void DidForkSwitchHardwareTraps(bool enable); + void ParseExpeditedRegisters(ExpeditedRegisterMap &expedited_register_map, + lldb::ThreadSP thread_sp); + // Lists of register fields generated from the remote's target XML. // Pointers to these RegisterFlags will be set in the register info passed // back to the upper levels of lldb. Doing so is safe because this class will diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td index d4c3c8b94b7e..520dad062e09 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td @@ -3,7 +3,11 @@ include "../../../../include/lldb/Core/PropertiesBase.td" let Definition = "processgdbremote" in { def PacketTimeout: Property<"packet-timeout", "UInt64">, Global, +#ifdef LLDB_SANITIZED + DefaultUnsignedValue<60>, +#else DefaultUnsignedValue<5>, +#endif Desc<"Specify the default packet timeout in seconds.">; def TargetDefinitionFile: Property<"target-definition-file", "FileSpec">, Global, 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 99d0b54c40f9..b72307c7e4b9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -166,7 +166,7 @@ ProcessMinidump::~ProcessMinidump() { // make sure all of the broadcaster cleanup goes as planned. If we destruct // this class, then Process::~Process() might have problems trying to fully // destroy the broadcaster. - Finalize(); + Finalize(true /* destructing */); } void ProcessMinidump::Initialize() { @@ -795,12 +795,12 @@ public: Options *GetOptions() override { return &m_option_group; } - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc > 0) { result.AppendErrorWithFormat("'%s' take no arguments, only options", m_cmd_name.c_str()); - return false; + return; } SetDefaultOptionsIfNoneAreSet(); @@ -904,9 +904,7 @@ public: DumpTextStream(StreamType::FacebookThreadName, "Facebook Thread Name"); if (DumpFacebookLogcat()) - DumpTextStream(StreamType::FacebookLogcat, - "Facebook Logcat"); - return true; + DumpTextStream(StreamType::FacebookLogcat, "Facebook Logcat"); } }; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h index 8ae751095c04..58cf8d62fb86 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h @@ -67,13 +67,14 @@ public: uint8_t v[32 * 16]; // 32 128-bit floating point registers }; -protected: enum class Flags : uint32_t { ARM64_Flag = 0x80000000, Integer = ARM64_Flag | 0x00000002, FloatingPoint = ARM64_Flag | 0x00000004, LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint) }; + +protected: Context m_regs; }; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h index 9592d335eff7..4dffc4f9db0e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h @@ -99,7 +99,7 @@ struct MinidumpContext_x86_32 { // The next field is included with // MinidumpContext_x86_32_Flags::ExtendedRegisters - // It contains vector (MMX/SSE) registers. It it laid out in the + // It contains vector (MMX/SSE) registers. It is laid out in the // format used by the fxsave and fsrstor instructions, so it includes // a copy of the x87 floating-point registers as well. See FXSAVE in // "Intel Architecture Software Developer's Manual, Volume 2." diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp index e99a2a08bd50..66f861350d14 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -108,10 +108,18 @@ ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp, ExecutionContext exe_ctx(target_sp, /*get_process=*/false); // Create process script object - StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject( + auto obj_or_err = GetInterface().CreatePluginObject( m_scripted_metadata.GetClassName(), exe_ctx, m_scripted_metadata.GetArgsSP()); + if (!obj_or_err) { + llvm::consumeError(obj_or_err.takeError()); + error.SetErrorString("Failed to create script object."); + return; + } + + StructuredData::GenericSP object_sp = *obj_or_err; + if (!object_sp || !object_sp->IsValid()) { error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", __FUNCTION__, @@ -122,11 +130,17 @@ ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp, ScriptedProcess::~ScriptedProcess() { Clear(); + // If the interface is not valid, we can't call Finalize(). When that happens + // it means that the Scripted Process instanciation failed and the + // CreateProcess function returns a nullptr, so no one besides this class + // should have access to that bogus process object. + if (!m_interface_up) + return; // We need to call finalize on the process before destroying ourselves to // make sure all of the broadcaster cleanup goes as planned. If we destruct // this class, then Process::~Process() might have problems trying to fully // destroy the broadcaster. - Finalize(); + Finalize(true /* destructing */); } void ScriptedProcess::Initialize() { diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp index 684375957d24..88a4ca3b0389 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp @@ -56,14 +56,18 @@ ScriptedThread::Create(ScriptedProcess &process, } ExecutionContext exe_ctx(process); - StructuredData::GenericSP owned_script_object_sp = - scripted_thread_interface->CreatePluginObject( - thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(), - script_object); + auto obj_or_err = scripted_thread_interface->CreatePluginObject( + thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(), + script_object); - if (!owned_script_object_sp) + if (!obj_or_err) { + llvm::consumeError(obj_or_err.takeError()); return llvm::createStringError(llvm::inconvertibleErrorCode(), "Failed to create script object."); + } + + StructuredData::GenericSP owned_script_object_sp = *obj_or_err; + if (!owned_script_object_sp->IsValid()) return llvm::createStringError(llvm::inconvertibleErrorCode(), "Created script object is invalid."); @@ -172,8 +176,9 @@ bool ScriptedThread::LoadArtificialStackFrames() { StackFrameListSP frames = GetStackFrameList(); for (size_t idx = 0; idx < arr_size; idx++) { - StructuredData::Dictionary *dict; - if (!arr_sp->GetItemAtIndexAsDictionary(idx, dict) || !dict) + std::optional<StructuredData::Dictionary *> maybe_dict = + arr_sp->GetItemAtIndexAsDictionary(idx); + if (!maybe_dict) return ScriptedInterface::ErrorWithMessage<bool>( LLVM_PRETTY_FUNCTION, llvm::Twine( @@ -181,6 +186,7 @@ bool ScriptedThread::LoadArtificialStackFrames() { llvm::Twine(idx) + llvm::Twine(") from stackframe array.")) .str(), error, LLDBLog::Thread); + StructuredData::Dictionary *dict = *maybe_dict; lldb::addr_t pc; if (!dict->GetValueForKeyAsInteger("pc", pc)) diff --git a/contrib/llvm-project/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/contrib/llvm-project/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp index aeb54ef9ee24..067768537c06 100644 --- a/contrib/llvm-project/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp @@ -60,7 +60,8 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType( fields_type = type_system->CreateRecordType( nullptr, OptionalClangModuleID(), lldb::eAccessPublic, - register_type_name, clang::TTK_Struct, lldb::eLanguageTypeC); + register_type_name, llvm::to_underlying(clang::TagTypeKind::Struct), + lldb::eLanguageTypeC); type_system->StartTagDeclarationDefinition(fields_type); // We assume that RegisterFlags has padded and sorted the fields 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 be573cfba610..f50bc61279d0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp @@ -11,7 +11,7 @@ #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Utility/Stream.h" diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp index bec90b2038e1..7aeee6e40395 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp @@ -9,7 +9,6 @@ #include "ScriptInterpreterNone.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StringList.h" @@ -27,17 +26,19 @@ ScriptInterpreterNone::ScriptInterpreterNone(Debugger &debugger) ScriptInterpreterNone::~ScriptInterpreterNone() = default; +static const char *no_interpreter_err_msg = + "error: Embedded script interpreter unavailable. LLDB was built without " + "scripting language support.\n"; + bool ScriptInterpreterNone::ExecuteOneLine(llvm::StringRef command, CommandReturnObject *, const ExecuteScriptOptions &) { - m_debugger.GetErrorStream().PutCString( - "error: there is no embedded script interpreter in this mode.\n"); + m_debugger.GetErrorStream().PutCString(no_interpreter_err_msg); return false; } void ScriptInterpreterNone::ExecuteInterpreterLoop() { - m_debugger.GetErrorStream().PutCString( - "error: there is no embedded script interpreter in this mode.\n"); + m_debugger.GetErrorStream().PutCString(no_interpreter_err_msg); } void ScriptInterpreterNone::Initialize() { diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/OperatingSystemPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/OperatingSystemPythonInterface.cpp new file mode 100644 index 000000000000..c162c7367c65 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/OperatingSystemPythonInterface.cpp @@ -0,0 +1,82 @@ +//===-- ScriptedThreadPythonInterface.cpp ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Config.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/Log.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// LLDB Python header must be included first +#include "../lldb-python.h" + +#include "../SWIGPythonBridge.h" +#include "../ScriptInterpreterPythonImpl.h" +#include "OperatingSystemPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::python; +using Locker = ScriptInterpreterPythonImpl::Locker; + +OperatingSystemPythonInterface::OperatingSystemPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : OperatingSystemInterface(), ScriptedThreadPythonInterface(interpreter) {} + +llvm::Expected<StructuredData::GenericSP> +OperatingSystemPythonInterface::CreatePluginObject( + llvm::StringRef class_name, ExecutionContext &exe_ctx, + StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) { + return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr, + exe_ctx.GetProcessSP()); +} + +StructuredData::DictionarySP +OperatingSystemPythonInterface::CreateThread(lldb::tid_t tid, + lldb::addr_t context) { + Status error; + StructuredData::DictionarySP dict = Dispatch<StructuredData::DictionarySP>( + "create_thread", error, tid, context); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, + error)) + return {}; + + return dict; +} + +StructuredData::ArraySP OperatingSystemPythonInterface::GetThreadInfo() { + Status error; + StructuredData::ArraySP arr = + Dispatch<StructuredData::ArraySP>("get_thread_info", error); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, + error)) + return {}; + + return arr; +} + +StructuredData::DictionarySP OperatingSystemPythonInterface::GetRegisterInfo() { + return ScriptedThreadPythonInterface::GetRegisterInfo(); +} + +std::optional<std::string> +OperatingSystemPythonInterface::GetRegisterContextForTID(lldb::tid_t tid) { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_register_data", error, tid); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) + return {}; + + return obj->GetAsString()->GetValue().str(); +} + +#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/OperatingSystemPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/OperatingSystemPythonInterface.h new file mode 100644 index 000000000000..da7bbf13b1d5 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/OperatingSystemPythonInterface.h @@ -0,0 +1,48 @@ +//===-- OperatingSystemPythonInterface.h ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_OPERATINGSYSTEMPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_OPERATINGSYSTEMPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON + +#include "ScriptedThreadPythonInterface.h" +#include "lldb/Interpreter/Interfaces/OperatingSystemInterface.h" +#include <optional> + +namespace lldb_private { +class OperatingSystemPythonInterface + : virtual public OperatingSystemInterface, + virtual public ScriptedThreadPythonInterface { +public: + OperatingSystemPythonInterface(ScriptInterpreterPythonImpl &interpreter); + + llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx, + StructuredData::DictionarySP args_sp, + StructuredData::Generic *script_obj = nullptr) override; + + llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override { + return llvm::SmallVector<llvm::StringLiteral>({"get_thread_info"}); + } + + StructuredData::DictionarySP CreateThread(lldb::tid_t tid, + lldb::addr_t context) override; + + StructuredData::ArraySP GetThreadInfo() override; + + StructuredData::DictionarySP GetRegisterInfo() override; + + std::optional<std::string> GetRegisterContextForTID(lldb::tid_t tid) override; +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_OPERATINGSYSTEMPYTHONINTERFACE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPlatformPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp index a0c55874c70a..9ba4731032bd 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPlatformPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp @@ -14,10 +14,10 @@ #if LLDB_ENABLE_PYTHON // LLDB Python header must be included first -#include "lldb-python.h" +#include "../lldb-python.h" -#include "SWIGPythonBridge.h" -#include "ScriptInterpreterPythonImpl.h" +#include "../SWIGPythonBridge.h" +#include "../ScriptInterpreterPythonImpl.h" #include "ScriptedPlatformPythonInterface.h" using namespace lldb; @@ -29,29 +29,15 @@ ScriptedPlatformPythonInterface::ScriptedPlatformPythonInterface( ScriptInterpreterPythonImpl &interpreter) : ScriptedPlatformInterface(), ScriptedPythonInterface(interpreter) {} -StructuredData::GenericSP ScriptedPlatformPythonInterface::CreatePluginObject( +llvm::Expected<StructuredData::GenericSP> +ScriptedPlatformPythonInterface::CreatePluginObject( llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) { - if (class_name.empty()) - return {}; - - StructuredDataImpl args_impl(args_sp); - std::string error_string; - - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - lldb::ExecutionContextRefSP exe_ctx_ref_sp = + ExecutionContextRefSP exe_ctx_ref_sp = std::make_shared<ExecutionContextRef>(exe_ctx); - - PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedObject( - class_name.str().c_str(), m_interpreter.GetDictionaryName(), - exe_ctx_ref_sp, args_impl, error_string); - - m_object_instance_sp = - StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val))); - - return m_object_instance_sp; + StructuredDataImpl sd_impl(args_sp); + return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj, + exe_ctx_ref_sp, sd_impl); } StructuredData::DictionarySP ScriptedPlatformPythonInterface::ListProcesses() { diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPlatformPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.h index 1e3ad9962325..0842d3a00342 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPlatformPythonInterface.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.h @@ -6,15 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPLATFORMPYTHONINTERFACE_H -#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPLATFORMPYTHONINTERFACE_H +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPLATFORMPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPLATFORMPYTHONINTERFACE_H #include "lldb/Host/Config.h" #if LLDB_ENABLE_PYTHON #include "ScriptedPythonInterface.h" -#include "lldb/Interpreter/ScriptedPlatformInterface.h" +#include "lldb/Interpreter/Interfaces/ScriptedPlatformInterface.h" namespace lldb_private { class ScriptedPlatformPythonInterface : public ScriptedPlatformInterface, @@ -22,12 +22,18 @@ class ScriptedPlatformPythonInterface : public ScriptedPlatformInterface, public: ScriptedPlatformPythonInterface(ScriptInterpreterPythonImpl &interpreter); - StructuredData::GenericSP + llvm::Expected<StructuredData::GenericSP> CreatePluginObject(const llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj = nullptr) override; + llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override { + return llvm::SmallVector<llvm::StringLiteral>( + {"list_processes", "attach_to_process", "launch_process", + "kill_process"}); + } + StructuredData::DictionarySP ListProcesses() override; StructuredData::DictionarySP GetProcessInfo(lldb::pid_t) override; @@ -41,4 +47,4 @@ public: } // namespace lldb_private #endif // LLDB_ENABLE_PYTHON -#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPLATFORMPYTHONINTERFACE_H +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPLATFORMPYTHONINTERFACE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp index 019924fa1971..e86b34d6b930 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp @@ -9,7 +9,7 @@ #include "lldb/Host/Config.h" #if LLDB_ENABLE_PYTHON // LLDB Python header must be included first -#include "lldb-python.h" +#include "../lldb-python.h" #endif #include "lldb/Target/Process.h" #include "lldb/Utility/Log.h" @@ -18,8 +18,8 @@ #if LLDB_ENABLE_PYTHON -#include "SWIGPythonBridge.h" -#include "ScriptInterpreterPythonImpl.h" +#include "../SWIGPythonBridge.h" +#include "../ScriptInterpreterPythonImpl.h" #include "ScriptedProcessPythonInterface.h" #include "ScriptedThreadPythonInterface.h" #include <optional> @@ -33,29 +33,15 @@ ScriptedProcessPythonInterface::ScriptedProcessPythonInterface( ScriptInterpreterPythonImpl &interpreter) : ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {} -StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject( +llvm::Expected<StructuredData::GenericSP> +ScriptedProcessPythonInterface::CreatePluginObject( llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) { - if (class_name.empty()) - return {}; - - StructuredDataImpl args_impl(args_sp); - std::string error_string; - - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - lldb::ExecutionContextRefSP exe_ctx_ref_sp = + ExecutionContextRefSP exe_ctx_ref_sp = std::make_shared<ExecutionContextRef>(exe_ctx); - - PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedObject( - class_name.str().c_str(), m_interpreter.GetDictionaryName(), - exe_ctx_ref_sp, args_impl, error_string); - - m_object_instance_sp = - StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val))); - - return m_object_instance_sp; + StructuredDataImpl sd_impl(args_sp); + return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj, + exe_ctx_ref_sp, sd_impl); } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetCapabilities() { @@ -199,7 +185,7 @@ ScriptedProcessPythonInterface::GetScriptedThreadPluginName() { lldb::ScriptedThreadInterfaceSP ScriptedProcessPythonInterface::CreateScriptedThreadInterface() { - return std::make_shared<ScriptedThreadPythonInterface>(m_interpreter); + return m_interpreter.CreateScriptedThreadInterface(); } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetMetadata() { diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.h index ff03eab07648..c75caa9340f2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.h @@ -6,15 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSPYTHONINTERFACE_H -#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSPYTHONINTERFACE_H +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPROCESSPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPROCESSPYTHONINTERFACE_H #include "lldb/Host/Config.h" #if LLDB_ENABLE_PYTHON #include "ScriptedPythonInterface.h" -#include "lldb/Interpreter/ScriptedProcessInterface.h" +#include "lldb/Interpreter/Interfaces/ScriptedProcessInterface.h" #include <optional> namespace lldb_private { @@ -23,12 +23,17 @@ class ScriptedProcessPythonInterface : public ScriptedProcessInterface, public: ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter); - StructuredData::GenericSP + llvm::Expected<StructuredData::GenericSP> CreatePluginObject(const llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj = nullptr) override; + llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override { + return llvm::SmallVector<llvm::StringLiteral>( + {"read_memory_at_address", "is_alive", "get_scripted_thread_plugin"}); + } + StructuredData::DictionarySP GetCapabilities() override; Status Attach(const ProcessAttachInfo &attach_info) override; @@ -68,4 +73,4 @@ private: } // namespace lldb_private #endif // LLDB_ENABLE_PYTHON -#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSPYTHONINTERFACE_H +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPROCESSPYTHONINTERFACE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp index 1e36a81fde54..6f22503b279c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp @@ -13,9 +13,9 @@ #if LLDB_ENABLE_PYTHON // LLDB Python header must be included first -#include "lldb-python.h" +#include "../lldb-python.h" -#include "ScriptInterpreterPythonImpl.h" +#include "../ScriptInterpreterPythonImpl.h" #include "ScriptedPythonInterface.h" #include <optional> diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h index 4d0645d18aca..163659234466 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H -#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H #if LLDB_ENABLE_PYTHON @@ -18,12 +18,12 @@ #include <utility> #include "lldb/Host/Config.h" -#include "lldb/Interpreter/ScriptedInterface.h" +#include "lldb/Interpreter/Interfaces/ScriptedInterface.h" #include "lldb/Utility/DataBufferHeap.h" -#include "PythonDataObjects.h" -#include "SWIGPythonBridge.h" -#include "ScriptInterpreterPythonImpl.h" +#include "../PythonDataObjects.h" +#include "../SWIGPythonBridge.h" +#include "../ScriptInterpreterPythonImpl.h" namespace lldb_private { class ScriptInterpreterPythonImpl; @@ -32,6 +32,196 @@ public: ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); ~ScriptedPythonInterface() override = default; + enum class AbstractMethodCheckerCases { + eNotImplemented, + eNotAllocated, + eNotCallable, + eValid + }; + + llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>> + CheckAbstractMethodImplementation( + const python::PythonDictionary &class_dict) const { + + using namespace python; + + std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker; +#define SET_ERROR_AND_CONTINUE(method_name, error) \ + { \ + checker[method_name] = error; \ + continue; \ + } + + for (const llvm::StringLiteral &method_name : GetAbstractMethods()) { + if (!class_dict.HasKey(method_name)) + SET_ERROR_AND_CONTINUE(method_name, + AbstractMethodCheckerCases::eNotImplemented) + auto callable_or_err = class_dict.GetItem(method_name); + if (!callable_or_err) + SET_ERROR_AND_CONTINUE(method_name, + AbstractMethodCheckerCases::eNotAllocated) + if (!PythonCallable::Check(callable_or_err.get().get())) + SET_ERROR_AND_CONTINUE(method_name, + AbstractMethodCheckerCases::eNotCallable) + checker[method_name] = AbstractMethodCheckerCases::eValid; + } + +#undef HANDLE_ERROR + + return checker; + } + + template <typename... Args> + llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, + StructuredData::Generic *script_obj, Args... args) { + using namespace python; + using Locker = ScriptInterpreterPythonImpl::Locker; + + auto create_error = [](std::string message) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), message); + }; + + bool has_class_name = !class_name.empty(); + bool has_interpreter_dict = + !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); + if (!has_class_name && !has_interpreter_dict && !script_obj) { + if (!has_class_name) + return create_error("Missing script class name."); + else if (!has_interpreter_dict) + return create_error("Invalid script interpreter dictionary."); + else + return create_error("Missing scripting object."); + } + + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + PythonObject result = {}; + + if (script_obj) { + result = PythonObject(PyRefType::Borrowed, + static_cast<PyObject *>(script_obj->GetValue())); + } else { + auto dict = + PythonModule::MainModule().ResolveName<python::PythonDictionary>( + m_interpreter.GetDictionaryName()); + if (!dict.IsAllocated()) + return create_error( + llvm::formatv("Could not find interpreter dictionary: %s", + m_interpreter.GetDictionaryName())); + + auto init = + PythonObject::ResolveNameWithDictionary<python::PythonCallable>( + class_name, dict); + if (!init.IsAllocated()) + return create_error(llvm::formatv("Could not find script class: %s", + class_name.data())); + + std::tuple<Args...> original_args = std::forward_as_tuple(args...); + auto transformed_args = TransformArgs(original_args); + + std::string error_string; + llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo(); + if (!arg_info) { + llvm::handleAllErrors( + arg_info.takeError(), + [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, + [&](const llvm::ErrorInfoBase &E) { + error_string.append(E.message()); + }); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + error_string); + } + + llvm::Expected<PythonObject> expected_return_object = + create_error("Resulting object is not initialized."); + + std::apply( + [&init, &expected_return_object](auto &&...args) { + llvm::consumeError(expected_return_object.takeError()); + expected_return_object = init(args...); + }, + transformed_args); + + if (!expected_return_object) + return expected_return_object.takeError(); + result = expected_return_object.get(); + } + + if (!result.IsValid()) + return create_error("Resulting object is not a valid Python Object."); + if (!result.HasAttribute("__class__")) + return create_error("Resulting object doesn't have '__class__' member."); + + PythonObject obj_class = result.GetAttributeValue("__class__"); + if (!obj_class.IsValid()) + return create_error("Resulting class object is not a valid."); + if (!obj_class.HasAttribute("__name__")) + return create_error( + "Resulting object class doesn't have '__name__' member."); + PythonString obj_class_name = + obj_class.GetAttributeValue("__name__").AsType<PythonString>(); + + PythonObject object_class_mapping_proxy = + obj_class.GetAttributeValue("__dict__"); + if (!obj_class.HasAttribute("__dict__")) + return create_error( + "Resulting object class doesn't have '__dict__' member."); + + PythonCallable dict_converter = PythonModule::BuiltinsModule() + .ResolveName("dict") + .AsType<PythonCallable>(); + if (!dict_converter.IsAllocated()) + return create_error( + "Python 'builtins' module doesn't have 'dict' class."); + + PythonDictionary object_class_dict = + dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>(); + if (!object_class_dict.IsAllocated()) + return create_error("Coudn't create dictionary from resulting object " + "class mapping proxy object."); + + auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict); + if (!checker_or_err) + return checker_or_err.takeError(); + + for (const auto &method_checker : *checker_or_err) + switch (method_checker.second) { + case AbstractMethodCheckerCases::eNotImplemented: + LLDB_LOG(GetLog(LLDBLog::Script), + "Abstract method {0}.{1} not implemented.", + obj_class_name.GetString(), method_checker.first); + break; + case AbstractMethodCheckerCases::eNotAllocated: + LLDB_LOG(GetLog(LLDBLog::Script), + "Abstract method {0}.{1} not allocated.", + obj_class_name.GetString(), method_checker.first); + break; + case AbstractMethodCheckerCases::eNotCallable: + LLDB_LOG(GetLog(LLDBLog::Script), + "Abstract method {0}.{1} not callable.", + obj_class_name.GetString(), method_checker.first); + break; + case AbstractMethodCheckerCases::eValid: + LLDB_LOG(GetLog(LLDBLog::Script), + "Abstract method {0}.{1} implemented & valid.", + obj_class_name.GetString(), method_checker.first); + break; + } + + for (const auto &method_checker : *checker_or_err) + if (method_checker.second != AbstractMethodCheckerCases::eValid) + return create_error( + llvm::formatv("Abstract method {0}.{1} missing. Enable lldb " + "script log for more details.", + obj_class_name.GetString(), method_checker.first)); + + m_object_instance_sp = StructuredData::GenericSP( + new StructuredPythonObject(std::move(result))); + return m_object_instance_sp; + } + protected: template <typename T = StructuredData::ObjectSP> T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { @@ -83,10 +273,6 @@ protected: PythonObject py_return = std::move(expected_return_object.get()); - if (!py_return.IsAllocated()) - return ErrorWithMessage<T>(caller_signature, "Returned object is null.", - error); - // Now that we called the python method with the transformed arguments, // we need to interate again over both the original and transformed // parameter pack, and transform back the parameter that were passed in @@ -97,6 +283,8 @@ protected: caller_signature, "Couldn't re-assign reference and pointer arguments.", error); + if (!py_return.IsAllocated()) + return {}; return ExtractValueFromPythonObject<T>(py_return, error); } @@ -122,6 +310,18 @@ protected: return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(const StructuredDataImpl &arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + + python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + + python::PythonObject Transform(lldb::ProcessSP arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg); } @@ -146,7 +346,6 @@ protected: original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); } - void ReverseTransform(bool &original_arg, python::PythonObject transformed_arg, Status &error) { python::PythonBoolean boolean_arg = python::PythonBoolean( @@ -254,4 +453,4 @@ ScriptedPythonInterface::ExtractValueFromPythonObject< } // namespace lldb_private #endif // LLDB_ENABLE_PYTHON -#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp index 5603a1541314..18e268527eb2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp @@ -13,10 +13,10 @@ #if LLDB_ENABLE_PYTHON // LLDB Python header must be included first -#include "lldb-python.h" +#include "../lldb-python.h" -#include "SWIGPythonBridge.h" -#include "ScriptInterpreterPythonImpl.h" +#include "../SWIGPythonBridge.h" +#include "../ScriptInterpreterPythonImpl.h" #include "ScriptedThreadPythonInterface.h" #include <optional> @@ -29,37 +29,15 @@ ScriptedThreadPythonInterface::ScriptedThreadPythonInterface( ScriptInterpreterPythonImpl &interpreter) : ScriptedThreadInterface(), ScriptedPythonInterface(interpreter) {} -StructuredData::GenericSP ScriptedThreadPythonInterface::CreatePluginObject( +llvm::Expected<StructuredData::GenericSP> +ScriptedThreadPythonInterface::CreatePluginObject( const llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) { - if (class_name.empty() && !script_obj) - return {}; - - StructuredDataImpl args_impl(args_sp); - std::string error_string; - - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - PythonObject ret_val; - - if (!script_obj) { - lldb::ExecutionContextRefSP exe_ctx_ref_sp = - std::make_shared<ExecutionContextRef>(exe_ctx); - ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedObject( - class_name.str().c_str(), m_interpreter.GetDictionaryName(), - exe_ctx_ref_sp, args_impl, error_string); - } else - ret_val = PythonObject(PyRefType::Borrowed, - static_cast<PyObject *>(script_obj->GetValue())); - - if (!ret_val) - return {}; - - m_object_instance_sp = - StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val))); - - return m_object_instance_sp; + ExecutionContextRefSP exe_ctx_ref_sp = + std::make_shared<ExecutionContextRef>(exe_ctx); + StructuredDataImpl sd_impl(args_sp); + return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj, + exe_ctx_ref_sp, sd_impl); } lldb::tid_t ScriptedThreadPythonInterface::GetThreadID() { diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h index eac4941f8814..5676f7f1d675 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h @@ -6,15 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDTHREADPYTHONINTERFACE_H -#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDTHREADPYTHONINTERFACE_H +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPYTHONINTERFACE_H #include "lldb/Host/Config.h" #if LLDB_ENABLE_PYTHON #include "ScriptedPythonInterface.h" -#include "lldb/Interpreter/ScriptedProcessInterface.h" +#include "lldb/Interpreter/Interfaces/ScriptedThreadInterface.h" #include <optional> namespace lldb_private { @@ -23,11 +23,16 @@ class ScriptedThreadPythonInterface : public ScriptedThreadInterface, public: ScriptedThreadPythonInterface(ScriptInterpreterPythonImpl &interpreter); - StructuredData::GenericSP + llvm::Expected<StructuredData::GenericSP> CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj = nullptr) override; + llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override { + return llvm::SmallVector<llvm::StringLiteral>( + {"get_stop_reason", "get_register_context"}); + } + lldb::tid_t GetThreadID() override; std::optional<std::string> GetName() override; @@ -49,4 +54,4 @@ public: } // namespace lldb_private #endif // LLDB_ENABLE_PYTHON -#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDTHREADPYTHONINTERFACE_H +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPYTHONINTERFACE_H 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 eee2f6f5d43f..ea0a1cdff40f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -71,7 +71,9 @@ Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) { } static bool python_is_finalizing() { -#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7 +#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 13) || (PY_MAJOR_VERSION > 3) + return Py_IsFinalizing(); +#elif PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7 return _Py_Finalizing != nullptr; #else return _Py_IsFinalizing(); @@ -661,6 +663,20 @@ bool PythonDictionary::Check(PyObject *py_obj) { return PyDict_Check(py_obj); } +bool PythonDictionary::HasKey(const llvm::Twine &key) const { + if (!IsValid()) + return false; + + PythonString key_object(key.isSingleStringRef() ? key.getSingleStringRef() + : key.str()); + + if (int res = PyDict_Contains(m_py_obj, key_object.get()) > 0) + return res; + + PyErr_Print(); + return false; +} + uint32_t PythonDictionary::GetSize() const { if (IsValid()) return PyDict_Size(m_py_obj); @@ -1344,7 +1360,7 @@ llvm::Expected<FileSP> PythonFile::ConvertToFile(bool borrowed) { FileSP file_sp; if (borrowed) { - // In this case we we don't need to retain the python + // In this case we don't need to retain the python // object at all. file_sp = std::make_shared<NativeFile>(fd, options.get(), false); } else { diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 012f16e95e77..82eee76e42b2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -562,6 +562,8 @@ public: static bool Check(PyObject *py_obj); + bool HasKey(const llvm::Twine &key) const; + uint32_t GetSize() const; PythonList GetKeys() const; diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h index 630ab293cf93..7cdd5577919b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -116,12 +116,6 @@ public: // callbacks. Although these are scripting-language specific, their definition // depends on the public API. - static python::PythonObject LLDBSwigPythonCreateScriptedObject( - const char *python_class_name, const char *session_dictionary_name, - lldb::ExecutionContextRefSP exe_ctx_sp, - const lldb_private::StructuredDataImpl &args_impl, - std::string &error_string); - static llvm::Expected<bool> LLDBSwigPythonBreakpointCallbackFunction( const char *python_function_name, const char *session_dictionary_name, const lldb::StackFrameSP &sb_frame, 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 55b7a73712c4..ef7a2c128a22 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -14,12 +14,14 @@ // LLDB Python header must be included first #include "lldb-python.h" +#include "Interfaces/OperatingSystemPythonInterface.h" +#include "Interfaces/ScriptedPlatformPythonInterface.h" +#include "Interfaces/ScriptedProcessPythonInterface.h" +#include "Interfaces/ScriptedThreadPythonInterface.h" #include "PythonDataObjects.h" #include "PythonReadline.h" #include "SWIGPythonBridge.h" #include "ScriptInterpreterPythonImpl.h" -#include "ScriptedPlatformPythonInterface.h" -#include "ScriptedProcessPythonInterface.h" #include "lldb/API/SBError.h" #include "lldb/API/SBFrame.h" @@ -177,18 +179,31 @@ private: return; #endif +// `PyEval_ThreadsInitialized` was deprecated in Python 3.9 and removed in +// Python 3.13. It has been returning `true` always since Python 3.7. +#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9) || (PY_MAJOR_VERSION < 3) if (PyEval_ThreadsInitialized()) { +#else + if (true) { +#endif Log *log = GetLog(LLDBLog::Script); m_was_already_initialized = true; m_gil_state = PyGILState_Ensure(); LLDB_LOGV(log, "Ensured PyGILState. Previous state = {0}locked\n", m_gil_state == PyGILState_UNLOCKED ? "un" : ""); + +// `PyEval_InitThreads` was deprecated in Python 3.9 and removed in +// Python 3.13. +#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9) || (PY_MAJOR_VERSION < 3) return; } // InitThreads acquires the GIL if it hasn't been called before. PyEval_InitThreads(); +#else + } +#endif } PyGILState_STATE m_gil_state = PyGILState_UNLOCKED; @@ -412,8 +427,6 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger) m_active_io_handler(eIOHandlerNone), m_session_is_active(false), m_pty_secondary_is_open(false), m_valid_session(true), m_lock_count(0), m_command_thread_state(nullptr) { - m_scripted_platform_interface_up = - std::make_unique<ScriptedPlatformPythonInterface>(*this); m_dictionary_name.append("_dict"); StreamString run_string; @@ -582,10 +595,6 @@ void ScriptInterpreterPythonImpl::LeaveSession() { // up believing we have no thread state and PyImport_AddModule will crash if // that is the case - since that seems to only happen when destroying the // SBDebugger, we can make do without clearing up stdout and stderr - - // rdar://problem/11292882 - // When the current thread state is NULL, PyThreadState_Get() issues a fatal - // error. if (PyThreadState_GetDict()) { PythonDictionary &sys_module_dict = GetSysModuleDictionary(); if (sys_module_dict.IsValid()) { @@ -1519,6 +1528,16 @@ ScriptInterpreterPythonImpl::CreateScriptedProcessInterface() { return std::make_unique<ScriptedProcessPythonInterface>(*this); } +ScriptedThreadInterfaceSP +ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() { + return std::make_shared<ScriptedThreadPythonInterface>(*this); +} + +OperatingSystemInterfaceSP +ScriptInterpreterPythonImpl::CreateOperatingSystemInterface() { + return std::make_shared<OperatingSystemPythonInterface>(*this); +} + StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateStructuredDataFromScriptObject( ScriptObject obj) { @@ -1530,159 +1549,6 @@ ScriptInterpreterPythonImpl::CreateStructuredDataFromScriptObject( return py_obj.CreateStructuredObject(); } -StructuredData::GenericSP -ScriptInterpreterPythonImpl::OSPlugin_CreatePluginObject( - const char *class_name, lldb::ProcessSP process_sp) { - if (class_name == nullptr || class_name[0] == '\0') - return StructuredData::GenericSP(); - - if (!process_sp) - return StructuredData::GenericSP(); - - Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); - PythonObject ret_val = SWIGBridge::LLDBSWIGPythonCreateOSPlugin( - class_name, m_dictionary_name.c_str(), process_sp); - - return StructuredData::GenericSP( - new StructuredPythonObject(std::move(ret_val))); -} - -StructuredData::DictionarySP ScriptInterpreterPythonImpl::OSPlugin_RegisterInfo( - StructuredData::ObjectSP os_plugin_object_sp) { - Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); - - if (!os_plugin_object_sp) - return {}; - - StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); - if (!generic) - return {}; - - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)generic->GetValue()); - - if (!implementor.IsAllocated()) - return {}; - - llvm::Expected<PythonObject> expected_py_return = - implementor.CallMethod("get_register_info"); - - if (!expected_py_return) { - llvm::consumeError(expected_py_return.takeError()); - return {}; - } - - PythonObject py_return = std::move(expected_py_return.get()); - - if (py_return.get()) { - PythonDictionary result_dict(PyRefType::Borrowed, py_return.get()); - return result_dict.CreateStructuredDictionary(); - } - return StructuredData::DictionarySP(); -} - -StructuredData::ArraySP ScriptInterpreterPythonImpl::OSPlugin_ThreadsInfo( - StructuredData::ObjectSP os_plugin_object_sp) { - Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); - if (!os_plugin_object_sp) - return {}; - - StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); - if (!generic) - return {}; - - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)generic->GetValue()); - - if (!implementor.IsAllocated()) - return {}; - - llvm::Expected<PythonObject> expected_py_return = - implementor.CallMethod("get_thread_info"); - - if (!expected_py_return) { - llvm::consumeError(expected_py_return.takeError()); - return {}; - } - - PythonObject py_return = std::move(expected_py_return.get()); - - if (py_return.get()) { - PythonList result_list(PyRefType::Borrowed, py_return.get()); - return result_list.CreateStructuredArray(); - } - return StructuredData::ArraySP(); -} - -StructuredData::StringSP -ScriptInterpreterPythonImpl::OSPlugin_RegisterContextData( - StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid) { - Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); - - if (!os_plugin_object_sp) - return {}; - - StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); - if (!generic) - return {}; - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)generic->GetValue()); - - if (!implementor.IsAllocated()) - return {}; - - llvm::Expected<PythonObject> expected_py_return = - implementor.CallMethod("get_register_data", tid); - - if (!expected_py_return) { - llvm::consumeError(expected_py_return.takeError()); - return {}; - } - - PythonObject py_return = std::move(expected_py_return.get()); - - if (py_return.get()) { - PythonBytes result(PyRefType::Borrowed, py_return.get()); - return result.CreateStructuredString(); - } - return {}; -} - -StructuredData::DictionarySP ScriptInterpreterPythonImpl::OSPlugin_CreateThread( - StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid, - lldb::addr_t context) { - Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); - - if (!os_plugin_object_sp) - return {}; - - StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); - if (!generic) - return {}; - - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)generic->GetValue()); - - if (!implementor.IsAllocated()) - return {}; - - llvm::Expected<PythonObject> expected_py_return = - implementor.CallMethod("create_thread", tid, context); - - if (!expected_py_return) { - llvm::consumeError(expected_py_return.takeError()); - return {}; - } - - PythonObject py_return = std::move(expected_py_return.get()); - - if (py_return.get()) { - PythonDictionary result_dict(PyRefType::Borrowed, py_return.get()); - return result_dict.CreateStructuredDictionary(); - } - return StructuredData::DictionarySP(); -} - StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan( const char *class_name, const StructuredDataImpl &args_data, std::string &error_str, lldb::ThreadPlanSP thread_plan_sp) { @@ -1783,7 +1649,7 @@ lldb::StateType ScriptInterpreterPythonImpl::ScriptedThreadPlanGetRunState( bool ScriptInterpreterPythonImpl::ScriptedThreadPlanGetStopDescription( - StructuredData::ObjectSP implementor_sp, lldb_private::Stream *stream, + StructuredData::ObjectSP implementor_sp, lldb_private::Stream *stream, bool &script_error) { StructuredData::Generic *generic = nullptr; if (implementor_sp) @@ -2442,24 +2308,11 @@ ConstString ScriptInterpreterPythonImpl::GetSyntheticTypeName( } PythonObject py_return = std::move(expected_py_return.get()); + if (!py_return.IsAllocated() || !PythonString::Check(py_return.get())) + return {}; - ConstString ret_val; - bool got_string = false; - std::string buffer; - - if (py_return.IsAllocated() && PythonString::Check(py_return.get())) { - PythonString py_string(PyRefType::Borrowed, py_return.get()); - llvm::StringRef return_data(py_string.GetString()); - if (!return_data.empty()) { - buffer.assign(return_data.data(), return_data.size()); - got_string = true; - } - } - - if (got_string) - ret_val.SetCStringWithLength(buffer.c_str(), buffer.size()); - - return ret_val; + PythonString type_name(PyRefType::Borrowed, py_return.get()); + return ConstString(type_name.GetString()); } bool ScriptInterpreterPythonImpl::RunScriptFormatKeyword( 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 01db6c520300..a33499816d8d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -134,23 +134,9 @@ public: lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override; - StructuredData::GenericSP - OSPlugin_CreatePluginObject(const char *class_name, - lldb::ProcessSP process_sp) override; - - StructuredData::DictionarySP - OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugin_object_sp) override; + lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override; - StructuredData::ArraySP - OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin_object_sp) override; - - StructuredData::StringSP - OSPlugin_RegisterContextData(StructuredData::ObjectSP os_plugin_object_sp, - lldb::tid_t thread_id) override; - - StructuredData::DictionarySP - OSPlugin_CreateThread(StructuredData::ObjectSP os_plugin_object_sp, - lldb::tid_t tid, lldb::addr_t context) override; + lldb::OperatingSystemInterfaceSP CreateOperatingSystemInterface() override; StructuredData::ObjectSP LoadPluginModule(const FileSpec &file_spec, 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 a5818915773c..c46dc54c912e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp @@ -32,6 +32,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" +#include "llvm/ADT/StringMap.h" + #define DARWIN_LOG_TYPE_VALUE "DarwinLog" using namespace lldb; @@ -117,8 +119,8 @@ enum { class StructuredDataDarwinLogProperties : public Properties { public: - static ConstString &GetSettingName() { - static ConstString g_setting_name("darwin-log"); + static llvm::StringRef GetSettingName() { + static constexpr llvm::StringLiteral g_setting_name("darwin-log"); return g_setting_name; } @@ -183,21 +185,20 @@ public: std::function<FilterRuleSP(bool accept, size_t attribute_index, const std::string &op_arg, Status &error)>; - static void RegisterOperation(ConstString operation, + static void RegisterOperation(llvm::StringRef operation, const OperationCreationFunc &creation_func) { GetCreationFuncMap().insert(std::make_pair(operation, creation_func)); } static FilterRuleSP CreateRule(bool match_accepts, size_t attribute, - ConstString operation, + llvm::StringRef operation, const std::string &op_arg, Status &error) { // Find the creation func for this type of filter rule. auto map = GetCreationFuncMap(); auto find_it = map.find(operation); if (find_it == map.end()) { - error.SetErrorStringWithFormat("unknown filter operation \"" - "%s\"", - operation.GetCString()); + error.SetErrorStringWithFormatv("unknown filter operation \"{0}\"", + operation); return FilterRuleSP(); } @@ -217,7 +218,7 @@ public: dict_p->AddStringItem("attribute", s_filter_attributes[m_attribute_index]); // Indicate the type of the rule. - dict_p->AddStringItem("type", GetOperationType().GetCString()); + dict_p->AddStringItem("type", GetOperationType()); // Let the rule add its own specific details here. DoSerialization(*dict_p); @@ -227,10 +228,10 @@ public: virtual void Dump(Stream &stream) const = 0; - ConstString GetOperationType() const { return m_operation; } + llvm::StringRef GetOperationType() const { return m_operation; } protected: - FilterRule(bool accept, size_t attribute_index, ConstString operation) + FilterRule(bool accept, size_t attribute_index, llvm::StringRef operation) : m_accept(accept), m_attribute_index(attribute_index), m_operation(operation) {} @@ -243,7 +244,7 @@ protected: } private: - using CreationFuncMap = std::map<ConstString, OperationCreationFunc>; + using CreationFuncMap = llvm::StringMap<OperationCreationFunc>; static CreationFuncMap &GetCreationFuncMap() { static CreationFuncMap s_map; @@ -252,7 +253,8 @@ private: const bool m_accept; const size_t m_attribute_index; - const ConstString m_operation; + // The lifetime of m_operation should be static. + const llvm::StringRef m_operation; }; using FilterRules = std::vector<FilterRuleSP>; @@ -296,8 +298,8 @@ private: return FilterRuleSP(new RegexFilterRule(accept, attribute_index, op_arg)); } - static ConstString StaticGetOperation() { - static ConstString s_operation("regex"); + static llvm::StringRef StaticGetOperation() { + static constexpr llvm::StringLiteral s_operation("regex"); return s_operation; } @@ -341,8 +343,8 @@ private: new ExactMatchFilterRule(accept, attribute_index, op_arg)); } - static ConstString StaticGetOperation() { - static ConstString s_operation("match"); + static llvm::StringRef StaticGetOperation() { + static constexpr llvm::StringLiteral s_operation("match"); return s_operation; } @@ -701,7 +703,7 @@ private: // add filter spec auto rule_sp = FilterRule::CreateRule( - accept, attribute_index, ConstString(operation), + accept, attribute_index, operation, std::string(rule_text.substr(operation_end_pos + 1)), error); if (rule_sp && error.Success()) @@ -764,7 +766,7 @@ protected: result.AppendWarning(stream.GetString()); } - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { // First off, set the global sticky state of enable/disable based on this // command execution. s_is_explicitly_enabled = m_enable; @@ -788,14 +790,14 @@ protected: if (!process_sp) { // No active process, so there is nothing more to do right now. result.SetStatus(eReturnStatusSuccessFinishNoResult); - return true; + return; } // If the process is no longer alive, we can't do this now. We'll catch it // the next time the process is started up. if (!process_sp->IsAlive()) { result.SetStatus(eReturnStatusSuccessFinishNoResult); - return true; + return; } // Get the plugin for the process. @@ -836,7 +838,6 @@ protected: // one this command is setup to do. plugin.SetEnabled(m_enable); } - return result.Succeeded(); } Options *GetOptions() override { @@ -859,7 +860,7 @@ public: "plugin structured-data darwin-log status") {} protected: - bool DoExecute(Args &command, CommandReturnObject &result) override { + void DoExecute(Args &command, CommandReturnObject &result) override { auto &stream = result.GetOutputStream(); // Figure out if we've got a process. If so, we can tell if DarwinLog is @@ -889,7 +890,7 @@ protected: if (!options_sp) { // Nothing more to do. result.SetStatus(eReturnStatusSuccessFinishResult); - return true; + return; } // Print filter rules @@ -922,7 +923,6 @@ protected: options_sp->GetFallthroughAccepts() ? "accept" : "reject"); result.SetStatus(eReturnStatusSuccessFinishResult); - return true; } }; @@ -1254,8 +1254,6 @@ void StructuredDataDarwinLog::ModulesDidLoad(Process &process, return; } - const ConstString logging_module_name = ConstString(logging_module_cstr); - // We need to see libtrace in the list of modules before we can enable // tracing for the target process. bool found_logging_support_module = false; @@ -1266,7 +1264,7 @@ void StructuredDataDarwinLog::ModulesDidLoad(Process &process, auto &file_spec = module_sp->GetFileSpec(); found_logging_support_module = - (file_spec.GetFilename() == logging_module_name); + (file_spec.GetFilename() == logging_module_cstr); if (found_logging_support_module) break; } @@ -1276,8 +1274,7 @@ void StructuredDataDarwinLog::ModulesDidLoad(Process &process, "StructuredDataDarwinLog::%s logging module %s " "has not yet been loaded, can't set a breakpoint " "yet (process uid %u)", - __FUNCTION__, logging_module_name.AsCString(), - process.GetUniqueID()); + __FUNCTION__, logging_module_cstr, process.GetUniqueID()); return; } @@ -1287,8 +1284,7 @@ void StructuredDataDarwinLog::ModulesDidLoad(Process &process, LLDB_LOGF(log, "StructuredDataDarwinLog::%s post-init hook breakpoint " "set for logging module %s (process uid %u)", - __FUNCTION__, logging_module_name.AsCString(), - process.GetUniqueID()); + __FUNCTION__, logging_module_cstr, process.GetUniqueID()); // We need to try the enable here as well, which will succeed in the event // that we're attaching to (rather than launching) the process and the 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 cd52233cc8cc..729d6af02402 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -448,15 +448,6 @@ void SymbolFileBreakpad::FindFunctions(const RegularExpression ®ex, // TODO } -void SymbolFileBreakpad::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, - TypeMap &types) {} - -void SymbolFileBreakpad::FindTypes( - llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {} - void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { Log *log = GetLog(LLDBLog::Symbols); Module &module = *m_objfile_sp->GetModule(); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h index 4a01a64202ee..214fbdd3ff3a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -118,15 +118,6 @@ public: void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) override; - void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, - TypeMap &types) override; - - void FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, - TypeMap &types) override; - llvm::Expected<lldb::TypeSystemSP> GetTypeSystemForLanguage(lldb::LanguageType language) override { return llvm::make_error<llvm::StringError>( diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/CTFTypes.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/CTFTypes.h new file mode 100644 index 000000000000..c1016b2af0c6 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/CTFTypes.h @@ -0,0 +1,203 @@ +//===-- CTFTypes.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_SYMBOLFILE_CTF_CTFTYPES_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_CTF_CTFTYPES_H + +#include "lldb/lldb-types.h" +#include "llvm/ADT/StringRef.h" + +namespace lldb_private { + +struct CTFType { + enum Kind : uint32_t { + eUnknown = 0, + eInteger = 1, + eFloat = 2, + ePointer = 3, + eArray = 4, + eFunction = 5, + eStruct = 6, + eUnion = 7, + eEnum = 8, + eForward = 9, + eTypedef = 10, + eVolatile = 11, + eConst = 12, + eRestrict = 13, + eSlice = 14, + }; + + Kind kind; + lldb::user_id_t uid; + llvm::StringRef name; + + CTFType(Kind kind, lldb::user_id_t uid, llvm::StringRef name) + : kind(kind), uid(uid), name(name) {} +}; + +struct CTFInteger : public CTFType { + CTFInteger(lldb::user_id_t uid, llvm::StringRef name, uint32_t bits, + uint32_t encoding) + : CTFType(eInteger, uid, name), bits(bits), encoding(encoding) {} + + static bool classof(const CTFType *T) { return T->kind == eInteger; } + + uint32_t bits; + uint32_t encoding; +}; + +struct CTFModifier : public CTFType { +protected: + CTFModifier(Kind kind, lldb::user_id_t uid, uint32_t type) + : CTFType(kind, uid, ""), type(type) {} + + static bool classof(const CTFType *T) { + return T->kind == ePointer || T->kind == eConst || T->kind == eVolatile || + T->kind == eRestrict; + } + +public: + uint32_t type; +}; + +struct CTFPointer : public CTFModifier { + CTFPointer(lldb::user_id_t uid, uint32_t type) + : CTFModifier(ePointer, uid, type) {} + + static bool classof(const CTFType *T) { return T->kind == ePointer; } +}; + +struct CTFConst : public CTFModifier { + CTFConst(lldb::user_id_t uid, uint32_t type) + : CTFModifier(eConst, uid, type) {} + + static bool classof(const CTFType *T) { return T->kind == eConst; } +}; + +struct CTFVolatile : public CTFModifier { + CTFVolatile(lldb::user_id_t uid, uint32_t type) + : CTFModifier(eVolatile, uid, type) {} + + static bool classof(const CTFType *T) { return T->kind == eVolatile; } +}; + +struct CTFRestrict : public CTFModifier { + CTFRestrict(lldb::user_id_t uid, uint32_t type) + : CTFModifier(eRestrict, uid, type) {} + static bool classof(const CTFType *T) { return T->kind == eRestrict; } +}; + +struct CTFTypedef : public CTFType { + CTFTypedef(lldb::user_id_t uid, llvm::StringRef name, uint32_t type) + : CTFType(eTypedef, uid, name), type(type) {} + + static bool classof(const CTFType *T) { return T->kind == eTypedef; } + + uint32_t type; +}; + +struct CTFArray : public CTFType { + CTFArray(lldb::user_id_t uid, llvm::StringRef name, uint32_t type, + uint32_t index, uint32_t nelems) + : CTFType(eArray, uid, name), type(type), index(index), nelems(nelems) {} + + static bool classof(const CTFType *T) { return T->kind == eArray; } + + uint32_t type; + uint32_t index; + uint32_t nelems; +}; + +struct CTFEnum : public CTFType { + struct Value { + Value(llvm::StringRef name, uint32_t value) : name(name), value(value){}; + llvm::StringRef name; + uint32_t value; + }; + + CTFEnum(lldb::user_id_t uid, llvm::StringRef name, uint32_t nelems, + uint32_t size, std::vector<Value> values) + : CTFType(eEnum, uid, name), nelems(nelems), size(size), + values(std::move(values)) { + assert(this->values.size() == nelems); + } + + static bool classof(const CTFType *T) { return T->kind == eEnum; } + + uint32_t nelems; + uint32_t size; + std::vector<Value> values; +}; + +struct CTFFunction : public CTFType { + CTFFunction(lldb::user_id_t uid, llvm::StringRef name, uint32_t nargs, + uint32_t return_type, std::vector<uint32_t> args, bool variadic) + : CTFType(eFunction, uid, name), nargs(nargs), return_type(return_type), + args(std::move(args)), variadic(variadic) {} + + static bool classof(const CTFType *T) { return T->kind == eFunction; } + + uint32_t nargs; + uint32_t return_type; + + std::vector<uint32_t> args; + bool variadic = false; +}; + +struct CTFRecord : public CTFType { +public: + struct Field { + Field(llvm::StringRef name, uint32_t type, uint64_t offset) + : name(name), type(type), offset(offset) {} + + llvm::StringRef name; + uint32_t type; + uint64_t offset; + }; + + CTFRecord(Kind kind, lldb::user_id_t uid, llvm::StringRef name, + uint32_t nfields, uint32_t size, std::vector<Field> fields) + : CTFType(kind, uid, name), nfields(nfields), size(size), + fields(std::move(fields)) {} + + static bool classof(const CTFType *T) { + return T->kind == eStruct || T->kind == eUnion; + } + + uint32_t nfields; + uint32_t size; + std::vector<Field> fields; +}; + +struct CTFStruct : public CTFRecord { + CTFStruct(lldb::user_id_t uid, llvm::StringRef name, uint32_t nfields, + uint32_t size, std::vector<Field> fields) + : CTFRecord(eStruct, uid, name, nfields, size, std::move(fields)){}; + + static bool classof(const CTFType *T) { return T->kind == eStruct; } +}; + +struct CTFUnion : public CTFRecord { + CTFUnion(lldb::user_id_t uid, llvm::StringRef name, uint32_t nfields, + uint32_t size, std::vector<Field> fields) + : CTFRecord(eUnion, uid, name, nfields, size, std::move(fields)){}; + + static bool classof(const CTFType *T) { return T->kind == eUnion; } +}; + +struct CTFForward : public CTFType { + CTFForward(lldb::user_id_t uid, llvm::StringRef name) + : CTFType(eForward, uid, name) {} + + static bool classof(const CTFType *T) { return T->kind == eForward; } +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_CTF_CTFTYPES_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp index 88926baa7a6e..d192944bb9d0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp @@ -10,7 +10,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamBuffer.h" #include "lldb/Host/Config.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" @@ -26,6 +25,7 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/StreamBuffer.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #include "llvm/Support/MemoryBuffer.h" @@ -317,31 +317,27 @@ uint32_t GetVLen(uint32_t data) { static uint32_t GetBytes(uint32_t bits) { return bits / sizeof(unsigned); } -static clang::TagTypeKind TranslateRecordKind(SymbolFileCTF::TypeKind type) { +static clang::TagTypeKind TranslateRecordKind(CTFType::Kind type) { switch (type) { - case SymbolFileCTF::TypeKind::eStruct: - return clang::TTK_Struct; - case SymbolFileCTF::TypeKind::eUnion: - return clang::TTK_Union; + case CTFType::Kind::eStruct: + return clang::TagTypeKind::Struct; + case CTFType::Kind::eUnion: + return clang::TagTypeKind::Union; default: lldbassert(false && "Invalid record kind!"); - return clang::TTK_Struct; + return clang::TagTypeKind::Struct; } } -llvm::Expected<TypeSP> SymbolFileCTF::ParseInteger(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name) { - const uint32_t vdata = m_data.GetU32(&offset); - const uint32_t bits = GetBits(vdata); - const uint32_t encoding = GetEncoding(vdata); - - lldb::BasicType basic_type = TypeSystemClang::GetBasicTypeEnumeration(name); +llvm::Expected<TypeSP> +SymbolFileCTF::CreateInteger(const CTFInteger &ctf_integer) { + lldb::BasicType basic_type = + TypeSystemClang::GetBasicTypeEnumeration(ctf_integer.name); if (basic_type == eBasicTypeInvalid) return llvm::make_error<llvm::StringError>( llvm::formatv("unsupported integer type: no corresponding basic clang " "type for '{0}'", - name), + ctf_integer.name), llvm::inconvertibleErrorCode()); CompilerType compiler_type = m_ast->GetBasicType(basic_type); @@ -353,104 +349,98 @@ llvm::Expected<TypeSP> SymbolFileCTF::ParseInteger(lldb::offset_t &offset, return llvm::make_error<llvm::StringError>( llvm::formatv( "Found compiler type for '{0}' but it's not an integer type: {1}", - name, compiler_type.GetDisplayTypeName().GetStringRef()), + ctf_integer.name, + compiler_type.GetDisplayTypeName().GetStringRef()), llvm::inconvertibleErrorCode()); // Make sure the signing matches between the CTF and the compiler type. - const bool type_is_signed = (encoding & IntEncoding::eSigned); + const bool type_is_signed = (ctf_integer.encoding & IntEncoding::eSigned); if (compiler_type_is_signed != type_is_signed) return llvm::make_error<llvm::StringError>( llvm::formatv("Found integer compiler type for {0} but compiler type " "is {1} and {0} is {2}", - name, compiler_type_is_signed ? "signed" : "unsigned", + ctf_integer.name, + compiler_type_is_signed ? "signed" : "unsigned", type_is_signed ? "signed" : "unsigned"), llvm::inconvertibleErrorCode()); } Declaration decl; - return MakeType(uid, ConstString(name), GetBytes(bits), nullptr, - LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, - compiler_type, lldb_private::Type::ResolveState::Full); + return MakeType(ctf_integer.uid, ConstString(ctf_integer.name), + GetBytes(ctf_integer.bits), nullptr, LLDB_INVALID_UID, + lldb_private::Type::eEncodingIsUID, decl, compiler_type, + lldb_private::Type::ResolveState::Full); } llvm::Expected<lldb::TypeSP> -SymbolFileCTF::ParseModifierType(lldb::offset_t &offset, lldb::user_id_t uid, - uint32_t kind, uint32_t type) { - TypeSP ref_type = GetTypeForUID(type); +SymbolFileCTF::CreateModifier(const CTFModifier &ctf_modifier) { + Type *ref_type = ResolveTypeUID(ctf_modifier.type); if (!ref_type) return llvm::make_error<llvm::StringError>( - llvm::formatv("Could not find modified type: {0}", type), + llvm::formatv("Could not find modified type: {0}", ctf_modifier.type), llvm::inconvertibleErrorCode()); CompilerType compiler_type; - switch (kind) { - case TypeKind::ePointer: + switch (ctf_modifier.kind) { + case CTFType::ePointer: compiler_type = ref_type->GetFullCompilerType().GetPointerType(); break; - case TypeKind::eConst: + case CTFType::eConst: compiler_type = ref_type->GetFullCompilerType().AddConstModifier(); break; - case TypeKind::eVolatile: + case CTFType::eVolatile: compiler_type = ref_type->GetFullCompilerType().AddVolatileModifier(); break; - case TypeKind::eRestrict: + case CTFType::eRestrict: compiler_type = ref_type->GetFullCompilerType().AddRestrictModifier(); break; default: return llvm::make_error<llvm::StringError>( - llvm::formatv("ParseModifierType called with unsupported kind: {0}", - kind), + llvm::formatv("ParseModifier called with unsupported kind: {0}", + ctf_modifier.kind), llvm::inconvertibleErrorCode()); } Declaration decl; - return MakeType(uid, ConstString(), 0, nullptr, LLDB_INVALID_UID, + return MakeType(ctf_modifier.uid, ConstString(), 0, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, compiler_type, lldb_private::Type::ResolveState::Full); } -llvm::Expected<lldb::TypeSP> SymbolFileCTF::ParseTypedef(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name, - uint32_t type) { - TypeSP underlying_type = GetTypeForUID(type); +llvm::Expected<lldb::TypeSP> +SymbolFileCTF::CreateTypedef(const CTFTypedef &ctf_typedef) { + Type *underlying_type = ResolveTypeUID(ctf_typedef.type); if (!underlying_type) return llvm::make_error<llvm::StringError>( - llvm::formatv("Could not find typedef underlying type: {0}", type), + llvm::formatv("Could not find typedef underlying type: {0}", + ctf_typedef.type), llvm::inconvertibleErrorCode()); CompilerType target_ast_type = underlying_type->GetFullCompilerType(); clang::DeclContext *decl_ctx = m_ast->GetTranslationUnitDecl(); CompilerType ast_typedef = target_ast_type.CreateTypedef( - name.data(), m_ast->CreateDeclContext(decl_ctx), 0); + ctf_typedef.name.data(), m_ast->CreateDeclContext(decl_ctx), 0); Declaration decl; - return MakeType(uid, ConstString(name), 0, nullptr, LLDB_INVALID_UID, - lldb_private::Type::eEncodingIsUID, decl, ast_typedef, - lldb_private::Type::ResolveState::Full); + return MakeType(ctf_typedef.uid, ConstString(ctf_typedef.name), 0, nullptr, + LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, + ast_typedef, lldb_private::Type::ResolveState::Full); } -llvm::Expected<lldb::TypeSP> SymbolFileCTF::ParseArray(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name) { - ctf_array_t ctf_array; - ctf_array.contents = m_data.GetU32(&offset); - ctf_array.index = m_data.GetU32(&offset); - ctf_array.nelems = m_data.GetU32(&offset); - - TypeSP element_type = GetTypeForUID(ctf_array.contents); +llvm::Expected<lldb::TypeSP> +SymbolFileCTF::CreateArray(const CTFArray &ctf_array) { + Type *element_type = ResolveTypeUID(ctf_array.type); if (!element_type) return llvm::make_error<llvm::StringError>( - llvm::formatv("Could not find array element type: {0}", - ctf_array.contents), + llvm::formatv("Could not find array element type: {0}", ctf_array.type), llvm::inconvertibleErrorCode()); std::optional<uint64_t> element_size = element_type->GetByteSize(nullptr); if (!element_size) return llvm::make_error<llvm::StringError>( llvm::formatv("could not get element size of type: {0}", - ctf_array.contents), + ctf_array.type), llvm::inconvertibleErrorCode()); uint64_t size = ctf_array.nelems * *element_size; @@ -460,149 +450,256 @@ llvm::Expected<lldb::TypeSP> SymbolFileCTF::ParseArray(lldb::offset_t &offset, /*is_gnu_vector*/ false); Declaration decl; - return MakeType(uid, ConstString(), size, nullptr, LLDB_INVALID_UID, + return MakeType(ctf_array.uid, ConstString(), size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, compiler_type, lldb_private::Type::ResolveState::Full); } -llvm::Expected<lldb::TypeSP> SymbolFileCTF::ParseEnum(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name, - uint32_t elements, - uint32_t size) { +llvm::Expected<lldb::TypeSP> +SymbolFileCTF::CreateEnum(const CTFEnum &ctf_enum) { Declaration decl; CompilerType enum_type = m_ast->CreateEnumerationType( - name, m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), decl, - m_ast->GetBasicType(eBasicTypeInt), + ctf_enum.name, m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), + decl, m_ast->GetBasicType(eBasicTypeInt), /*is_scoped=*/false); - for (uint32_t i = 0; i < elements; ++i) { - ctf_enum_t ctf_enum; - ctf_enum.name = m_data.GetU32(&offset); - ctf_enum.value = m_data.GetU32(&offset); - - llvm::StringRef value_name = ReadString(ctf_enum.name); - const uint32_t value = ctf_enum.value; - + for (const CTFEnum::Value &value : ctf_enum.values) { Declaration value_decl; - m_ast->AddEnumerationValueToEnumerationType(enum_type, value_decl, - value_name.data(), value, size); + m_ast->AddEnumerationValueToEnumerationType( + enum_type, value_decl, value.name.data(), value.value, ctf_enum.size); } + TypeSystemClang::CompleteTagDeclarationDefinition(enum_type); - return MakeType(uid, ConstString(), 0, nullptr, LLDB_INVALID_UID, + return MakeType(ctf_enum.uid, ConstString(), 0, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, enum_type, lldb_private::Type::ResolveState::Full); } llvm::Expected<lldb::TypeSP> -SymbolFileCTF::ParseFunction(lldb::offset_t &offset, lldb::user_id_t uid, - llvm::StringRef name, uint32_t num_args, - uint32_t type) { +SymbolFileCTF::CreateFunction(const CTFFunction &ctf_function) { std::vector<CompilerType> arg_types; - arg_types.reserve(num_args); - - bool is_variadic = false; - for (uint32_t i = 0; i < num_args; ++i) { - const uint32_t arg_uid = m_data.GetU32(&offset); - - // If the last argument is 0, this is a variadic function. - if (arg_uid == 0) { - is_variadic = true; - break; - } - - if (TypeSP arg_type = GetTypeForUID(arg_uid)) + for (uint32_t arg : ctf_function.args) { + if (Type *arg_type = ResolveTypeUID(arg)) arg_types.push_back(arg_type->GetFullCompilerType()); } - // If the number of arguments is odd, a single uint32_t of padding is inserted - // to maintain alignment. - if (num_args % 2 == 1) - m_data.GetU32(&offset); - - TypeSP ret_type = GetTypeForUID(type); + Type *ret_type = ResolveTypeUID(ctf_function.return_type); if (!ret_type) return llvm::make_error<llvm::StringError>( - llvm::formatv("Could not find function return type: {0}", type), + llvm::formatv("Could not find function return type: {0}", + ctf_function.return_type), llvm::inconvertibleErrorCode()); CompilerType func_type = m_ast->CreateFunctionType( ret_type->GetFullCompilerType(), arg_types.data(), arg_types.size(), - is_variadic, 0, clang::CallingConv::CC_C); + ctf_function.variadic, 0, clang::CallingConv::CC_C); Declaration decl; - return MakeType(uid, ConstString(name), 0, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, decl, func_type, + return MakeType(ctf_function.uid, ConstString(ctf_function.name), 0, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, func_type, lldb_private::Type::ResolveState::Full); } llvm::Expected<lldb::TypeSP> -SymbolFileCTF::ParseRecord(lldb::offset_t &offset, lldb::user_id_t uid, - llvm::StringRef name, uint32_t kind, uint32_t fields, - uint32_t size) { - const clang::TagTypeKind tag_kind = - TranslateRecordKind(static_cast<TypeKind>(kind)); - - CompilerType union_type = - m_ast->CreateRecordType(nullptr, OptionalClangModuleID(), eAccessPublic, - name.data(), tag_kind, eLanguageTypeC); - - m_ast->StartTagDeclarationDefinition(union_type); - for (uint32_t i = 0; i < fields; ++i) { - ctf_member_t ctf_member; - ctf_member.name = m_data.GetU32(&offset); - ctf_member.type = m_data.GetU32(&offset); - ctf_member.offset = m_data.GetU16(&offset); - ctf_member.padding = m_data.GetU16(&offset); - - llvm::StringRef member_name = ReadString(ctf_member.name); - const uint32_t member_type_uid = ctf_member.type; - - if (TypeSP member_type = GetTypeForUID(member_type_uid)) { - const uint32_t member_size = - member_type->GetByteSize(nullptr).value_or(0); - TypeSystemClang::AddFieldToRecordType(union_type, member_name, - member_type->GetFullCompilerType(), - eAccessPublic, member_size); +SymbolFileCTF::CreateRecord(const CTFRecord &ctf_record) { + const clang::TagTypeKind tag_kind = TranslateRecordKind(ctf_record.kind); + CompilerType record_type = m_ast->CreateRecordType( + nullptr, OptionalClangModuleID(), eAccessPublic, ctf_record.name.data(), + llvm::to_underlying(tag_kind), eLanguageTypeC); + m_compiler_types[record_type.GetOpaqueQualType()] = &ctf_record; + Declaration decl; + return MakeType(ctf_record.uid, ConstString(ctf_record.name), ctf_record.size, + nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, + decl, record_type, lldb_private::Type::ResolveState::Forward); +} + +bool SymbolFileCTF::CompleteType(CompilerType &compiler_type) { + // Check if we have a CTF type for the given incomplete compiler type. + auto it = m_compiler_types.find(compiler_type.GetOpaqueQualType()); + if (it == m_compiler_types.end()) + return false; + + const CTFType *ctf_type = it->second; + assert(ctf_type && "m_compiler_types should only contain valid CTF types"); + + // We only support resolving record types. + assert(llvm::isa<CTFRecord>(ctf_type)); + + // Cast to the appropriate CTF type. + const CTFRecord *ctf_record = static_cast<const CTFRecord *>(ctf_type); + + // If any of the fields are incomplete, we cannot complete the type. + for (const CTFRecord::Field &field : ctf_record->fields) { + if (!ResolveTypeUID(field.type)) { + LLDB_LOG(GetLog(LLDBLog::Symbols), + "Cannot complete type {0} because field {1} is incomplete", + ctf_type->uid, field.type); + return false; } } - m_ast->CompleteTagDeclarationDefinition(union_type); + // Complete the record type. + m_ast->StartTagDeclarationDefinition(compiler_type); + for (const CTFRecord::Field &field : ctf_record->fields) { + Type *field_type = ResolveTypeUID(field.type); + assert(field_type && "field must be complete"); + const uint32_t field_size = field_type->GetByteSize(nullptr).value_or(0); + TypeSystemClang::AddFieldToRecordType(compiler_type, field.name, + field_type->GetFullCompilerType(), + eAccessPublic, field_size); + } + m_ast->CompleteTagDeclarationDefinition(compiler_type); + + // Now that the compiler type is complete, we don't need to remember it + // anymore and can remove the CTF record type. + m_compiler_types.erase(compiler_type.GetOpaqueQualType()); + m_ctf_types.erase(ctf_type->uid); + + return true; +} + +llvm::Expected<lldb::TypeSP> +SymbolFileCTF::CreateForward(const CTFForward &ctf_forward) { + CompilerType forward_compiler_type = m_ast->CreateRecordType( + nullptr, OptionalClangModuleID(), eAccessPublic, ctf_forward.name, + llvm::to_underlying(clang::TagTypeKind::Struct), eLanguageTypeC); Declaration decl; - return MakeType(uid, ConstString(name), size, nullptr, LLDB_INVALID_UID, - lldb_private::Type::eEncodingIsUID, decl, union_type, - lldb_private::Type::ResolveState::Full); + return MakeType(ctf_forward.uid, ConstString(ctf_forward.name), 0, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, + forward_compiler_type, Type::ResolveState::Forward); +} + +llvm::Expected<TypeSP> SymbolFileCTF::CreateType(CTFType *ctf_type) { + if (!ctf_type) + return llvm::make_error<llvm::StringError>( + "cannot create type for unparsed type", llvm::inconvertibleErrorCode()); + + switch (ctf_type->kind) { + case CTFType::Kind::eInteger: + return CreateInteger(*static_cast<CTFInteger *>(ctf_type)); + case CTFType::Kind::eConst: + case CTFType::Kind::ePointer: + case CTFType::Kind::eRestrict: + case CTFType::Kind::eVolatile: + return CreateModifier(*static_cast<CTFModifier *>(ctf_type)); + case CTFType::Kind::eTypedef: + return CreateTypedef(*static_cast<CTFTypedef *>(ctf_type)); + case CTFType::Kind::eArray: + return CreateArray(*static_cast<CTFArray *>(ctf_type)); + case CTFType::Kind::eEnum: + return CreateEnum(*static_cast<CTFEnum *>(ctf_type)); + case CTFType::Kind::eFunction: + return CreateFunction(*static_cast<CTFFunction *>(ctf_type)); + case CTFType::Kind::eStruct: + case CTFType::Kind::eUnion: + return CreateRecord(*static_cast<CTFRecord *>(ctf_type)); + case CTFType::Kind::eForward: + return CreateForward(*static_cast<CTFForward *>(ctf_type)); + case CTFType::Kind::eUnknown: + case CTFType::Kind::eFloat: + case CTFType::Kind::eSlice: + return llvm::make_error<llvm::StringError>( + llvm::formatv("unsupported type (uid = {0}, name = {1}, kind = {2})", + ctf_type->uid, ctf_type->name, ctf_type->kind), + llvm::inconvertibleErrorCode()); + } } -llvm::Expected<TypeSP> SymbolFileCTF::ParseType( - lldb::offset_t &offset, lldb::user_id_t uid, llvm::StringRef name, - uint32_t kind, uint32_t variable_length, uint32_t type, uint32_t size) { +llvm::Expected<std::unique_ptr<CTFType>> +SymbolFileCTF::ParseType(lldb::offset_t &offset, lldb::user_id_t uid) { + ctf_stype_t ctf_stype; + ctf_stype.name = m_data.GetU32(&offset); + ctf_stype.info = m_data.GetU32(&offset); + ctf_stype.size = m_data.GetU32(&offset); + + llvm::StringRef name = ReadString(ctf_stype.name); + const uint32_t kind = GetKind(ctf_stype.info); + const uint32_t variable_length = GetVLen(ctf_stype.info); + const uint32_t type = ctf_stype.GetType(); + const uint32_t size = ctf_stype.GetSize(); + switch (kind) { - case TypeKind::eInteger: - return ParseInteger(offset, uid, name); + case TypeKind::eInteger: { + const uint32_t vdata = m_data.GetU32(&offset); + const uint32_t bits = GetBits(vdata); + const uint32_t encoding = GetEncoding(vdata); + return std::make_unique<CTFInteger>(uid, name, bits, encoding); + } case TypeKind::eConst: + return std::make_unique<CTFConst>(uid, type); case TypeKind::ePointer: + return std::make_unique<CTFPointer>(uid, type); case TypeKind::eRestrict: + return std::make_unique<CTFRestrict>(uid, type); case TypeKind::eVolatile: - return ParseModifierType(offset, uid, kind, type); + return std::make_unique<CTFVolatile>(uid, type); case TypeKind::eTypedef: - return ParseTypedef(offset, uid, name, type); - case TypeKind::eArray: - return ParseArray(offset, uid, name); - case TypeKind::eEnum: - return ParseEnum(offset, uid, name, variable_length, size); - case TypeKind::eFunction: - return ParseFunction(offset, uid, name, variable_length, size); + return std::make_unique<CTFTypedef>(uid, name, type); + case TypeKind::eArray: { + const uint32_t type = m_data.GetU32(&offset); + const uint32_t index = m_data.GetU32(&offset); + const uint32_t nelems = m_data.GetU32(&offset); + return std::make_unique<CTFArray>(uid, name, type, index, nelems); + } + case TypeKind::eEnum: { + std::vector<CTFEnum::Value> values; + for (uint32_t i = 0; i < variable_length; ++i) { + const uint32_t value_name = m_data.GetU32(&offset); + const uint32_t value = m_data.GetU32(&offset); + values.emplace_back(ReadString(value_name), value); + } + return std::make_unique<CTFEnum>(uid, name, variable_length, size, values); + } + case TypeKind::eFunction: { + std::vector<uint32_t> args; + bool variadic = false; + for (uint32_t i = 0; i < variable_length; ++i) { + const uint32_t arg_uid = m_data.GetU32(&offset); + // If the last argument is 0, this is a variadic function. + if (arg_uid == 0) { + variadic = true; + break; + } + args.push_back(arg_uid); + } + // If the number of arguments is odd, a single uint32_t of padding is + // inserted to maintain alignment. + if (variable_length % 2 == 1) + m_data.GetU32(&offset); + return std::make_unique<CTFFunction>(uid, name, variable_length, type, args, + variadic); + } case TypeKind::eStruct: - case TypeKind::eUnion: - return ParseRecord(offset, uid, name, kind, variable_length, size); - case TypeKind::eFloat: + case TypeKind::eUnion: { + std::vector<CTFRecord::Field> fields; + for (uint32_t i = 0; i < variable_length; ++i) { + const uint32_t field_name = m_data.GetU32(&offset); + const uint32_t type = m_data.GetU32(&offset); + uint64_t field_offset = 0; + if (size < g_ctf_field_threshold) { + field_offset = m_data.GetU16(&offset); + m_data.GetU16(&offset); // Padding + } else { + const uint32_t offset_hi = m_data.GetU32(&offset); + const uint32_t offset_lo = m_data.GetU32(&offset); + field_offset = (((uint64_t)offset_hi) << 32) | ((uint64_t)offset_lo); + } + fields.emplace_back(ReadString(field_name), type, field_offset); + } + return std::make_unique<CTFRecord>(static_cast<CTFType::Kind>(kind), uid, + name, variable_length, size, fields); + } case TypeKind::eForward: - case TypeKind::eSlice: + return std::make_unique<CTFForward>(uid, name); case TypeKind::eUnknown: + return std::make_unique<CTFType>(static_cast<CTFType::Kind>(kind), uid, + name); + case TypeKind::eFloat: + case TypeKind::eSlice: offset += (variable_length * sizeof(uint32_t)); break; } + return llvm::make_error<llvm::StringError>( llvm::formatv("unsupported type (name = {0}, kind = {1}, vlength = {2})", name, kind, variable_length), @@ -627,46 +724,24 @@ size_t SymbolFileCTF::ParseTypes(CompileUnit &cu) { lldb::user_id_t type_uid = 1; while (type_offset < type_offset_end) { - ctf_stype_t ctf_stype; - ctf_stype.name = m_data.GetU32(&type_offset); - ctf_stype.info = m_data.GetU32(&type_offset); - ctf_stype.size = m_data.GetU32(&type_offset); - - llvm::StringRef name = ReadString(ctf_stype.name); - const uint32_t kind = GetKind(ctf_stype.info); - const uint32_t variable_length = GetVLen(ctf_stype.info); - const uint32_t type = ctf_stype.GetType(); - const uint32_t size = ctf_stype.GetSize(); - - TypeSP type_sp; - llvm::Expected<TypeSP> type_or_error = ParseType( - type_offset, type_uid, name, kind, variable_length, type, size); - if (!type_or_error) { + llvm::Expected<std::unique_ptr<CTFType>> type_or_error = + ParseType(type_offset, type_uid); + if (type_or_error) { + m_ctf_types[(*type_or_error)->uid] = std::move(*type_or_error); + } else { LLDB_LOG_ERROR(log, type_or_error.takeError(), "Failed to parse type {1} at offset {2}: {0}", type_uid, type_offset); - } else { - type_sp = *type_or_error; - if (log) { - StreamString ss; - type_sp->Dump(&ss, true); - LLDB_LOGV(log, "Adding type {0}: {1}", type_uid, - llvm::StringRef(ss.GetString()).rtrim()); - } } - - AddTypeForUID(type_uid++, type_sp); + type_uid++; } - if (log) { - size_t skipped_types = 0; - for (auto &type : m_types) { - if (!type) - skipped_types++; - } - LLDB_LOG(log, "Parsed {0} CTF types ({1} skipped)", m_types.size(), - skipped_types); - } + LLDB_LOG(log, "Parsed {0} CTF types", m_ctf_types.size()); + + for (lldb::user_id_t uid = 1; uid < type_uid; ++uid) + ResolveTypeUID(uid); + + LLDB_LOG(log, "Created {0} CTF types", m_types.size()); return m_types.size(); } @@ -725,12 +800,12 @@ size_t SymbolFileCTF::ParseFunctions(CompileUnit &cu) { break; } - TypeSP arg_type = GetTypeForUID(arg_uid); + Type *arg_type = ResolveTypeUID(arg_uid); arg_types.push_back(arg_type->GetFullCompilerType()); } if (symbol) { - TypeSP ret_type = GetTypeForUID(ret_uid); + Type *ret_type = ResolveTypeUID(ret_uid); AddressRange func_range = AddressRange(symbol->GetFileAddress(), symbol->GetByteSize(), GetObjectFile()->GetModule()->GetSectionList()); @@ -744,7 +819,7 @@ size_t SymbolFileCTF::ParseFunctions(CompileUnit &cu) { MakeType(function_type_uid, symbol->GetName(), 0, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, func_type, lldb_private::Type::ResolveState::Full); - AddTypeForUID(function_type_uid, type_sp); + m_types[function_type_uid] = type_sp; // Create function. lldb::user_id_t func_uid = m_functions.size(); @@ -814,7 +889,6 @@ size_t SymbolFileCTF::ParseObjects(CompileUnit &comp_unit) { if (Symbol *symbol = symtab->FindSymbolWithType(eSymbolTypeData, Symtab::eDebugYes, Symtab::eVisibilityAny, symbol_idx)) { - Variable::RangeList ranges; ranges.Append(symbol->GetFileAddress(), symbol->GetByteSize()); @@ -906,42 +980,58 @@ void SymbolFileCTF::AddSymbols(Symtab &symtab) { // We rely on the existing symbol table to map symbols to type. } -void SymbolFileCTF::AddTypeForUID(lldb::user_id_t type_uid, lldb::TypeSP type) { - assert(type_uid == m_types.size() + 1); - m_types.emplace_back(type); -} +lldb_private::Type *SymbolFileCTF::ResolveTypeUID(lldb::user_id_t type_uid) { + auto type_it = m_types.find(type_uid); + if (type_it != m_types.end()) + return type_it->second.get(); -TypeSP SymbolFileCTF::GetTypeForUID(lldb::user_id_t type_uid) { - if (type_uid > m_types.size()) - return {}; + auto ctf_type_it = m_ctf_types.find(type_uid); + if (ctf_type_it == m_ctf_types.end()) + return nullptr; + + CTFType *ctf_type = ctf_type_it->second.get(); + assert(ctf_type && "m_ctf_types should only contain valid CTF types"); + + Log *log = GetLog(LLDBLog::Symbols); - if (type_uid < 1) + llvm::Expected<TypeSP> type_or_error = CreateType(ctf_type); + if (!type_or_error) { + LLDB_LOG_ERROR(log, type_or_error.takeError(), + "Failed to create type for {1}: {0}", ctf_type->uid); return {}; + } - return m_types[type_uid - 1]; -} + TypeSP type_sp = *type_or_error; -lldb_private::Type *SymbolFileCTF::ResolveTypeUID(lldb::user_id_t type_uid) { - return GetTypeForUID(type_uid).get(); -} + if (log) { + StreamString ss; + type_sp->Dump(&ss, true); + LLDB_LOGV(log, "Adding type {0}: {1}", type_sp->GetID(), + llvm::StringRef(ss.GetString()).rtrim()); + } -void SymbolFileCTF::FindTypes( - lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) { + m_types[type_uid] = type_sp; - searched_symbol_files.clear(); - searched_symbol_files.insert(this); + // Except for record types which we'll need to complete later, we don't need + // the CTF type anymore. + if (!isa<CTFRecord>(ctf_type)) + m_ctf_types.erase(type_uid); - size_t matches = 0; - for (TypeSP type_sp : m_types) { - if (matches == max_matches) - break; + return type_sp.get(); +} + +void SymbolFileCTF::FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) { + // Make sure we haven't already searched this SymbolFile before. + if (results.AlreadySearched(this)) + return; + + ConstString name = match.GetTypeBasename(); + for (TypeSP type_sp : GetTypeList().Types()) { if (type_sp && type_sp->GetName() == name) { - types.Insert(type_sp); - matches++; + results.InsertUnique(type_sp); + if (results.Done(match)) + return; } } } @@ -952,7 +1042,7 @@ void SymbolFileCTF::FindTypesByRegex( ParseTypes(*m_comp_unit_sp); size_t matches = 0; - for (TypeSP type_sp : m_types) { + for (TypeSP type_sp : GetTypeList().Types()) { if (matches == max_matches) break; if (type_sp && regex.Execute(type_sp->GetName())) diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h index bdd6dcdc3fda..f111937dbd6e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h @@ -13,6 +13,7 @@ #include <optional> #include <vector> +#include "CTFTypes.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SymbolFile.h" @@ -85,9 +86,6 @@ public: lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; - lldb::TypeSP GetTypeForUID(lldb::user_id_t type_uid); - void AddTypeForUID(lldb::user_id_t type_uid, lldb::TypeSP type); - Type *ResolveTypeUID(lldb::user_id_t type_uid) override; std::optional<ArrayInfo> GetDynamicArrayInfoForUID( lldb::user_id_t type_uid, @@ -95,7 +93,7 @@ public: return std::nullopt; } - bool CompleteType(CompilerType &compiler_type) override { return false; } + bool CompleteType(CompilerType &compiler_type) override; uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr, lldb::SymbolContextItem resolve_scope, @@ -107,12 +105,8 @@ public: lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override {} - void - FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) override; + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; void FindTypesByRegex(const lldb_private::RegularExpression ®ex, uint32_t max_matches, lldb_private::TypeMap &types); @@ -216,60 +210,18 @@ private: uint32_t GetSize() const { return size; } }; - struct ctf_member_t { - uint32_t name; - uint32_t type; - uint16_t offset; - uint16_t padding; - }; - - struct ctf_array_t { - uint32_t contents; - uint32_t index; - uint32_t nelems; - }; - - struct ctf_enum_t { - uint32_t name; - int32_t value; - }; - - llvm::Expected<lldb::TypeSP> ParseType(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name, uint32_t kind, - uint32_t variable_length, - uint32_t type, uint32_t size); + llvm::Expected<std::unique_ptr<CTFType>> ParseType(lldb::offset_t &offset, + lldb::user_id_t uid); - llvm::Expected<lldb::TypeSP> ParseInteger(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name); - - llvm::Expected<lldb::TypeSP> ParseModifierType(lldb::offset_t &offset, - lldb::user_id_t uid, - uint32_t kind, uint32_t type); - - llvm::Expected<lldb::TypeSP> ParseTypedef(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name, - uint32_t type); - - llvm::Expected<lldb::TypeSP> - ParseArray(lldb::offset_t &offset, lldb::user_id_t uid, llvm::StringRef name); - - llvm::Expected<lldb::TypeSP> ParseEnum(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name, - uint32_t elements, uint32_t size); - - llvm::Expected<lldb::TypeSP> ParseFunction(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name, - uint32_t num_args, uint32_t type); - - llvm::Expected<lldb::TypeSP> ParseRecord(lldb::offset_t &offset, - lldb::user_id_t uid, - llvm::StringRef name, uint32_t kind, - uint32_t fields, uint32_t size); + llvm::Expected<lldb::TypeSP> CreateType(CTFType *ctf_type); + llvm::Expected<lldb::TypeSP> CreateInteger(const CTFInteger &ctf_integer); + llvm::Expected<lldb::TypeSP> CreateModifier(const CTFModifier &ctf_modifier); + llvm::Expected<lldb::TypeSP> CreateTypedef(const CTFTypedef &ctf_typedef); + llvm::Expected<lldb::TypeSP> CreateArray(const CTFArray &ctf_array); + llvm::Expected<lldb::TypeSP> CreateEnum(const CTFEnum &ctf_enum); + llvm::Expected<lldb::TypeSP> CreateFunction(const CTFFunction &ctf_function); + llvm::Expected<lldb::TypeSP> CreateRecord(const CTFRecord &ctf_record); + llvm::Expected<lldb::TypeSP> CreateForward(const CTFForward &ctf_forward); llvm::StringRef ReadString(lldb::offset_t offset) const; @@ -288,12 +240,24 @@ private: lldb::CompUnitSP m_comp_unit_sp; std::optional<ctf_header_t> m_header; - std::vector<lldb::TypeSP> m_types; + + /// Parsed CTF types. + llvm::DenseMap<lldb::user_id_t, std::unique_ptr<CTFType>> m_ctf_types; + + /// Parsed LLDB types. + llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types; + + /// To complete types, we need a way to map (imcomplete) compiler types back + /// to parsed CTF types. + llvm::DenseMap<lldb::opaque_compiler_type_t, const CTFType *> + m_compiler_types; + std::vector<lldb::FunctionSP> m_functions; std::vector<lldb::VariableSP> m_variables; static constexpr uint16_t g_ctf_magic = 0xcff1; static constexpr uint8_t g_ctf_version = 4; + static constexpr uint16_t g_ctf_field_threshold = 0x2000; }; } // namespace lldb_private 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 34fb98b5a9b6..33537df4f507 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -18,6 +18,7 @@ using namespace lldb_private; using namespace lldb; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create( Module &module, DWARFDataExtractor apple_names, @@ -50,13 +51,20 @@ std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create( extract_and_check(apple_namespaces_table_up); extract_and_check(apple_types_table_up); extract_and_check(apple_objc_table_up); + assert(apple_names.GetByteSize() == 0 || apple_names.GetSharedDataBuffer()); + assert(apple_namespaces.GetByteSize() == 0 || + apple_namespaces.GetSharedDataBuffer()); + assert(apple_types.GetByteSize() == 0 || apple_types.GetSharedDataBuffer()); + assert(apple_objc.GetByteSize() == 0 || apple_objc.GetSharedDataBuffer()); 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), - std::move(apple_objc_table_up)); + std::move(apple_objc_table_up), apple_names.GetSharedDataBuffer(), + apple_namespaces.GetSharedDataBuffer(), + apple_types.GetSharedDataBuffer(), apple_objc.GetSharedDataBuffer()); return nullptr; } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h index 6b948e079895..73de75b583bd 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h @@ -12,7 +12,8 @@ #include "Plugins/SymbolFile/DWARF/DWARFIndex.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" -namespace lldb_private { +namespace lldb_private::plugin { +namespace dwarf { class AppleDWARFIndex : public DWARFIndex { public: static std::unique_ptr<AppleDWARFIndex> @@ -24,11 +25,19 @@ public: std::unique_ptr<llvm::AppleAcceleratorTable> apple_names, std::unique_ptr<llvm::AppleAcceleratorTable> apple_namespaces, std::unique_ptr<llvm::AppleAcceleratorTable> apple_types, - std::unique_ptr<llvm::AppleAcceleratorTable> apple_objc) + std::unique_ptr<llvm::AppleAcceleratorTable> apple_objc, + lldb::DataBufferSP apple_names_storage, + lldb::DataBufferSP apple_namespaces_storage, + lldb::DataBufferSP apple_types_storage, + lldb::DataBufferSP apple_objc_storage) : DWARFIndex(module), m_apple_names_up(std::move(apple_names)), m_apple_namespaces_up(std::move(apple_namespaces)), m_apple_types_up(std::move(apple_types)), - m_apple_objc_up(std::move(apple_objc)) {} + m_apple_objc_up(std::move(apple_objc)), + m_apple_names_storage(apple_names_storage), + m_apple_namespaces_storage(apple_namespaces_storage), + m_apple_types_storage(apple_types_storage), + m_apple_objc_storage(apple_objc_storage) {} void Preload() override {} @@ -66,6 +75,14 @@ private: std::unique_ptr<llvm::AppleAcceleratorTable> m_apple_namespaces_up; std::unique_ptr<llvm::AppleAcceleratorTable> m_apple_types_up; std::unique_ptr<llvm::AppleAcceleratorTable> m_apple_objc_up; + /// The following storage variables hold the data that the apple accelerator + /// tables tables above point to. + /// { + lldb::DataBufferSP m_apple_names_storage; + lldb::DataBufferSP m_apple_namespaces_storage; + lldb::DataBufferSP m_apple_types_storage; + lldb::DataBufferSP m_apple_objc_storage; + /// } /// Search for entries whose name is `name` in `table`, calling `callback` for /// each match. If `search_for_tag` is provided, ignore entries whose tag is @@ -77,6 +94,7 @@ private: std::optional<dw_tag_t> search_for_tag = std::nullopt, std::optional<uint32_t> search_for_qualhash = std::nullopt); }; -} // namespace lldb_private +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_APPLEDWARFINDEX_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp index 88a5e6027557..163e9f4c081c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp @@ -14,6 +14,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; void llvm::format_provider<DIERef>::format(const DIERef &ref, raw_ostream &OS, StringRef Style) { diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h index b5a5cfe263f7..ad443aacb46e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h @@ -14,6 +14,8 @@ #include <cassert> #include <optional> +namespace lldb_private::plugin { +namespace dwarf { /// Identifies a DWARF debug info entry within a given Module. It contains three /// "coordinates": /// - file_index: identifies the separate stand alone debug info file @@ -93,7 +95,7 @@ public: /// \return /// Returns a valid DIERef if decoding succeeded, std::nullopt if there was /// unsufficient or invalid values that were decoded. - static std::optional<DIERef> Decode(const lldb_private::DataExtractor &data, + static std::optional<DIERef> Decode(const DataExtractor &data, lldb::offset_t *offset_ptr); /// Encode this object into a data encoder object. @@ -103,7 +105,7 @@ public: /// \param encoder /// A data encoder object that serialized bytes will be encoded into. /// - void Encode(lldb_private::DataEncoder &encoder) const; + void Encode(DataEncoder &encoder) const; static constexpr uint64_t k_die_offset_bit_size = DW_DIE_OFFSET_MAX_BITSIZE; static constexpr uint64_t k_file_index_bit_size = @@ -131,10 +133,13 @@ private: static_assert(sizeof(DIERef) == 8); typedef std::vector<DIERef> DIEArray; +} // namespace dwarf +} // namespace lldb_private::plugin namespace llvm { -template<> struct format_provider<DIERef> { - static void format(const DIERef &ref, raw_ostream &OS, StringRef Style); +template <> struct format_provider<lldb_private::plugin::dwarf::DIERef> { + static void format(const lldb_private::plugin::dwarf::DIERef &ref, + raw_ostream &OS, StringRef Style); }; } // namespace llvm diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp index a68b7cd110eb..409e9bb37ab2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp @@ -9,6 +9,7 @@ #include "DWARFASTParser.h" #include "DWARFAttribute.h" #include "DWARFDIE.h" +#include "SymbolFileDWARF.h" #include "lldb/Core/ValueObject.h" #include "lldb/Symbol/SymbolFile.h" @@ -18,6 +19,7 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; std::optional<SymbolFile::ArrayInfo> DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die, @@ -99,6 +101,30 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die, return array_info; } +Type *DWARFASTParser::GetTypeForDIE(const DWARFDIE &die) { + if (!die) + return nullptr; + + SymbolFileDWARF *dwarf = die.GetDWARF(); + if (!dwarf) + return nullptr; + + DWARFAttributes attributes = die.GetAttributes(); + if (attributes.Size() == 0) + return nullptr; + + DWARFFormValue type_die_form; + for (size_t i = 0; i < attributes.Size(); ++i) { + dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + + if (attr == DW_AT_type && attributes.ExtractFormValueAtIndex(i, form_value)) + return dwarf->ResolveTypeUID(form_value.Reference(), true); + } + + return nullptr; +} + AccessType DWARFASTParser::GetAccessTypeFromDWARF(uint32_t dwarf_accessibility) { switch (dwarf_accessibility) { diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h index 18825ae060b1..66db396279e0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -17,53 +17,63 @@ #include "lldb/lldb-enumerations.h" #include <optional> -class DWARFDIE; namespace lldb_private { class CompileUnit; class ExecutionContext; } + +namespace lldb_private::plugin { +namespace dwarf { +class DWARFDIE; class SymbolFileDWARF; class DWARFASTParser { public: + enum class Kind { DWARFASTParserClang }; + DWARFASTParser(Kind kind) : m_kind(kind) {} + virtual ~DWARFASTParser() = default; - virtual lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, + virtual lldb::TypeSP ParseTypeFromDWARF(const SymbolContext &sc, const DWARFDIE &die, bool *type_is_new_ptr) = 0; - virtual lldb_private::ConstString - ConstructDemangledNameFromDWARF(const DWARFDIE &die) = 0; + virtual ConstString ConstructDemangledNameFromDWARF(const DWARFDIE &die) = 0; - virtual lldb_private::Function * - ParseFunctionFromDWARF(lldb_private::CompileUnit &comp_unit, - const DWARFDIE &die, - const lldb_private::AddressRange &range) = 0; + virtual Function *ParseFunctionFromDWARF(CompileUnit &comp_unit, + const DWARFDIE &die, + const AddressRange &range) = 0; - virtual bool - CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, - lldb_private::CompilerType &compiler_type) = 0; + virtual bool CompleteTypeFromDWARF(const DWARFDIE &die, Type *type, + CompilerType &compiler_type) = 0; - virtual lldb_private::CompilerDecl - GetDeclForUIDFromDWARF(const DWARFDIE &die) = 0; + virtual CompilerDecl GetDeclForUIDFromDWARF(const DWARFDIE &die) = 0; - virtual lldb_private::CompilerDeclContext + virtual CompilerDeclContext GetDeclContextForUIDFromDWARF(const DWARFDIE &die) = 0; - virtual lldb_private::CompilerDeclContext + virtual CompilerDeclContext GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) = 0; virtual void EnsureAllDIEsInDeclContextHaveBeenParsed( - lldb_private::CompilerDeclContext decl_context) = 0; + CompilerDeclContext decl_context) = 0; - virtual lldb_private::ConstString - GetDIEClassTemplateParams(const DWARFDIE &die) = 0; + virtual ConstString GetDIEClassTemplateParams(const DWARFDIE &die) = 0; - static std::optional<lldb_private::SymbolFile::ArrayInfo> + static std::optional<SymbolFile::ArrayInfo> ParseChildArrayInfo(const DWARFDIE &parent_die, - const lldb_private::ExecutionContext *exe_ctx = nullptr); + const ExecutionContext *exe_ctx = nullptr); + + lldb_private::Type *GetTypeForDIE(const DWARFDIE &die); static lldb::AccessType GetAccessTypeFromDWARF(uint32_t dwarf_accessibility); + + Kind GetKind() const { return m_kind; } + +private: + const Kind m_kind; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSER_H 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 a3ade51e1fe5..334876620249 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -31,6 +31,7 @@ #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeMap.h" +#include "lldb/Symbol/VariableList.h" #include "lldb/Target/Language.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" @@ -60,8 +61,11 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; + DWARFASTParserClang::DWARFASTParserClang(TypeSystemClang &ast) - : m_ast(ast), m_die_to_decl_ctx(), m_decl_ctx_to_die() {} + : DWARFASTParser(Kind::DWARFASTParserClang), m_ast(ast), + m_die_to_decl_ctx(), m_decl_ctx_to_die() {} DWARFASTParserClang::~DWARFASTParserClang() = default; @@ -130,6 +134,14 @@ static lldb::ModuleSP GetContainingClangModule(const DWARFDIE &die) { return lldb::ModuleSP(); } +// Returns true if the given artificial field name should be ignored when +// parsing the DWARF. +static bool ShouldIgnoreArtificialField(llvm::StringRef FieldName) { + return FieldName.starts_with("_vptr$") + // gdb emit vtable pointer as "_vptr.classname" + || FieldName.starts_with("_vptr."); +} + TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, const DWARFDIE &die, Log *log) { @@ -140,17 +152,16 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, // If this type comes from a Clang module, recursively look in the // DWARF section of the .pcm file in the module cache. Clang // generates DWO skeleton units as breadcrumbs to find them. - llvm::SmallVector<CompilerContext, 4> decl_context; - die.GetDeclContext(decl_context); - TypeMap pcm_types; + std::vector<lldb_private::CompilerContext> die_context = die.GetDeclContext(); + TypeQuery query(die_context, TypeQueryOptions::e_module_search | + TypeQueryOptions::e_find_one); + TypeResults results; // The type in the Clang module must have the same language as the current CU. - LanguageSet languages; - languages.Insert(SymbolFileDWARF::GetLanguageFamily(*die.GetCU())); - llvm::DenseSet<SymbolFile *> searched_symbol_files; - clang_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, - searched_symbol_files, pcm_types); - if (pcm_types.Empty()) { + query.AddLanguage(SymbolFileDWARF::GetLanguageFamily(*die.GetCU())); + clang_module_sp->FindTypes(query, results); + TypeSP pcm_type_sp = results.GetTypeMap().FirstType(); + if (!pcm_type_sp) { // Since this type is defined in one of the Clang modules imported // by this symbol file, search all of them. Instead of calling // sym_file->FindTypes(), which would return this again, go straight @@ -159,24 +170,20 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, // Well-formed clang modules never form cycles; guard against corrupted // ones by inserting the current file. - searched_symbol_files.insert(&sym_file); + results.AlreadySearched(&sym_file); sym_file.ForEachExternalModule( - *sc.comp_unit, searched_symbol_files, [&](Module &module) { - module.GetSymbolFile()->FindTypes(decl_context, languages, - searched_symbol_files, pcm_types); - return pcm_types.GetSize(); + *sc.comp_unit, results.GetSearchedSymbolFiles(), [&](Module &module) { + module.FindTypes(query, results); + pcm_type_sp = results.GetTypeMap().FirstType(); + return !pcm_type_sp; }); } - if (!pcm_types.GetSize()) + if (!pcm_type_sp) return TypeSP(); // We found a real definition for this type in the Clang module, so lets use // it and cache the fact that we found a complete type for this die. - TypeSP pcm_type_sp = pcm_types.GetTypeAtIndex(0); - if (!pcm_type_sp) - return TypeSP(); - lldb_private::CompilerType pcm_type = pcm_type_sp->GetForwardCompilerType(); lldb_private::CompilerType type = GetClangASTImporter().CopyType(m_ast, pcm_type); @@ -296,6 +303,10 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { byte_size = form_value.Unsigned(); break; + case DW_AT_alignment: + alignment = form_value.Unsigned(); + break; + case DW_AT_byte_stride: byte_stride = form_value.Unsigned(); break; @@ -519,6 +530,33 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, return UpdateSymbolContextScopeForType(sc, die, type_sp); } +static std::optional<uint32_t> +ExtractDataMemberLocation(DWARFDIE const &die, DWARFFormValue const &form_value, + ModuleSP module_sp) { + // With DWARF 3 and later, if the value is an integer constant, + // this form value is the offset in bytes from the beginning of + // the containing entity. + if (!form_value.BlockData()) + return form_value.Unsigned(); + + Value initialValue(0); + Value memberOffset(0); + const DWARFDataExtractor &debug_info_data = die.GetData(); + uint32_t block_length = form_value.Unsigned(); + uint32_t block_offset = + form_value.BlockData() - debug_info_data.GetDataStart(); + if (!DWARFExpression::Evaluate( + nullptr, // ExecutionContext * + nullptr, // RegisterContext * + module_sp, DataExtractor(debug_info_data, block_offset, block_length), + die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr, memberOffset, + nullptr)) { + return {}; + } + + return memberOffset.ResolveValue(nullptr).UInt(); +} + lldb::TypeSP DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, const DWARFDIE &die, @@ -805,9 +843,9 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, CompilerType enumerator_clang_type; CompilerType clang_type; - clang_type = - CompilerType(m_ast.weak_from_this(), - dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); + clang_type = CompilerType( + m_ast.weak_from_this(), + dwarf->GetForwardDeclDIEToCompilerType().lookup(die.GetDIE())); if (!clang_type) { if (attrs.type.IsValid()) { Type *enumerator_type = @@ -890,8 +928,9 @@ ConvertDWARFCallingConventionToClang(const ParsedDWARFTypeAttributes &attrs) { return clang::CC_C; } -TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, - ParsedDWARFTypeAttributes &attrs) { +TypeSP +DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, + const ParsedDWARFTypeAttributes &attrs) { Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); SymbolFileDWARF *dwarf = die.GetDWARF(); @@ -1000,16 +1039,10 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, } if (class_opaque_type) { - // If accessibility isn't set to anything valid, assume public - // for now... - if (attrs.accessibility == eAccessNone) - attrs.accessibility = eAccessPublic; - clang::ObjCMethodDecl *objc_method_decl = m_ast.AddMethodToObjCObjectType( class_opaque_type, attrs.name.GetCString(), clang_type, - attrs.accessibility, attrs.is_artificial, is_variadic, - attrs.is_objc_direct_call); + attrs.is_artificial, is_variadic, attrs.is_objc_direct_call); type_handled = objc_method_decl != nullptr; if (type_handled) { LinkDeclContextToDIE(objc_method_decl, die); @@ -1023,7 +1056,7 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, } } } else if (is_cxx_method) { - // Look at the parent of this DIE and see if is is a class or + // Look at the parent of this DIE and see if it is a class or // struct and see if this is actually a C++ method Type *class_type = dwarf->ResolveType(decl_ctx_die); if (class_type) { @@ -1116,14 +1149,15 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, // Neither GCC 4.2 nor clang++ currently set a valid // accessibility in the DWARF for C++ methods... // Default to public for now... - if (attrs.accessibility == eAccessNone) - attrs.accessibility = eAccessPublic; + const auto accessibility = attrs.accessibility == eAccessNone + ? eAccessPublic + : attrs.accessibility; clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType( class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(), attrs.mangled_name, - clang_type, attrs.accessibility, attrs.is_virtual, + clang_type, accessibility, attrs.is_virtual, is_static, attrs.is_inline, attrs.is_explicit, is_attr_used, attrs.is_artificial); @@ -1171,16 +1205,17 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, class_type->GetFullCompilerType(); // The type for this DIE should have been filled in the - // function call above + // function call above. Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { return type_ptr->shared_from_this(); } - // FIXME This is fixing some even uglier behavior but we - // really need to - // uniq the methods of each class as well as the class - // itself. <rdar://problem/11240464> + // The previous comment isn't actually true if the class wasn't + // resolved using the current method's parent DIE as source + // data. We need to ensure that we look up the method correctly + // in the class and then link the method's DIE to the unique + // CXXMethodDecl appropriately. type_handled = true; } } @@ -1405,26 +1440,9 @@ void DWARFASTParserClang::ParseInheritance( encoding_form = form_value; break; case DW_AT_data_member_location: - if (form_value.BlockData()) { - Value initialValue(0); - Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = die.GetData(); - uint32_t block_length = form_value.Unsigned(); - uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); - if (DWARFExpression::Evaluate( - nullptr, nullptr, module_sp, - DataExtractor(debug_info_data, block_offset, block_length), - die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr, - memberOffset, nullptr)) { - member_byte_offset = memberOffset.ResolveValue(nullptr).UInt(); - } - } else { - // With DWARF 3 and later, if the value is an integer constant, - // this form value is the offset in bytes from the beginning of - // the containing entity. - member_byte_offset = form_value.Unsigned(); - } + if (auto maybe_offset = + ExtractDataMemberLocation(die, form_value, module_sp)) + member_byte_offset = *maybe_offset; break; case DW_AT_accessibility: @@ -1624,13 +1642,13 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, int tag_decl_kind = -1; AccessType default_accessibility = eAccessNone; if (tag == DW_TAG_structure_type) { - tag_decl_kind = clang::TTK_Struct; + tag_decl_kind = llvm::to_underlying(clang::TagTypeKind::Struct); default_accessibility = eAccessPublic; } else if (tag == DW_TAG_union_type) { - tag_decl_kind = clang::TTK_Union; + tag_decl_kind = llvm::to_underlying(clang::TagTypeKind::Union); default_accessibility = eAccessPublic; } else if (tag == DW_TAG_class_type) { - tag_decl_kind = clang::TTK_Class; + tag_decl_kind = llvm::to_underlying(clang::TagTypeKind::Class); default_accessibility = eAccessPrivate; } @@ -1749,11 +1767,11 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, } } assert(tag_decl_kind != -1); - (void)tag_decl_kind; + UNUSED_IF_ASSERT_DISABLED(tag_decl_kind); bool clang_type_was_created = false; - clang_type = - CompilerType(m_ast.weak_from_this(), - dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); + clang_type = CompilerType( + m_ast.weak_from_this(), + dwarf->GetForwardDeclDIEToCompilerType().lookup(die.GetDIE())); if (!clang_type) { clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); @@ -1851,17 +1869,21 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, die.GetOffset(), attrs.name.GetCString()); } - // If the byte size of the record is specified then overwrite the size - // that would be computed by Clang. This is only needed as LLDB's - // TypeSystemClang is always in C++ mode, but some compilers such as - // GCC and Clang give empty structs a size of 0 in C mode (in contrast to - // the size of 1 for empty structs that would be computed in C++ mode). - if (attrs.byte_size) { + // Setting authority byte size and alignment for empty structures. + // + // If the byte size or alignmenet of the record is specified then + // overwrite the ones that would be computed by Clang. + // This is only needed as LLDB's TypeSystemClang is always in C++ mode, + // but some compilers such as GCC and Clang give empty structs a size of 0 + // in C mode (in contrast to the size of 1 for empty structs that would be + // computed in C++ mode). + if (attrs.byte_size || attrs.alignment) { clang::RecordDecl *record_decl = TypeSystemClang::GetAsRecordDecl(clang_type); if (record_decl) { ClangASTImporter::LayoutInfo layout; - layout.bit_size = *attrs.byte_size * 8; + layout.bit_size = attrs.byte_size.value_or(0) * 8; + layout.alignment = attrs.alignment.value_or(0) * 8; GetClangASTImporter().SetRecordLayout(record_decl, layout); } } @@ -1883,16 +1905,16 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, // the SymbolFile virtual function // "SymbolFileDWARF::CompleteType(Type *)" When the definition // needs to be defined. - assert(!dwarf->GetForwardDeclClangTypeToDie().count( + assert(!dwarf->GetForwardDeclCompilerTypeToDIE().count( ClangUtil::RemoveFastQualifiers(clang_type) .GetOpaqueQualType()) && "Type already in the forward declaration map!"); // Can't assume m_ast.GetSymbolFile() is actually a // SymbolFileDWARF, it can be a SymbolFileDWARFDebugMap for Apple // binaries. - dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = + dwarf->GetForwardDeclDIEToCompilerType()[die.GetDIE()] = clang_type.GetOpaqueQualType(); - dwarf->GetForwardDeclClangTypeToDie().try_emplace( + dwarf->GetForwardDeclCompilerTypeToDIE().try_emplace( ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(), *die.GetDIERef()); m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); @@ -1916,7 +1938,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); if (record_decl) record_decl->setArgPassingRestrictions( - clang::RecordDecl::APK_CannotPassInRegs); + clang::RecordArgPassingKind::CannotPassInRegs); } return type_sp; } @@ -2200,6 +2222,9 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, if (layout_info.bit_size == 0) layout_info.bit_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; + if (layout_info.alignment == 0) + layout_info.alignment = + die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_alignment, 0) * 8; clang::CXXRecordDecl *record_decl = m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); @@ -2273,7 +2298,7 @@ CompilerDecl DWARFASTParserClang::GetDeclForUIDFromDWARF(const DWARFDIE &die) { clang::Decl *clang_decl = GetClangDeclForDIE(die); if (clang_decl != nullptr) return m_ast.GetCompilerDecl(clang_decl); - return CompilerDecl(); + return {}; } CompilerDeclContext @@ -2281,7 +2306,7 @@ DWARFASTParserClang::GetDeclContextForUIDFromDWARF(const DWARFDIE &die) { clang::DeclContext *clang_decl_ctx = GetClangDeclContextForDIE(die); if (clang_decl_ctx) return m_ast.CreateDeclContext(clang_decl_ctx); - return CompilerDeclContext(); + return {}; } CompilerDeclContext @@ -2290,7 +2315,7 @@ DWARFASTParserClang::GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) { GetClangDeclContextContainingDIE(die, nullptr); if (clang_decl_ctx) return m_ast.CreateDeclContext(clang_decl_ctx); - return CompilerDeclContext(); + return {}; } size_t DWARFASTParserClang::ParseChildEnumerators( @@ -2464,27 +2489,6 @@ DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, } namespace { -/// Parsed form of all attributes that are relevant for parsing type members. -struct MemberAttributes { - explicit MemberAttributes(const DWARFDIE &die, const DWARFDIE &parent_die, - ModuleSP module_sp); - const char *name = nullptr; - /// Indicates how many bits into the word (according to the host endianness) - /// the low-order bit of the field starts. Can be negative. - int64_t bit_offset = 0; - /// Indicates the size of the field in bits. - size_t bit_size = 0; - uint64_t data_bit_offset = UINT64_MAX; - AccessType accessibility = eAccessNone; - std::optional<uint64_t> byte_size; - std::optional<DWARFFormValue> const_value_form; - DWARFFormValue encoding_form; - /// Indicates the byte offset of the word from the base address of the - /// structure. - uint32_t member_byte_offset; - bool is_artificial = false; -}; - /// Parsed form of all attributes that are relevant for parsing Objective-C /// properties. struct PropertyAttributes { @@ -2495,13 +2499,126 @@ struct PropertyAttributes { /// \see clang::ObjCPropertyAttribute uint32_t prop_attributes = 0; }; + +struct DiscriminantValue { + explicit DiscriminantValue(const DWARFDIE &die, ModuleSP module_sp); + + uint32_t byte_offset; + uint32_t byte_size; + DWARFFormValue type_ref; +}; + +struct VariantMember { + explicit VariantMember(DWARFDIE &die, ModuleSP module_sp); + bool IsDefault() const; + + std::optional<uint32_t> discr_value; + DWARFFormValue type_ref; + ConstString variant_name; + uint32_t byte_offset; + ConstString GetName() const; +}; + +struct VariantPart { + explicit VariantPart(const DWARFDIE &die, const DWARFDIE &parent_die, + ModuleSP module_sp); + + std::vector<VariantMember> &members(); + + DiscriminantValue &discriminant(); + +private: + std::vector<VariantMember> _members; + DiscriminantValue _discriminant; +}; + } // namespace -MemberAttributes::MemberAttributes(const DWARFDIE &die, - const DWARFDIE &parent_die, - ModuleSP module_sp) { - member_byte_offset = (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX; +ConstString VariantMember::GetName() const { return this->variant_name; } + +bool VariantMember::IsDefault() const { return !discr_value; } + +VariantMember::VariantMember(DWARFDIE &die, lldb::ModuleSP module_sp) { + assert(die.Tag() == llvm::dwarf::DW_TAG_variant); + this->discr_value = + die.GetAttributeValueAsOptionalUnsigned(DW_AT_discr_value); + + for (auto child_die : die.children()) { + switch (child_die.Tag()) { + case llvm::dwarf::DW_TAG_member: { + DWARFAttributes attributes = child_die.GetAttributes(); + for (std::size_t i = 0; i < attributes.Size(); ++i) { + DWARFFormValue form_value; + const dw_attr_t attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + case DW_AT_name: + variant_name = ConstString(form_value.AsCString()); + break; + case DW_AT_type: + type_ref = form_value; + break; + + case DW_AT_data_member_location: + if (auto maybe_offset = + ExtractDataMemberLocation(die, form_value, module_sp)) + byte_offset = *maybe_offset; + break; + + default: + break; + } + } + } + break; + } + default: + break; + } + break; + } +} + +DiscriminantValue::DiscriminantValue(const DWARFDIE &die, ModuleSP module_sp) { + auto referenced_die = die.GetReferencedDIE(DW_AT_discr); + DWARFAttributes attributes = referenced_die.GetAttributes(); + for (std::size_t i = 0; i < attributes.Size(); ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + case DW_AT_type: + type_ref = form_value; + break; + case DW_AT_data_member_location: + if (auto maybe_offset = + ExtractDataMemberLocation(die, form_value, module_sp)) + byte_offset = *maybe_offset; + break; + default: + break; + } + } + } +} + +VariantPart::VariantPart(const DWARFDIE &die, const DWARFDIE &parent_die, + lldb::ModuleSP module_sp) + : _members(), _discriminant(die, module_sp) { + for (auto child : die.children()) { + if (child.Tag() == llvm::dwarf::DW_TAG_variant) { + _members.push_back(VariantMember(child, module_sp)); + } + } +} + +std::vector<VariantMember> &VariantPart::members() { return this->_members; } + +DiscriminantValue &VariantPart::discriminant() { return this->_discriminant; } + +DWARFASTParserClang::MemberAttributes::MemberAttributes( + const DWARFDIE &die, const DWARFDIE &parent_die, ModuleSP module_sp) { DWARFAttributes attributes = die.GetAttributes(); for (size_t i = 0; i < attributes.Size(); ++i) { const dw_attr_t attr = attributes.AttributeAtIndex(i); @@ -2530,28 +2647,9 @@ MemberAttributes::MemberAttributes(const DWARFDIE &die, data_bit_offset = form_value.Unsigned(); break; case DW_AT_data_member_location: - if (form_value.BlockData()) { - Value initialValue(0); - Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = die.GetData(); - uint32_t block_length = form_value.Unsigned(); - uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); - if (DWARFExpression::Evaluate( - nullptr, // ExecutionContext * - nullptr, // RegisterContext * - module_sp, - DataExtractor(debug_info_data, block_offset, block_length), - die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr, - memberOffset, nullptr)) { - member_byte_offset = memberOffset.ResolveValue(nullptr).UInt(); - } - } else { - // With DWARF 3 and later, if the value is an integer constant, - // this form value is the offset in bytes from the beginning of - // the containing entity. - member_byte_offset = form_value.Unsigned(); - } + if (auto maybe_offset = + ExtractDataMemberLocation(die, form_value, module_sp)) + member_byte_offset = *maybe_offset; break; case DW_AT_accessibility: @@ -2561,6 +2659,9 @@ MemberAttributes::MemberAttributes(const DWARFDIE &die, case DW_AT_artificial: is_artificial = form_value.Boolean(); break; + case DW_AT_declaration: + is_declaration = form_value.Boolean(); + break; default: break; } @@ -2739,13 +2840,51 @@ llvm::Expected<llvm::APInt> DWARFASTParserClang::ExtractIntFromFormValue( return result; } +void DWARFASTParserClang::CreateStaticMemberVariable( + const DWARFDIE &die, const MemberAttributes &attrs, + const lldb_private::CompilerType &class_clang_type) { + Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); + assert(die.Tag() == DW_TAG_member || die.Tag() == DW_TAG_variable); + + Type *var_type = die.ResolveTypeUID(attrs.encoding_form.Reference()); + + if (!var_type) + return; + + auto accessibility = + attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility; + + CompilerType ct = var_type->GetForwardCompilerType(); + clang::VarDecl *v = TypeSystemClang::AddVariableToRecordType( + class_clang_type, attrs.name, ct, accessibility); + if (!v) { + LLDB_LOG(log, "Failed to add variable to the record type"); + return; + } + + bool unused; + // TODO: Support float/double static members as well. + if (!ct.IsIntegerOrEnumerationType(unused) || !attrs.const_value_form) + return; + + llvm::Expected<llvm::APInt> const_value_or_err = + ExtractIntFromFormValue(ct, *attrs.const_value_form); + if (!const_value_or_err) { + LLDB_LOG_ERROR(log, const_value_or_err.takeError(), + "Failed to add const value to variable {1}: {0}", + v->getQualifiedNameAsString()); + return; + } + + TypeSystemClang::SetIntegerInitializerForVariable(v, *const_value_or_err); +} + void DWARFASTParserClang::ParseSingleMember( const DWARFDIE &die, const DWARFDIE &parent_die, const lldb_private::CompilerType &class_clang_type, lldb::AccessType default_accessibility, lldb_private::ClangASTImporter::LayoutInfo &layout_info, FieldInfo &last_field_info) { - Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); // This function can only parse DW_TAG_member. assert(die.Tag() == DW_TAG_member); @@ -2757,49 +2896,22 @@ void DWARFASTParserClang::ParseSingleMember( const uint64_t parent_bit_size = parent_byte_size == UINT64_MAX ? UINT64_MAX : parent_byte_size * 8; - // FIXME: Remove the workarounds below and make this const. - MemberAttributes attrs(die, parent_die, module_sp); - - const bool class_is_objc_object_or_interface = - TypeSystemClang::IsObjCObjectOrInterfaceType(class_clang_type); - - // FIXME: Make Clang ignore Objective-C accessibility for expressions - if (class_is_objc_object_or_interface) - attrs.accessibility = eAccessNone; + const MemberAttributes attrs(die, parent_die, module_sp); - // Handle static members, which is any member that doesn't have a bit or a - // byte member offset. + // Handle static members, which are typically members without + // locations. However, GCC doesn't emit DW_AT_data_member_location + // for any union members (regardless of linkage). + // Non-normative text pre-DWARFv5 recommends marking static + // data members with an DW_AT_external flag. Clang emits this consistently + // whereas GCC emits it only for static data members if not part of an + // anonymous namespace. The flag that is consistently emitted for static + // data members is DW_AT_declaration, so we check it instead. + // The following block is only necessary to support DWARFv4 and earlier. + // Starting with DWARFv5, static data members are marked DW_AT_variable so we + // can consistently detect them on both GCC and Clang without below heuristic. if (attrs.member_byte_offset == UINT32_MAX && - attrs.data_bit_offset == UINT64_MAX) { - Type *var_type = die.ResolveTypeUID(attrs.encoding_form.Reference()); - - if (var_type) { - if (attrs.accessibility == eAccessNone) - attrs.accessibility = eAccessPublic; - CompilerType ct = var_type->GetForwardCompilerType(); - clang::VarDecl *v = TypeSystemClang::AddVariableToRecordType( - class_clang_type, attrs.name, ct, attrs.accessibility); - if (!v) { - LLDB_LOG(log, "Failed to add variable to the record type"); - return; - } - - bool unused; - // TODO: Support float/double static members as well. - if (!attrs.const_value_form || !ct.IsIntegerOrEnumerationType(unused)) - return; - - llvm::Expected<llvm::APInt> const_value_or_err = - ExtractIntFromFormValue(ct, *attrs.const_value_form); - if (!const_value_or_err) { - LLDB_LOG_ERROR(log, const_value_or_err.takeError(), - "Failed to add const value to variable {1}: {0}", - v->getQualifiedNameAsString()); - return; - } - - TypeSystemClang::SetIntegerInitializerForVariable(v, *const_value_or_err); - } + attrs.data_bit_offset == UINT64_MAX && attrs.is_declaration) { + CreateStaticMemberVariable(die, attrs, class_clang_type); return; } @@ -2822,8 +2934,9 @@ void DWARFASTParserClang::ParseSingleMember( const uint64_t word_width = 32; CompilerType member_clang_type = member_type->GetLayoutCompilerType(); - if (attrs.accessibility == eAccessNone) - attrs.accessibility = default_accessibility; + const auto accessibility = attrs.accessibility == eAccessNone + ? default_accessibility + : attrs.accessibility; uint64_t field_bit_offset = (attrs.member_byte_offset == UINT32_MAX ? 0 @@ -2837,12 +2950,13 @@ void DWARFASTParserClang::ParseSingleMember( if (attrs.data_bit_offset != UINT64_MAX) { this_field_info.bit_offset = attrs.data_bit_offset; } else { - if (!attrs.byte_size) - attrs.byte_size = member_type->GetByteSize(nullptr); + auto byte_size = attrs.byte_size; + if (!byte_size) + byte_size = member_type->GetByteSize(nullptr); ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); if (objfile->GetByteOrder() == eByteOrderLittle) { - this_field_info.bit_offset += attrs.byte_size.value_or(0) * 8; + this_field_info.bit_offset += byte_size.value_or(0) * 8; this_field_info.bit_offset -= (attrs.bit_offset + attrs.bit_size); } else { this_field_info.bit_offset += attrs.bit_offset; @@ -2881,7 +2995,7 @@ void DWARFASTParserClang::ParseSingleMember( // unnamed bitfields if we have a new enough clang. bool detect_unnamed_bitfields = true; - if (class_is_objc_object_or_interface) + if (TypeSystemClang::IsObjCObjectOrInterfaceType(class_clang_type)) detect_unnamed_bitfields = die.GetCU()->Supports_unnamed_objc_bitfields(); @@ -2913,7 +3027,7 @@ void DWARFASTParserClang::ParseSingleMember( class_clang_type, llvm::StringRef(), m_ast.GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, word_width), - attrs.accessibility, unnamed_field_info->bit_size); + accessibility, unnamed_field_info->bit_size); layout_info.field_offsets.insert(std::make_pair( unnamed_bitfield_decl, unnamed_field_info->bit_offset)); @@ -2937,11 +3051,9 @@ void DWARFASTParserClang::ParseSingleMember( // in our AST. Clang will re-create those articial members and they would // otherwise just overlap in the layout with the FieldDecls we add here. // This needs to be done after updating FieldInfo which keeps track of where - // field start/end so we don't later try to fill the the space of this + // field start/end so we don't later try to fill the space of this // artificial member with (unnamed bitfield) padding. - // FIXME: This check should verify that this is indeed an artificial member - // we are supposed to ignore. - if (attrs.is_artificial) { + if (attrs.is_artificial && ShouldIgnoreArtificialField(attrs.name)) { last_field_info.SetIsArtificial(true); return; } @@ -2950,12 +3062,10 @@ void DWARFASTParserClang::ParseSingleMember( member_clang_type.GetCompleteType(); { - // Older versions of clang emit array[0] and array[1] in the - // same way (<rdar://problem/12566646>). If the current field - // is at the end of the structure, then there is definitely no - // room for extra elements and we override the type to - // array[0]. - + // Older versions of clang emit the same DWARF for array[0] and array[1]. If + // the current field is at the end of the structure, then there is + // definitely no room for extra elements and we override the type to + // array[0]. This was fixed by f454dfb6b5af. CompilerType member_array_element_type; uint64_t member_array_size; bool member_array_is_incomplete; @@ -2987,7 +3097,7 @@ void DWARFASTParserClang::ParseSingleMember( TypeSystemClang::RequireCompleteType(member_clang_type); clang::FieldDecl *field_decl = TypeSystemClang::AddFieldToRecordType( - class_clang_type, attrs.name, member_clang_type, attrs.accessibility, + class_clang_type, attrs.name, member_clang_type, accessibility, attrs.bit_size); m_ast.SetMetadataAsUserID(field_decl, die.GetID()); @@ -3022,6 +3132,17 @@ bool DWARFASTParserClang::ParseChildMembers( ParseObjCProperty(die, parent_die, class_clang_type, delayed_properties); break; + case DW_TAG_variant_part: + if (die.GetCU()->GetDWARFLanguageType() == eLanguageTypeRust) { + ParseRustVariantPart(die, parent_die, class_clang_type, + default_accessibility, layout_info); + } + break; + + case DW_TAG_variable: { + const MemberAttributes attrs(die, parent_die, module_sp); + CreateStaticMemberVariable(die, attrs, class_clang_type); + } break; case DW_TAG_member: ParseSingleMember(die, parent_die, class_clang_type, default_accessibility, layout_info, last_field_info); @@ -3167,30 +3288,6 @@ size_t DWARFASTParserClang::ParseChildParameters( return arg_idx; } -Type *DWARFASTParserClang::GetTypeForDIE(const DWARFDIE &die) { - if (!die) - return nullptr; - - SymbolFileDWARF *dwarf = die.GetDWARF(); - if (!dwarf) - return nullptr; - - DWARFAttributes attributes = die.GetAttributes(); - if (attributes.Size() == 0) - return nullptr; - - DWARFFormValue type_die_form; - for (size_t i = 0; i < attributes.Size(); ++i) { - dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - - if (attr == DW_AT_type && attributes.ExtractFormValueAtIndex(i, form_value)) - return dwarf->ResolveTypeUID(form_value.Reference(), true); - } - - return nullptr; -} - clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { if (!die) return nullptr; @@ -3566,7 +3663,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( // Make sure this is a declaration and not a concrete instance by looking // for DW_AT_declaration set to 1. Sometimes concrete function instances are // placed inside the class definitions and shouldn't be included in the list - // of things are are tracking here. + // of things that are tracking here. if (die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) != 1) return; @@ -3729,3 +3826,77 @@ bool DWARFASTParserClang::ShouldCreateUnnamedBitfield( return true; } + +void DWARFASTParserClang::ParseRustVariantPart( + DWARFDIE &die, const DWARFDIE &parent_die, CompilerType &class_clang_type, + const lldb::AccessType default_accesibility, + ClangASTImporter::LayoutInfo &layout_info) { + assert(die.Tag() == llvm::dwarf::DW_TAG_variant_part); + assert(SymbolFileDWARF::GetLanguage(*die.GetCU()) == + LanguageType::eLanguageTypeRust); + + ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); + + VariantPart variants(die, parent_die, module_sp); + + auto discriminant_type = + die.ResolveTypeUID(variants.discriminant().type_ref.Reference()); + + auto decl_context = m_ast.GetDeclContextForType(class_clang_type); + + auto inner_holder = m_ast.CreateRecordType( + decl_context, OptionalClangModuleID(), lldb::eAccessPublic, + std::string( + llvm::formatv("{0}$Inner", class_clang_type.GetTypeName(false))), + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeRust); + m_ast.StartTagDeclarationDefinition(inner_holder); + m_ast.SetIsPacked(inner_holder); + + for (auto member : variants.members()) { + + auto has_discriminant = !member.IsDefault(); + + auto member_type = die.ResolveTypeUID(member.type_ref.Reference()); + + auto field_type = m_ast.CreateRecordType( + m_ast.GetDeclContextForType(inner_holder), OptionalClangModuleID(), + lldb::eAccessPublic, + std::string(llvm::formatv("{0}$Variant", member.GetName())), + llvm::to_underlying(clang::TagTypeKind::Struct), + lldb::eLanguageTypeRust); + + m_ast.StartTagDeclarationDefinition(field_type); + auto offset = member.byte_offset; + + if (has_discriminant) { + m_ast.AddFieldToRecordType( + field_type, "$discr$", discriminant_type->GetFullCompilerType(), + lldb::eAccessPublic, variants.discriminant().byte_offset); + offset += discriminant_type->GetByteSize(nullptr).value_or(0); + } + + m_ast.AddFieldToRecordType(field_type, "value", + member_type->GetFullCompilerType(), + lldb::eAccessPublic, offset * 8); + + m_ast.CompleteTagDeclarationDefinition(field_type); + + auto name = has_discriminant + ? llvm::formatv("$variant${0}", member.discr_value.value()) + : std::string("$variant$"); + + auto variant_decl = + m_ast.AddFieldToRecordType(inner_holder, llvm::StringRef(name), + field_type, default_accesibility, 0); + + layout_info.field_offsets.insert({variant_decl, 0}); + } + + auto inner_field = m_ast.AddFieldToRecordType(class_clang_type, + llvm::StringRef("$variants$"), + inner_holder, eAccessPublic, 0); + + m_ast.CompleteTagDeclarationDefinition(inner_holder); + + layout_info.field_offsets.insert({inner_field, 0}); +} 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 042075b7df5f..3e28e54d6220 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -31,45 +31,51 @@ namespace lldb_private { class CompileUnit; } +namespace lldb_private::plugin { +namespace dwarf { class DWARFDebugInfoEntry; class SymbolFileDWARF; +} // namespace dwarf +} // namespace lldb_private::plugin struct ParsedDWARFTypeAttributes; -class DWARFASTParserClang : public DWARFASTParser { +class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser { public: DWARFASTParserClang(lldb_private::TypeSystemClang &ast); ~DWARFASTParserClang() override; // DWARFASTParser interface. - lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, - bool *type_is_new_ptr) override; + lldb::TypeSP + ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, + const lldb_private::plugin::dwarf::DWARFDIE &die, + bool *type_is_new_ptr) override; - lldb_private::ConstString - ConstructDemangledNameFromDWARF(const DWARFDIE &die) override; + lldb_private::ConstString ConstructDemangledNameFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die) override; lldb_private::Function * ParseFunctionFromDWARF(lldb_private::CompileUnit &comp_unit, - const DWARFDIE &die, + const lldb_private::plugin::dwarf::DWARFDIE &die, const lldb_private::AddressRange &func_range) override; bool - CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, + CompleteTypeFromDWARF(const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb_private::Type *type, lldb_private::CompilerType &compiler_type) override; - lldb_private::CompilerDecl - GetDeclForUIDFromDWARF(const DWARFDIE &die) override; + lldb_private::CompilerDecl GetDeclForUIDFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die) override; void EnsureAllDIEsInDeclContextHaveBeenParsed( lldb_private::CompilerDeclContext decl_context) override; - lldb_private::CompilerDeclContext - GetDeclContextForUIDFromDWARF(const DWARFDIE &die) override; + lldb_private::CompilerDeclContext GetDeclContextForUIDFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die) override; - lldb_private::CompilerDeclContext - GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) override; + lldb_private::CompilerDeclContext GetDeclContextContainingUIDFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die) override; lldb_private::ClangASTImporter &GetClangASTImporter(); @@ -85,9 +91,9 @@ public: /// DWARFFormValue with the bit width of the given integer type. /// Returns an error if the value in the DWARFFormValue does not fit /// into the given integer type or the integer type isn't supported. - llvm::Expected<llvm::APInt> - ExtractIntFromFormValue(const lldb_private::CompilerType &int_type, - const DWARFFormValue &form_value) const; + llvm::Expected<llvm::APInt> ExtractIntFromFormValue( + const lldb_private::CompilerType &int_type, + const lldb_private::plugin::dwarf::DWARFFormValue &form_value) const; /// Returns the template parameters of a class DWARFDIE as a string. /// @@ -99,8 +105,8 @@ public: /// \return A string, including surrounding '<>', of the template parameters. /// If the DIE's name already has '<>', returns an empty ConstString because /// it's assumed that the caller is using the DIE name anyway. - lldb_private::ConstString - GetDIEClassTemplateParams(const DWARFDIE &die) override; + lldb_private::ConstString GetDIEClassTemplateParams( + const lldb_private::plugin::dwarf::DWARFDIE &die) override; protected: /// Protected typedefs and members. @@ -108,14 +114,19 @@ protected: class DelayedAddObjCClassProperty; typedef std::vector<DelayedAddObjCClassProperty> DelayedPropertyList; - typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::DeclContext *> + typedef llvm::DenseMap< + const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *, + clang::DeclContext *> DIEToDeclContextMap; - typedef std::multimap<const clang::DeclContext *, const DWARFDIE> + typedef std::multimap<const clang::DeclContext *, + const lldb_private::plugin::dwarf::DWARFDIE> DeclContextToDIEMap; - typedef llvm::DenseMap<const DWARFDebugInfoEntry *, - lldb_private::OptionalClangModuleID> + typedef llvm::DenseMap< + const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *, + lldb_private::OptionalClangModuleID> DIEToModuleMap; - typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::Decl *> + typedef llvm::DenseMap< + const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *, clang::Decl *> DIEToDeclMap; lldb_private::TypeSystemClang &m_ast; @@ -126,11 +137,14 @@ protected: std::unique_ptr<lldb_private::ClangASTImporter> m_clang_ast_importer_up; /// @} - clang::DeclContext *GetDeclContextForBlock(const DWARFDIE &die); + clang::DeclContext * + GetDeclContextForBlock(const lldb_private::plugin::dwarf::DWARFDIE &die); - clang::BlockDecl *ResolveBlockDIE(const DWARFDIE &die); + clang::BlockDecl * + ResolveBlockDIE(const lldb_private::plugin::dwarf::DWARFDIE &die); - clang::NamespaceDecl *ResolveNamespaceDIE(const DWARFDIE &die); + clang::NamespaceDecl * + ResolveNamespaceDIE(const lldb_private::plugin::dwarf::DWARFDIE &die); /// Returns the namespace decl that a DW_TAG_imported_declaration imports. /// @@ -141,82 +155,99 @@ protected: /// 'die' imports. If the imported entity is not a namespace /// or another import declaration, returns nullptr. If an error /// occurs, returns nullptr. - clang::NamespaceDecl *ResolveImportedDeclarationDIE(const DWARFDIE &die); + clang::NamespaceDecl *ResolveImportedDeclarationDIE( + const lldb_private::plugin::dwarf::DWARFDIE &die); - bool ParseTemplateDIE(const DWARFDIE &die, + bool ParseTemplateDIE(const lldb_private::plugin::dwarf::DWARFDIE &die, lldb_private::TypeSystemClang::TemplateParameterInfos &template_param_infos); bool ParseTemplateParameterInfos( - const DWARFDIE &parent_die, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, lldb_private::TypeSystemClang::TemplateParameterInfos &template_param_infos); - std::string GetCPlusPlusQualifiedName(const DWARFDIE &die); + std::string + GetCPlusPlusQualifiedName(const lldb_private::plugin::dwarf::DWARFDIE &die); bool ParseChildMembers( - const DWARFDIE &die, lldb_private::CompilerType &class_compiler_type, + const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb_private::CompilerType &class_compiler_type, std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, - std::vector<DWARFDIE> &member_function_dies, + std::vector<lldb_private::plugin::dwarf::DWARFDIE> &member_function_dies, DelayedPropertyList &delayed_properties, const lldb::AccessType default_accessibility, lldb_private::ClangASTImporter::LayoutInfo &layout_info); size_t ParseChildParameters(clang::DeclContext *containing_decl_ctx, - const DWARFDIE &parent_die, bool skip_artificial, - bool &is_static, bool &is_variadic, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, + bool skip_artificial, bool &is_static, bool &is_variadic, bool &has_template_params, std::vector<lldb_private::CompilerType> &function_args, std::vector<clang::ParmVarDecl *> &function_param_decls, unsigned &type_quals); - size_t ParseChildEnumerators(lldb_private::CompilerType &compiler_type, - bool is_signed, uint32_t enumerator_byte_size, - const DWARFDIE &parent_die); + size_t ParseChildEnumerators( + lldb_private::CompilerType &compiler_type, bool is_signed, + uint32_t enumerator_byte_size, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die); /// Parse a structure, class, or union type DIE. - lldb::TypeSP ParseStructureLikeDIE(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, - ParsedDWARFTypeAttributes &attrs); - - lldb_private::Type *GetTypeForDIE(const DWARFDIE &die); + lldb::TypeSP + ParseStructureLikeDIE(const lldb_private::SymbolContext &sc, + const lldb_private::plugin::dwarf::DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); - clang::Decl *GetClangDeclForDIE(const DWARFDIE &die); + clang::Decl * + GetClangDeclForDIE(const lldb_private::plugin::dwarf::DWARFDIE &die); - clang::DeclContext *GetClangDeclContextForDIE(const DWARFDIE &die); + clang::DeclContext * + GetClangDeclContextForDIE(const lldb_private::plugin::dwarf::DWARFDIE &die); - clang::DeclContext *GetClangDeclContextContainingDIE(const DWARFDIE &die, - DWARFDIE *decl_ctx_die); - lldb_private::OptionalClangModuleID GetOwningClangModule(const DWARFDIE &die); + clang::DeclContext *GetClangDeclContextContainingDIE( + const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb_private::plugin::dwarf::DWARFDIE *decl_ctx_die); + lldb_private::OptionalClangModuleID + GetOwningClangModule(const lldb_private::plugin::dwarf::DWARFDIE &die); - bool CopyUniqueClassMethodTypes(const DWARFDIE &src_class_die, - const DWARFDIE &dst_class_die, - lldb_private::Type *class_type, - std::vector<DWARFDIE> &failures); + bool CopyUniqueClassMethodTypes( + const lldb_private::plugin::dwarf::DWARFDIE &src_class_die, + const lldb_private::plugin::dwarf::DWARFDIE &dst_class_die, + lldb_private::Type *class_type, + std::vector<lldb_private::plugin::dwarf::DWARFDIE> &failures); - clang::DeclContext *GetCachedClangDeclContextForDIE(const DWARFDIE &die); + clang::DeclContext *GetCachedClangDeclContextForDIE( + const lldb_private::plugin::dwarf::DWARFDIE &die); - void LinkDeclContextToDIE(clang::DeclContext *decl_ctx, const DWARFDIE &die); + void LinkDeclContextToDIE(clang::DeclContext *decl_ctx, + const lldb_private::plugin::dwarf::DWARFDIE &die); - void LinkDeclToDIE(clang::Decl *decl, const DWARFDIE &die); + void LinkDeclToDIE(clang::Decl *decl, + const lldb_private::plugin::dwarf::DWARFDIE &die); /// If \p type_sp is valid, calculate and set its symbol context scope, and /// update the type list for its backing symbol file. /// /// Returns \p type_sp. - lldb::TypeSP - UpdateSymbolContextScopeForType(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, lldb::TypeSP type_sp); + lldb::TypeSP UpdateSymbolContextScopeForType( + const lldb_private::SymbolContext &sc, + const lldb_private::plugin::dwarf::DWARFDIE &die, lldb::TypeSP type_sp); /// Follow Clang Module Skeleton CU references to find a type definition. - lldb::TypeSP ParseTypeFromClangModule(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, - lldb_private::Log *log); + lldb::TypeSP + ParseTypeFromClangModule(const lldb_private::SymbolContext &sc, + const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb_private::Log *log); // Return true if this type is a declaration to a type in an external // module. - lldb::ModuleSP GetModuleForType(const DWARFDIE &die); + lldb::ModuleSP + GetModuleForType(const lldb_private::plugin::dwarf::DWARFDIE &die); + + static bool classof(const DWARFASTParser *Parser) { + return Parser->GetKind() == Kind::DWARFASTParserClang; + } private: struct FieldInfo { @@ -240,6 +271,30 @@ private: } }; + /// Parsed form of all attributes that are relevant for parsing type members. + struct MemberAttributes { + explicit MemberAttributes( + const lldb_private::plugin::dwarf::DWARFDIE &die, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, + lldb::ModuleSP module_sp); + const char *name = nullptr; + /// Indicates how many bits into the word (according to the host endianness) + /// the low-order bit of the field starts. Can be negative. + int64_t bit_offset = 0; + /// Indicates the size of the field in bits. + size_t bit_size = 0; + uint64_t data_bit_offset = UINT64_MAX; + lldb::AccessType accessibility = lldb::eAccessNone; + std::optional<uint64_t> byte_size; + std::optional<lldb_private::plugin::dwarf::DWARFFormValue> const_value_form; + lldb_private::plugin::dwarf::DWARFFormValue encoding_form; + /// Indicates the byte offset of the word from the base address of the + /// structure. + uint32_t member_byte_offset = UINT32_MAX; + bool is_artificial = false; + bool is_declaration = false; + }; + /// Returns 'true' if we should create an unnamed bitfield /// and add it to the parser's current AST. /// @@ -268,33 +323,57 @@ private: /// created property. /// \param delayed_properties The list of delayed properties that the result /// will be appended to. - void ParseObjCProperty(const DWARFDIE &die, const DWARFDIE &parent_die, - const lldb_private::CompilerType &class_clang_type, - DelayedPropertyList &delayed_properties); + void + ParseObjCProperty(const lldb_private::plugin::dwarf::DWARFDIE &die, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, + const lldb_private::CompilerType &class_clang_type, + DelayedPropertyList &delayed_properties); void - ParseSingleMember(const DWARFDIE &die, const DWARFDIE &parent_die, + ParseSingleMember(const lldb_private::plugin::dwarf::DWARFDIE &die, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, const lldb_private::CompilerType &class_clang_type, lldb::AccessType default_accessibility, lldb_private::ClangASTImporter::LayoutInfo &layout_info, FieldInfo &last_field_info); - bool CompleteRecordType(const DWARFDIE &die, lldb_private::Type *type, + /// If the specified 'die' represents a static data member, creates + /// a 'clang::VarDecl' for it and attaches it to specified parent + /// 'class_clang_type'. + /// + /// \param[in] die The member declaration we want to create a + /// clang::VarDecl for. + /// + /// \param[in] attrs The parsed attributes for the specified 'die'. + /// + /// \param[in] class_clang_type The parent RecordType of the static + /// member this function will create. + void CreateStaticMemberVariable( + const lldb_private::plugin::dwarf::DWARFDIE &die, + const MemberAttributes &attrs, + const lldb_private::CompilerType &class_clang_type); + + bool CompleteRecordType(const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb_private::Type *type, lldb_private::CompilerType &clang_type); - bool CompleteEnumType(const DWARFDIE &die, lldb_private::Type *type, + bool CompleteEnumType(const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb_private::Type *type, lldb_private::CompilerType &clang_type); - lldb::TypeSP ParseTypeModifier(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, - ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP + ParseTypeModifier(const lldb_private::SymbolContext &sc, + const lldb_private::plugin::dwarf::DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); lldb::TypeSP ParseEnum(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs); - lldb::TypeSP ParseSubroutine(const DWARFDIE &die, - ParsedDWARFTypeAttributes &attrs); - lldb::TypeSP ParseArrayType(const DWARFDIE &die, + const lldb_private::plugin::dwarf::DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP ParseSubroutine(const lldb_private::plugin::dwarf::DWARFDIE &die, + const ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP ParseArrayType(const lldb_private::plugin::dwarf::DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs); - lldb::TypeSP ParsePointerToMemberType(const DWARFDIE &die, - const ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP + ParsePointerToMemberType(const lldb_private::plugin::dwarf::DWARFDIE &die, + const ParsedDWARFTypeAttributes &attrs); /// Parses a DW_TAG_inheritance DIE into a base/super class. /// @@ -311,19 +390,37 @@ private: /// \param layout_info The layout information that will be updated for C++ /// base classes with the base offset. void ParseInheritance( - const DWARFDIE &die, const DWARFDIE &parent_die, + const lldb_private::plugin::dwarf::DWARFDIE &die, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, const lldb_private::CompilerType class_clang_type, const lldb::AccessType default_accessibility, const lldb::ModuleSP &module_sp, std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, lldb_private::ClangASTImporter::LayoutInfo &layout_info); + + /// Parses DW_TAG_variant_part DIE into a structure that encodes all variants + /// Note that this is currently being emitted by rustc and not Clang + /// \param die DW_TAG_variant_part DIE to parse + /// \param parent_die The parent DW_TAG_structure_type to parse + /// \param class_clang_type The Rust struct representing parent_die. + /// \param default_accesibility The default accessibility that is given to + /// base classes if they don't have an explicit accessibility set + /// \param layout_info The layout information that will be updated for + // base classes with the base offset + void + ParseRustVariantPart(lldb_private::plugin::dwarf::DWARFDIE &die, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, + lldb_private::CompilerType &class_clang_type, + const lldb::AccessType default_accesibility, + lldb_private::ClangASTImporter::LayoutInfo &layout_info); }; /// Parsed form of all attributes that are relevant for type reconstruction. /// Some attributes are relevant for all kinds of types (declaration), while /// others are only meaningful to a specific type (is_virtual) struct ParsedDWARFTypeAttributes { - explicit ParsedDWARFTypeAttributes(const DWARFDIE &die); + explicit ParsedDWARFTypeAttributes( + const lldb_private::plugin::dwarf::DWARFDIE &die); lldb::AccessType accessibility = lldb::eAccessNone; bool is_artificial = false; @@ -340,14 +437,15 @@ struct ParsedDWARFTypeAttributes { const char *mangled_name = nullptr; lldb_private::ConstString name; lldb_private::Declaration decl; - DWARFDIE object_pointer; - DWARFFormValue abstract_origin; - DWARFFormValue containing_type; - DWARFFormValue signature; - DWARFFormValue specification; - DWARFFormValue type; + lldb_private::plugin::dwarf::DWARFDIE object_pointer; + lldb_private::plugin::dwarf::DWARFFormValue abstract_origin; + lldb_private::plugin::dwarf::DWARFFormValue containing_type; + lldb_private::plugin::dwarf::DWARFFormValue signature; + lldb_private::plugin::dwarf::DWARFFormValue specification; + lldb_private::plugin::dwarf::DWARFFormValue type; lldb::LanguageType class_language = lldb::eLanguageTypeUnknown; std::optional<uint64_t> byte_size; + std::optional<uint64_t> alignment; size_t calling_convention = llvm::dwarf::DW_CC_normal; uint32_t bit_stride = 0; uint32_t byte_stride = 0; 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 00b56537ae2b..3d35775e081e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -11,6 +11,7 @@ #include "DWARFDebugInfo.h" using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; DWARFAttributes::DWARFAttributes() : m_infos() {} 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 90e12fa02493..e05ccc980d92 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h @@ -14,6 +14,8 @@ #include "llvm/ADT/SmallVector.h" #include <vector> +namespace lldb_private::plugin { +namespace dwarf { class DWARFUnit; class DWARFAttribute { @@ -31,6 +33,7 @@ public: form = m_form; val = m_value; } + protected: dw_attr_t m_attr; dw_form_t m_form; @@ -72,5 +75,7 @@ protected: typedef llvm::SmallVector<AttributeValue, 8> collection; collection m_infos; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFATTRIBUTE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp index 37a917c3a766..3a3b05acd26d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp @@ -18,6 +18,7 @@ #include <optional> using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; std::optional<DIERef> DWARFBaseDIE::GetDIERef() const { if (!IsValid()) @@ -35,7 +36,7 @@ dw_tag_t DWARFBaseDIE::Tag() const { } const char *DWARFBaseDIE::GetTagAsCString() const { - return lldb_private::DW_TAG_value_to_name(Tag()); + return DW_TAG_value_to_name(Tag()); } const char *DWARFBaseDIE::GetAttributeValueAsString(const dw_attr_t attr, @@ -120,6 +121,8 @@ DWARFAttributes DWARFBaseDIE::GetAttributes(Recurse recurse) const { return DWARFAttributes(); } +namespace lldb_private::plugin { +namespace dwarf { bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) { return lhs.GetDIE() == rhs.GetDIE() && lhs.GetCU() == rhs.GetCU(); } @@ -127,6 +130,8 @@ bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) { bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) { return !(lhs == rhs); } +} // namespace dwarf +} // namespace lldb_private::plugin const DWARFDataExtractor &DWARFBaseDIE::GetData() const { // Clients must check if this DIE is valid before calling this function. diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h index 8bcf807ad163..75c822703cd8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h @@ -15,6 +15,8 @@ #include "llvm/Support/Error.h" #include <optional> +namespace lldb_private::plugin { +namespace dwarf { class DIERef; class DWARFASTParser; class DWARFAttributes; @@ -78,7 +80,7 @@ public: // correct section data. // // Clients must validate that this object is valid before calling this. - const lldb_private::DWARFDataExtractor &GetData() const; + const DWARFDataExtractor &GetData() const; // Accessing information about a DIE dw_tag_t Tag() const; @@ -124,5 +126,7 @@ protected: bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFBASEDIE_H 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 f839a59bf6c3..ec4c297cf7e1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -16,6 +16,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; void DWARFCompileUnit::Dump(Stream *s) const { s->Format( 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 ab3017ba0ffc..dd130977d4b1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -12,11 +12,17 @@ #include "DWARFUnit.h" #include "llvm/Support/Error.h" +namespace llvm { +class DWARFAbbreviationDeclarationSet; +} // namespace llvm + +namespace lldb_private::plugin { +namespace dwarf { class DWARFCompileUnit : public DWARFUnit { public: void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) override; - void Dump(lldb_private::Stream *s) const override; + void Dump(Stream *s) const override; static bool classof(const DWARFUnit *unit) { return !unit->IsTypeUnit(); } @@ -27,7 +33,7 @@ public: private: DWARFCompileUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, - const DWARFAbbreviationDeclarationSet &abbrevs, + const llvm::DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo) : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} @@ -36,5 +42,7 @@ private: friend class DWARFUnit; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCOMPILEUNIT_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp index f72dad88e157..e3872dc626be 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp @@ -13,6 +13,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; static DWARFDataExtractor LoadSection(SectionList *section_list, SectionType section_type) { @@ -141,7 +142,10 @@ llvm::DWARFContext &DWARFContext::GetAsLLVM() { AddSection("debug_line_str", getOrLoadLineStrData()); AddSection("debug_cu_index", getOrLoadCuIndexData()); AddSection("debug_tu_index", getOrLoadTuIndexData()); - + if (isDwo()) { + AddSection("debug_info.dwo", getOrLoadDebugInfoData()); + AddSection("debug_types.dwo", getOrLoadDebugTypesData()); + } m_llvm_context = llvm::DWARFContext::create(section_map, addr_size); } return *m_llvm_context; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h index 7df776b5f514..87c6eb209337 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h @@ -16,7 +16,8 @@ #include <memory> #include <optional> -namespace lldb_private { +namespace lldb_private::plugin { +namespace dwarf { class DWARFContext { private: SectionList *m_main_section_list; @@ -78,6 +79,7 @@ public: llvm::DWARFContext &GetAsLLVM(); }; -} // namespace lldb_private +} // namespace dwarf +} // namespace lldb_private::plugin #endif diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index b31c5dcac918..bed68f45426f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -18,6 +18,7 @@ using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; namespace { @@ -372,47 +373,97 @@ std::vector<DWARFDIE> DWARFDIE::GetDeclContextDIEs() const { return result; } -void DWARFDIE::GetDeclContext( - llvm::SmallVectorImpl<lldb_private::CompilerContext> &context) const { +std::vector<lldb_private::CompilerContext> DWARFDIE::GetDeclContext() const { + std::vector<lldb_private::CompilerContext> context; const dw_tag_t tag = Tag(); if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) - return; + return context; DWARFDIE parent = GetParent(); if (parent) - parent.GetDeclContext(context); + context = parent.GetDeclContext(); + auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { + context.push_back({kind, ConstString(name)}); + }; switch (tag) { case DW_TAG_module: - context.push_back({CompilerContextKind::Module, ConstString(GetName())}); + push_ctx(CompilerContextKind::Module, GetName()); break; case DW_TAG_namespace: - context.push_back({CompilerContextKind::Namespace, ConstString(GetName())}); + push_ctx(CompilerContextKind::Namespace, GetName()); break; case DW_TAG_structure_type: - context.push_back({CompilerContextKind::Struct, ConstString(GetName())}); + push_ctx(CompilerContextKind::Struct, GetName()); break; case DW_TAG_union_type: - context.push_back({CompilerContextKind::Union, ConstString(GetName())}); + push_ctx(CompilerContextKind::Union, GetName()); break; case DW_TAG_class_type: - context.push_back({CompilerContextKind::Class, ConstString(GetName())}); + push_ctx(CompilerContextKind::Class, GetName()); break; case DW_TAG_enumeration_type: - context.push_back({CompilerContextKind::Enum, ConstString(GetName())}); + push_ctx(CompilerContextKind::Enum, GetName()); break; case DW_TAG_subprogram: - context.push_back( - {CompilerContextKind::Function, ConstString(GetPubname())}); + push_ctx(CompilerContextKind::Function, GetPubname()); break; case DW_TAG_variable: - context.push_back( - {CompilerContextKind::Variable, ConstString(GetPubname())}); + push_ctx(CompilerContextKind::Variable, GetPubname()); break; case DW_TAG_typedef: - context.push_back({CompilerContextKind::Typedef, ConstString(GetName())}); + push_ctx(CompilerContextKind::Typedef, GetName()); + break; + default: + break; + } + return context; +} + +std::vector<lldb_private::CompilerContext> +DWARFDIE::GetTypeLookupContext() const { + std::vector<lldb_private::CompilerContext> context; + // If there is no name, then there is no need to look anything up for this + // DIE. + const char *name = GetName(); + if (!name || !name[0]) + return context; + const dw_tag_t tag = Tag(); + if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) + return context; + DWARFDIE parent = GetParent(); + if (parent) + context = parent.GetTypeLookupContext(); + auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { + context.push_back({kind, ConstString(name)}); + }; + switch (tag) { + case DW_TAG_namespace: + push_ctx(CompilerContextKind::Namespace, name); + break; + case DW_TAG_structure_type: + push_ctx(CompilerContextKind::Struct, name); + break; + case DW_TAG_union_type: + push_ctx(CompilerContextKind::Union, name); + break; + case DW_TAG_class_type: + push_ctx(CompilerContextKind::Class, name); + break; + case DW_TAG_enumeration_type: + push_ctx(CompilerContextKind::Enum, name); + break; + case DW_TAG_variable: + push_ctx(CompilerContextKind::Variable, GetPubname()); + break; + case DW_TAG_typedef: + push_ctx(CompilerContextKind::Typedef, name); + break; + case DW_TAG_base_type: + push_ctx(CompilerContextKind::Builtin, name); break; default: break; } + return context; } DWARFDIE diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 031ea26ad405..511ca62d0197 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -13,6 +13,8 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/iterator_range.h" +namespace lldb_private::plugin { +namespace dwarf { class DWARFDIE : public DWARFBaseDIE { public: class child_iterator; @@ -31,14 +33,14 @@ public: const char *GetPubname() const; using DWARFBaseDIE::GetName; - void GetName(lldb_private::Stream &s) const; + void GetName(Stream &s) const; - void AppendTypeName(lldb_private::Stream &s) const; + void AppendTypeName(Stream &s) const; - lldb_private::Type *ResolveType() const; + Type *ResolveType() const; // Resolve a type by UID using this DIE's DWARF file - lldb_private::Type *ResolveTypeUID(const DWARFDIE &die) const; + Type *ResolveTypeUID(const DWARFDIE &die) const; // Functions for obtaining DIE relations and references @@ -71,9 +73,21 @@ public: std::vector<DWARFDIE> GetDeclContextDIEs() const; /// Return this DIE's decl context as it is needed to look up types - /// in Clang's -gmodules debug info format. - void GetDeclContext( - llvm::SmallVectorImpl<lldb_private::CompilerContext> &context) const; + /// in Clang modules. This context will include any modules or functions that + /// the type is declared in so an exact module match can be efficiently made. + std::vector<CompilerContext> GetDeclContext() const; + + /// Get a context to a type so it can be looked up. + /// + /// This function uses the current DIE to fill in a CompilerContext array + /// that is suitable for type lookup for comparison to a TypeQuery's compiler + /// context (TypeQuery::GetContextRef()). If this DIE represents a named type, + /// it should fill out the compiler context with the type itself as the last + /// entry. The declaration context should be above the type and stop at an + /// appropriate time, like either the translation unit or at a function + /// context. This is designed to allow users to efficiently look for types + /// using a full or partial CompilerContext array. + std::vector<CompilerContext> GetTypeLookupContext() const; // Getting attribute values from the DIE. // @@ -88,7 +102,7 @@ public: std::optional<int> &decl_file, std::optional<int> &decl_line, std::optional<int> &decl_column, std::optional<int> &call_file, std::optional<int> &call_line, std::optional<int> &call_column, - lldb_private::DWARFExpressionList *frame_base) const; + DWARFExpressionList *frame_base) const; /// The range of all the children of this DIE. llvm::iterator_range<child_iterator> children() const; @@ -126,5 +140,7 @@ public: return *this; } }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h index b9526b079c1e..41b8e9ad0217 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h @@ -33,6 +33,6 @@ public: llvm::DWARFDataExtractor GetAsLLVMDWARF() const; llvm::DataExtractor GetAsLLVM() const; }; -} +} // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDATAEXTRACTOR_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp deleted file mode 100644 index 0cd53463ee65..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp +++ /dev/null @@ -1,67 +0,0 @@ -//===-- DWARFDebugAbbrev.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 "DWARFDebugAbbrev.h" -#include "DWARFDataExtractor.h" -#include "DWARFFormValue.h" -#include "lldb/Utility/Stream.h" - -using namespace lldb; -using namespace lldb_private; - -// DWARFDebugAbbrev constructor -DWARFDebugAbbrev::DWARFDebugAbbrev() - : m_abbrevCollMap(), m_prev_abbr_offset_pos(m_abbrevCollMap.end()) {} - -// DWARFDebugAbbrev::Parse() -llvm::Error DWARFDebugAbbrev::parse(const DWARFDataExtractor &data) { - llvm::DataExtractor llvm_data = data.GetAsLLVM(); - lldb::offset_t offset = 0; - - while (llvm_data.isValidOffset(offset)) { - uint32_t initial_cu_offset = offset; - DWARFAbbreviationDeclarationSet abbrevDeclSet; - - llvm::Error error = abbrevDeclSet.extract(llvm_data, &offset); - if (error) - return error; - - m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet; - } - m_prev_abbr_offset_pos = m_abbrevCollMap.end(); - return llvm::ErrorSuccess(); -} - -// DWARFDebugAbbrev::GetAbbreviationDeclarationSet() -const DWARFAbbreviationDeclarationSet * -DWARFDebugAbbrev::GetAbbreviationDeclarationSet( - dw_offset_t cu_abbr_offset) const { - DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end(); - DWARFAbbreviationDeclarationCollMapConstIter pos; - if (m_prev_abbr_offset_pos != end && - m_prev_abbr_offset_pos->first == cu_abbr_offset) - return &(m_prev_abbr_offset_pos->second); - else { - pos = m_abbrevCollMap.find(cu_abbr_offset); - m_prev_abbr_offset_pos = pos; - } - - if (pos != m_abbrevCollMap.end()) - return &(pos->second); - return nullptr; -} - -// DWARFDebugAbbrev::GetUnsupportedForms() -void DWARFDebugAbbrev::GetUnsupportedForms( - std::set<dw_form_t> &invalid_forms) const { - for (const auto &pair : m_abbrevCollMap) - for (const auto &decl : pair.second) - for (const auto &attr : decl.attributes()) - if (!DWARFFormValue::FormIsSupported(attr.Form)) - invalid_forms.insert(attr.Form); -} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h deleted file mode 100644 index 0a579e34b001..000000000000 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h +++ /dev/null @@ -1,46 +0,0 @@ -//===-- DWARFDebugAbbrev.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_SYMBOLFILE_DWARF_DWARFDEBUGABBREV_H -#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGABBREV_H - -#include "DWARFDefines.h" -#include "lldb/lldb-private.h" - -#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" - -#include <map> - -using DWARFAbbreviationDeclaration = llvm::DWARFAbbreviationDeclaration; -using DWARFAbbreviationDeclarationSet = llvm::DWARFAbbreviationDeclarationSet; - -typedef std::map<dw_offset_t, DWARFAbbreviationDeclarationSet> - DWARFAbbreviationDeclarationCollMap; -typedef DWARFAbbreviationDeclarationCollMap::iterator - DWARFAbbreviationDeclarationCollMapIter; -typedef DWARFAbbreviationDeclarationCollMap::const_iterator - DWARFAbbreviationDeclarationCollMapConstIter; - -class DWARFDebugAbbrev { -public: - DWARFDebugAbbrev(); - const DWARFAbbreviationDeclarationSet * - GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const; - /// Extract all abbreviations for a particular compile unit. Returns - /// llvm::ErrorSuccess() on success, and an appropriate llvm::Error object - /// otherwise. - llvm::Error parse(const lldb_private::DWARFDataExtractor &data); - void GetUnsupportedForms(std::set<dw_form_t> &invalid_forms) const; - -protected: - DWARFAbbreviationDeclarationCollMap m_abbrevCollMap; - mutable DWARFAbbreviationDeclarationCollMapConstIter m_prev_abbr_offset_pos; -}; - -#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGABBREV_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp index 03cbfd28ae74..8461b94abca6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp @@ -13,6 +13,7 @@ #include <cassert> using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; DWARFDebugArangeSet::DWARFDebugArangeSet() : m_offset(DW_INVALID_OFFSET), m_next_offset(DW_INVALID_OFFSET) {} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h index 3c8633eaa3cc..ecdbe953f58b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h @@ -13,6 +13,8 @@ #include <cstdint> #include <vector> +namespace lldb_private::plugin { +namespace dwarf { class DWARFDebugArangeSet { public: struct Header { @@ -42,7 +44,7 @@ public: DWARFDebugArangeSet(); void Clear(); void SetOffset(uint32_t offset) { m_offset = offset; } - llvm::Error extract(const lldb_private::DWARFDataExtractor &data, + llvm::Error extract(const DWARFDataExtractor &data, lldb::offset_t *offset_ptr); dw_offset_t FindAddress(dw_addr_t address) const; size_t NumDescriptors() const { return m_arange_descriptors.size(); } @@ -62,5 +64,7 @@ protected: Header m_header; DescriptorColl m_arange_descriptors; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGESET_H 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 b38dd2b88c9d..da73891f6665 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -15,6 +15,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; // Constructor DWARFDebugAranges::DWARFDebugAranges() : m_aranges() {} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h index 5ff37e400c88..99e2108b85c6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h @@ -13,10 +13,11 @@ #include "lldb/Utility/RangeMap.h" #include "llvm/Support/Error.h" +namespace lldb_private::plugin { +namespace dwarf { class DWARFDebugAranges { protected: - typedef lldb_private::RangeDataVector<dw_addr_t, uint32_t, dw_offset_t> - RangeToDIE; + typedef RangeDataVector<dw_addr_t, uint32_t, dw_offset_t> RangeToDIE; public: typedef RangeToDIE::Entry Range; @@ -26,14 +27,14 @@ public: void Clear() { m_aranges.Clear(); } - void extract(const lldb_private::DWARFDataExtractor &debug_aranges_data); + void extract(const DWARFDataExtractor &debug_aranges_data); // Use append range multiple times and then call sort void AppendRange(dw_offset_t cu_offset, dw_addr_t low_pc, dw_addr_t high_pc); void Sort(bool minimize); - void Dump(lldb_private::Log *log) const; + void Dump(Log *log) const; dw_offset_t FindAddress(dw_addr_t address) const; @@ -50,5 +51,7 @@ public: protected: RangeToDIE m_aranges; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGES_H 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 9a33d6338b87..553b6a4c551d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -27,10 +27,10 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; // Constructor -DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf, - lldb_private::DWARFContext &context) +DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf, DWARFContext &context) : m_dwarf(dwarf), m_context(context), m_units(), m_cu_aranges_up() {} const DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() { diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index c990ac9fbe58..d5e48f312ea0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -19,20 +19,18 @@ #include "lldb/lldb-private.h" #include "llvm/Support/Error.h" -namespace lldb_private { +namespace lldb_private::plugin { +namespace dwarf { class DWARFContext; -} class DWARFDebugInfo { public: - typedef dw_offset_t (*Callback)(SymbolFileDWARF *dwarf2Data, - DWARFUnit *cu, + typedef dw_offset_t (*Callback)(SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, DWARFDebugInfoEntry *die, const dw_offset_t next_offset, const uint32_t depth, void *userData); - explicit DWARFDebugInfo(SymbolFileDWARF &dwarf, - lldb_private::DWARFContext &context); + explicit DWARFDebugInfo(SymbolFileDWARF &dwarf, DWARFContext &context); size_t GetNumUnits(); DWARFUnit *GetUnitAtIndex(size_t idx); @@ -58,7 +56,7 @@ protected: typedef std::vector<DWARFUnitSP> UnitColl; SymbolFileDWARF &m_dwarf; - lldb_private::DWARFContext &m_context; + DWARFContext &m_context; llvm::once_flag m_units_once_flag; UnitColl m_units; @@ -80,5 +78,7 @@ private: DWARFDebugInfo(const DWARFDebugInfo &) = delete; const DWARFDebugInfo &operator=(const DWARFDebugInfo &) = delete; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFO_H 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 a08637aef066..1b0fefedf983 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -22,7 +22,6 @@ #include "lldb/Utility/StreamString.h" #include "DWARFCompileUnit.h" -#include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "DWARFDebugRanges.h" @@ -32,8 +31,11 @@ #include "SymbolFileDWARF.h" #include "SymbolFileDWARFDwo.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" + using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; extern int g_verbose; // Extract a debug info entry for a given DWARFUnit from the data @@ -48,16 +50,12 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, lldbassert(abbr_idx <= UINT16_MAX); m_abbr_idx = abbr_idx; - // assert (fixed_form_sizes); // For best performance this should be - // specified! - if (m_abbr_idx == 0) { m_tag = llvm::dwarf::DW_TAG_null; m_has_children = false; return true; // NULL debug tag entry } - lldb::offset_t offset = *offset_ptr; const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu); if (abbrevDecl == nullptr) { cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( @@ -72,137 +70,18 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, m_tag = abbrevDecl->getTag(); m_has_children = abbrevDecl->hasChildren(); // Skip all data in the .debug_info or .debug_types for the attributes - dw_form_t form; for (const auto &attribute : abbrevDecl->attributes()) { - form = attribute.Form; - std::optional<uint8_t> fixed_skip_size = - DWARFFormValue::GetFixedSize(form, cu); - if (fixed_skip_size) - offset += *fixed_skip_size; - else { - bool form_is_indirect = false; - do { - form_is_indirect = false; - uint32_t form_size = 0; - switch (form) { - // Blocks if inlined data that have a length field and the data bytes - // inlined in the .debug_info/.debug_types - case DW_FORM_exprloc: - case DW_FORM_block: - form_size = data.GetULEB128(&offset); - break; - case DW_FORM_block1: - form_size = data.GetU8_unchecked(&offset); - break; - case DW_FORM_block2: - form_size = data.GetU16_unchecked(&offset); - break; - case DW_FORM_block4: - form_size = data.GetU32_unchecked(&offset); - break; - - // Inlined NULL terminated C-strings - case DW_FORM_string: - data.GetCStr(&offset); - break; - - // Compile unit address sized values - case DW_FORM_addr: - form_size = cu->GetAddressByteSize(); - break; - case DW_FORM_ref_addr: - if (cu->GetVersion() <= 2) - form_size = cu->GetAddressByteSize(); - else - form_size = 4; - break; - - // 0 sized form - case DW_FORM_flag_present: - form_size = 0; - break; - - // 1 byte values - case DW_FORM_addrx1: - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - case DW_FORM_strx1: - form_size = 1; - break; - - // 2 byte values - case DW_FORM_addrx2: - case DW_FORM_data2: - case DW_FORM_ref2: - case DW_FORM_strx2: - form_size = 2; - break; - - // 3 byte values - case DW_FORM_addrx3: - case DW_FORM_strx3: - form_size = 3; - break; + if (DWARFFormValue::SkipValue(attribute.Form, data, offset_ptr, cu)) + continue; - // 4 byte values - case DW_FORM_addrx4: - case DW_FORM_data4: - case DW_FORM_ref4: - case DW_FORM_strx4: - form_size = 4; - break; - - // 8 byte values - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - form_size = 8; - break; - - // signed or unsigned LEB 128 values - case DW_FORM_addrx: - case DW_FORM_loclistx: - case DW_FORM_rnglistx: - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_GNU_addr_index: - case DW_FORM_GNU_str_index: - case DW_FORM_strx: - data.Skip_LEB128(&offset); - break; - - case DW_FORM_indirect: - form_is_indirect = true; - form = static_cast<dw_form_t>(data.GetULEB128(&offset)); - break; - - case DW_FORM_strp: - case DW_FORM_line_strp: - case DW_FORM_sec_offset: - data.GetU32(&offset); - break; - - case DW_FORM_implicit_const: - form_size = 0; - break; - - default: - cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( - "[{0:x16}]: Unsupported DW_FORM_{1:x}, please file a bug " - "and " - "attach the file at the start of this error message", - (uint64_t)m_offset, (unsigned)form); - *offset_ptr = m_offset; - return false; - } - offset += form_size; - - } while (form_is_indirect); - } + cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "[{0:x16}]: Unsupported DW_FORM_{1:x}, please file a bug " + "and " + "attach the file at the start of this error message", + (uint64_t)m_offset, (unsigned)attribute.Form); + *offset_ptr = m_offset; + return false; } - *offset_ptr = offset; return true; } @@ -810,12 +689,13 @@ lldb::offset_t DWARFDebugInfoEntry::GetFirstAttributeOffset() const { return GetOffset() + llvm::getULEB128Size(m_abbr_idx); } -const DWARFAbbreviationDeclaration * +const llvm::DWARFAbbreviationDeclaration * DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const { if (!cu) return nullptr; - const DWARFAbbreviationDeclarationSet *abbrev_set = cu->GetAbbreviations(); + const llvm::DWARFAbbreviationDeclarationSet *abbrev_set = + cu->GetAbbreviations(); if (!abbrev_set) return nullptr; 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 c2ea40065232..c19fa7428549 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -14,7 +14,6 @@ #include "DWARFAttribute.h" #include "DWARFBaseDIE.h" -#include "DWARFDebugAbbrev.h" #include "DWARFDebugRanges.h" #include <map> #include <optional> @@ -23,6 +22,8 @@ #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +namespace lldb_private::plugin { +namespace dwarf { class DWARFDeclContext; #define DIE_SIBLING_IDX_BITSIZE 31 @@ -48,8 +49,8 @@ public: void BuildFunctionAddressRangeTable(DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; - bool Extract(const lldb_private::DWARFDataExtractor &data, - const DWARFUnit *cu, lldb::offset_t *offset_ptr); + bool Extract(const DWARFDataExtractor &data, const DWARFUnit *cu, + lldb::offset_t *offset_ptr); using Recurse = DWARFBaseDIE::Recurse; DWARFAttributes GetAttributes(DWARFUnit *cu, @@ -105,13 +106,15 @@ public: const char *GetPubname(const DWARFUnit *cu) const; - bool GetDIENamesAndRanges( - DWARFUnit *cu, const char *&name, const char *&mangled, - DWARFRangeList &rangeList, std::optional<int> &decl_file, - std::optional<int> &decl_line, std::optional<int> &decl_column, - std::optional<int> &call_file, std::optional<int> &call_line, - std::optional<int> &call_column, - lldb_private::DWARFExpressionList *frame_base = nullptr) const; + bool GetDIENamesAndRanges(DWARFUnit *cu, const char *&name, + const char *&mangled, DWARFRangeList &rangeList, + std::optional<int> &decl_file, + std::optional<int> &decl_line, + std::optional<int> &decl_column, + std::optional<int> &call_file, + std::optional<int> &call_line, + std::optional<int> &call_column, + DWARFExpressionList *frame_base = nullptr) const; const llvm::DWARFAbbreviationDeclaration * GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const; @@ -191,5 +194,7 @@ private: void GetAttributes(DWARFUnit *cu, DWARFAttributes &attrs, Recurse recurse, uint32_t curr_depth) const; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp index 19c6448c4e74..2cd84bc55b75 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp @@ -15,6 +15,7 @@ using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; DWARFDebugMacroHeader DWARFDebugMacroHeader::ParseHeader(const DWARFDataExtractor &debug_macro_data, diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h index cbf762458331..67d1cde8d5de 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h @@ -17,11 +17,11 @@ #include "lldb/lldb-types.h" namespace lldb_private { - class DWARFDataExtractor; +} -} // namespace lldb_private - +namespace lldb_private::plugin { +namespace dwarf { class SymbolFileDWARF; class DWARFDebugMacroHeader { @@ -33,15 +33,14 @@ public: }; static DWARFDebugMacroHeader - ParseHeader(const lldb_private::DWARFDataExtractor &debug_macro_data, + ParseHeader(const DWARFDataExtractor &debug_macro_data, lldb::offset_t *offset); bool OffsetIs64Bit() const { return m_offset_is_64_bit; } private: - static void - SkipOperandTable(const lldb_private::DWARFDataExtractor &debug_macro_data, - lldb::offset_t *offset); + static void SkipOperandTable(const DWARFDataExtractor &debug_macro_data, + lldb::offset_t *offset); uint16_t m_version = 0; bool m_offset_is_64_bit = false; @@ -50,12 +49,14 @@ private: class DWARFDebugMacroEntry { public: - static void - ReadMacroEntries(const lldb_private::DWARFDataExtractor &debug_macro_data, - const lldb_private::DWARFDataExtractor &debug_str_data, - const bool offset_is_64_bit, lldb::offset_t *sect_offset, - SymbolFileDWARF *sym_file_dwarf, - lldb_private::DebugMacrosSP &debug_macros_sp); + static void ReadMacroEntries(const DWARFDataExtractor &debug_macro_data, + const DWARFDataExtractor &debug_str_data, + const bool offset_is_64_bit, + lldb::offset_t *sect_offset, + SymbolFileDWARF *sym_file_dwarf, + DebugMacrosSP &debug_macros_sp); }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGMACRO_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index 0b5bb23a4981..fd8f4e12ff77 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -11,6 +11,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h index 2e06cd5daf6f..a04fcf59d5bf 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h @@ -12,21 +12,23 @@ #include "lldb/Core/dwarf.h" #include <map> +namespace lldb_private::plugin { +namespace dwarf { class DWARFUnit; -namespace lldb_private { class DWARFContext; -} class DWARFDebugRanges { public: DWARFDebugRanges(); - void Extract(lldb_private::DWARFContext &context); + void Extract(DWARFContext &context); DWARFRangeList FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset) const; protected: std::map<dw_offset_t, DWARFRangeList> m_range_map; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGRANGES_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp index 393de0038e65..44421c0eda3e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp @@ -7,8 +7,26 @@ //===----------------------------------------------------------------------===// #include "DWARFDeclContext.h" +#include "llvm/Support/raw_ostream.h" using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; + +/// Returns the name of `entry` if it has one, or the appropriate "anonymous +/// {namespace, class, struct, union}". +static const char *GetName(DWARFDeclContext::Entry entry) { + if (entry.name != nullptr) + return entry.name; + if (entry.tag == DW_TAG_namespace) + return "(anonymous namespace)"; + if (entry.tag == DW_TAG_class_type) + return "(anonymous class)"; + if (entry.tag == DW_TAG_structure_type) + return "(anonymous struct)"; + if (entry.tag == DW_TAG_union_type) + return "(anonymous union)"; + return "(anonymous)"; +} const char *DWARFDeclContext::GetQualifiedName() const { if (m_qualified_name.empty()) { @@ -25,26 +43,10 @@ const char *DWARFDeclContext::GetQualifiedName() const { m_qualified_name.append(m_entries[0].name); } } else { - collection::const_reverse_iterator pos; - collection::const_reverse_iterator begin = m_entries.rbegin(); - collection::const_reverse_iterator end = m_entries.rend(); - for (pos = begin; pos != end; ++pos) { - if (pos != begin) - m_qualified_name.append("::"); - if (pos->name == nullptr) { - if (pos->tag == DW_TAG_namespace) - m_qualified_name.append("(anonymous namespace)"); - else if (pos->tag == DW_TAG_class_type) - m_qualified_name.append("(anonymous class)"); - else if (pos->tag == DW_TAG_structure_type) - m_qualified_name.append("(anonymous struct)"); - else if (pos->tag == DW_TAG_union_type) - m_qualified_name.append("(anonymous union)"); - else - m_qualified_name.append("(anonymous)"); - } else - m_qualified_name.append(pos->name); - } + llvm::raw_string_ostream string_stream(m_qualified_name); + llvm::interleave( + llvm::reverse(m_entries), string_stream, + [&](auto entry) { string_stream << GetName(entry); }, "::"); } } } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h index 13e3dfb70c0c..a20a862d3402 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -16,6 +16,8 @@ #include <string> #include <vector> +namespace lldb_private::plugin { +namespace dwarf { // DWARFDeclContext // // A class that represents a declaration context all the way down to a @@ -68,8 +70,8 @@ public: // Same as GetQualifiedName, but the life time of the returned string will // be that of the LLDB session. - lldb_private::ConstString GetQualifiedNameAsConstString() const { - return lldb_private::ConstString(GetQualifiedName()); + ConstString GetQualifiedNameAsConstString() const { + return ConstString(GetQualifiedName()); } void Clear() { @@ -82,5 +84,7 @@ protected: collection m_entries; mutable std::string m_qualified_name; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp index 4e99a295ce50..9a88aed85e97 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp @@ -12,7 +12,8 @@ #include <cstring> #include <string> -namespace lldb_private { +namespace lldb_private::plugin { +namespace dwarf { const char *DW_TAG_value_to_name(uint32_t val) { static char invalid[100]; @@ -88,4 +89,5 @@ const char *DW_LNS_value_to_name(uint32_t val) { return llvmstr.data(); } -} // namespace lldb_private +} // namespace dwarf +} // namespace lldb_private::plugin diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h index 2afdbb47381a..3ed92cc203bf 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -12,7 +12,8 @@ #include "lldb/Core/dwarf.h" #include <cstdint> -namespace lldb_private { +namespace lldb_private::plugin { +namespace dwarf { typedef uint32_t DRC_class; // Holds DRC_* class bitfields @@ -30,6 +31,7 @@ const char *DW_LANG_value_to_name(uint32_t val); const char *DW_LNS_value_to_name(uint32_t val); -} // namespace lldb_private +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEFINES_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index 6ca17dcf47ff..0a7029a55c04 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -22,6 +22,7 @@ class DWARFUnit; using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; void DWARFFormValue::Clear() { m_unit = nullptr; 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 2a8843c1a0d4..445749a6aac3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -13,6 +13,8 @@ #include <cstddef> #include <optional> +namespace lldb_private::plugin { +namespace dwarf { class DWARFUnit; class SymbolFileDWARF; class DWARFDIE; @@ -51,9 +53,8 @@ public: ValueType &ValueRef() { return m_value; } void SetValue(const ValueType &val) { m_value = val; } - void Dump(lldb_private::Stream &s) const; - bool ExtractValue(const lldb_private::DWARFDataExtractor &data, - lldb::offset_t *offset_ptr); + void Dump(Stream &s) const; + bool ExtractValue(const DWARFDataExtractor &data, lldb::offset_t *offset_ptr); const uint8_t *BlockData() const; static std::optional<uint8_t> GetFixedSize(dw_form_t form, const DWARFUnit *u); @@ -68,10 +69,10 @@ public: const char *AsCString() const; dw_addr_t Address() const; bool IsValid() const { return m_form != 0; } - bool SkipValue(const lldb_private::DWARFDataExtractor &debug_info_data, + bool SkipValue(const DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr) const; static bool SkipValue(const dw_form_t form, - const lldb_private::DWARFDataExtractor &debug_info_data, + const DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr, const DWARFUnit *unit); static bool IsBlockForm(const dw_form_t form); static bool IsDataForm(const dw_form_t form); @@ -84,7 +85,9 @@ protected: // It may be different from compile unit where m_value refers to. const DWARFUnit *m_unit = nullptr; // Unit for this form dw_form_t m_form = dw_form_t(0); // Form for this value - ValueType m_value; // Contains all data for the form + ValueType m_value; // Contains all data for the form }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFFORMVALUE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp index 779b52481b85..b1c323b101ce 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp @@ -17,6 +17,7 @@ using namespace lldb_private; using namespace lldb; +using namespace lldb_private::plugin::dwarf; DWARFIndex::~DWARFIndex() = default; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h index 13fe96dae2aa..9aadeddbb217 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h @@ -17,10 +17,11 @@ #include "lldb/Core/Module.h" #include "lldb/Target/Statistics.h" +namespace lldb_private::plugin { +namespace dwarf { class DWARFDeclContext; class DWARFDIE; -namespace lldb_private { class DWARFIndex { public: DWARFIndex(Module &module) : m_module(module) {} @@ -102,6 +103,7 @@ protected: void ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const; }; -} // namespace lldb_private +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFINDEX_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp index 87af7177ca95..4f3a3f544653 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp @@ -13,6 +13,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; void DWARFTypeUnit::Dump(Stream *s) const { s->Format("{0:x16}: Type Unit: length = {1:x8}, version = {2:x4}, " diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h index 5e4d48ab285a..7b58c632c6c5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -12,11 +12,17 @@ #include "DWARFUnit.h" #include "llvm/Support/Error.h" +namespace llvm { +class DWARFAbbreviationDeclarationSet; +} // namespace llvm + +namespace lldb_private::plugin { +namespace dwarf { class DWARFTypeUnit : public DWARFUnit { public: void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) override {} - void Dump(lldb_private::Stream *s) const override; + void Dump(Stream *s) const override; uint64_t GetTypeHash() { return m_header.GetTypeHash(); } @@ -27,11 +33,13 @@ public: private: DWARFTypeUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, - const DWARFAbbreviationDeclarationSet &abbrevs, + const llvm::DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo) : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} friend class DWARFUnit; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFTYPEUNIT_H 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 749ffcb094ec..0e2f4d45543b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -13,6 +13,7 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/Object/Error.h" @@ -27,12 +28,13 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; extern int g_verbose; DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, - const DWARFAbbreviationDeclarationSet &abbrevs, + const llvm::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), @@ -200,8 +202,8 @@ DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs) rhs.m_cu = nullptr; } -DWARFUnit::ScopedExtractDIEs &DWARFUnit::ScopedExtractDIEs::operator=( - DWARFUnit::ScopedExtractDIEs &&rhs) { +DWARFUnit::ScopedExtractDIEs & +DWARFUnit::ScopedExtractDIEs::operator=(DWARFUnit::ScopedExtractDIEs &&rhs) { m_cu = rhs.m_cu; rhs.m_cu = nullptr; m_clear_dies = rhs.m_clear_dies; @@ -310,9 +312,9 @@ void DWARFUnit::ExtractDIEsRWLocked() { } if (!m_die_array.empty()) { - // The last die cannot have children (if it did, it wouldn't be the last one). - // This only makes a difference for malformed dwarf that does not have a - // terminating null die. + // The last die cannot have children (if it did, it wouldn't be the last + // one). This only makes a difference for malformed dwarf that does not have + // a terminating null die. m_die_array.back().SetHasChildren(false); if (m_first_die) { @@ -435,7 +437,8 @@ size_t DWARFUnit::GetDebugInfoSize() const { return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); } -const DWARFAbbreviationDeclarationSet *DWARFUnit::GetAbbreviations() const { +const llvm::DWARFAbbreviationDeclarationSet * +DWARFUnit::GetAbbreviations() const { return m_abbrevs; } @@ -718,7 +721,7 @@ void DWARFUnit::ParseProducerInfo() { llvm::SmallVector<llvm::StringRef, 3> matches; if (g_swiftlang_version_regex.Execute(producer, &matches)) { - m_producer_version.tryParse(matches[1]); + m_producer_version.tryParse(matches[1]); m_producer = eProducerSwift; } else if (producer.contains("clang")) { if (g_clang_version_regex.Execute(producer, &matches)) @@ -806,7 +809,7 @@ removeHostnameFromPathname(llvm::StringRef path_from_dwarf) { // check whether we have a windows path, and so the first character is a // drive-letter not a hostname. if (host.size() == 1 && llvm::isAlpha(host[0]) && - (path.startswith("\\") || path.startswith("/"))) + (path.starts_with("\\") || path.starts_with("/"))) return path_from_dwarf; return path; @@ -875,10 +878,37 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { return *m_func_aranges_up; } +llvm::Error DWARFUnitHeader::ApplyIndexEntry( + const llvm::DWARFUnitIndex::Entry *index_entry) { + // We should only be calling this function when the index entry is not set and + // we have a valid one to set it to. + assert(index_entry); + assert(!m_index_entry); + + if (m_abbr_offset) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Package unit with a non-zero abbreviation offset"); + + auto *unit_contrib = index_entry->getContribution(); + if (!unit_contrib || unit_contrib->getLength32() != m_length + 4) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Inconsistent DWARF package unit index"); + + auto *abbr_entry = index_entry->getContribution(llvm::DW_SECT_ABBREV); + if (!abbr_entry) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "DWARF package index missing abbreviation column"); + + m_abbr_offset = abbr_entry->getOffset(); + m_index_entry = index_entry; + return llvm::Error::success(); +} + llvm::Expected<DWARFUnitHeader> DWARFUnitHeader::extract(const DWARFDataExtractor &data, - DIERef::Section section, - lldb_private::DWARFContext &context, + DIERef::Section section, DWARFContext &context, lldb::offset_t *offset_ptr) { DWARFUnitHeader header; header.m_offset = *offset_ptr; @@ -903,42 +933,6 @@ DWARFUnitHeader::extract(const DWARFDataExtractor &data, header.m_type_offset = data.GetDWARFOffset(offset_ptr); } - if (context.isDwo()) { - const llvm::DWARFUnitIndex *Index; - if (header.IsTypeUnit()) { - Index = &context.GetAsLLVM().getTUIndex(); - if (*Index) - header.m_index_entry = Index->getFromHash(header.m_type_hash); - } else { - Index = &context.GetAsLLVM().getCUIndex(); - if (*Index && header.m_version >= 5 && header.m_dwo_id) - header.m_index_entry = Index->getFromHash(*header.m_dwo_id); - } - if (!header.m_index_entry) - header.m_index_entry = Index->getFromOffset(header.m_offset); - } - - if (header.m_index_entry) { - if (header.m_abbr_offset) { - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "Package unit with a non-zero abbreviation offset"); - } - auto *unit_contrib = header.m_index_entry->getContribution(); - if (!unit_contrib || unit_contrib->getLength32() != header.m_length + 4) { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Inconsistent DWARF package unit index"); - } - auto *abbr_entry = - header.m_index_entry->getContribution(llvm::DW_SECT_ABBREV); - if (!abbr_entry) { - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "DWARF package index missing abbreviation column"); - } - header.m_abbr_offset = abbr_entry->getOffset(); - } - bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1); bool version_OK = SymbolFileDWARF::SupportedVersion(header.m_version); bool addr_size_OK = (header.m_addr_size == 2) || (header.m_addr_size == 4) || @@ -968,12 +962,31 @@ DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, DIERef::Section section, lldb::offset_t *offset_ptr) { assert(debug_info.ValidOffset(*offset_ptr)); - auto expected_header = DWARFUnitHeader::extract( - debug_info, section, dwarf.GetDWARFContext(), offset_ptr); + DWARFContext &context = dwarf.GetDWARFContext(); + auto expected_header = + DWARFUnitHeader::extract(debug_info, section, context, offset_ptr); if (!expected_header) return expected_header.takeError(); - const DWARFDebugAbbrev *abbr = dwarf.DebugAbbrev(); + if (context.isDwo()) { + const llvm::DWARFUnitIndex::Entry *entry = nullptr; + const llvm::DWARFUnitIndex &index = expected_header->IsTypeUnit() + ? context.GetAsLLVM().getTUIndex() + : context.GetAsLLVM().getCUIndex(); + if (index) { + if (expected_header->IsTypeUnit()) + entry = index.getFromHash(expected_header->GetTypeHash()); + else if (auto dwo_id = expected_header->GetDWOId()) + entry = index.getFromHash(*dwo_id); + } + if (!entry) + entry = index.getFromOffset(expected_header->GetOffset()); + if (entry) + if (llvm::Error err = expected_header->ApplyIndexEntry(entry)) + return std::move(err); + } + + const llvm::DWARFDebugAbbrev *abbr = dwarf.DebugAbbrev(); if (!abbr) return llvm::make_error<llvm::object::GenericBinaryError>( "No debug_abbrev data"); @@ -985,8 +998,12 @@ DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, return llvm::make_error<llvm::object::GenericBinaryError>( "Abbreviation offset for unit is not valid"); - const DWARFAbbreviationDeclarationSet *abbrevs = - abbr->GetAbbreviationDeclarationSet(expected_header->GetAbbrOffset()); + llvm::Expected<const llvm::DWARFAbbreviationDeclarationSet *> abbrevs_or_err = + abbr->getAbbreviationDeclarationSet(expected_header->GetAbbrOffset()); + if (!abbrevs_or_err) + return abbrevs_or_err.takeError(); + + const llvm::DWARFAbbreviationDeclarationSet *abbrevs = *abbrevs_or_err; if (!abbrevs) return llvm::make_error<llvm::object::GenericBinaryError>( "No abbrev exists at the specified offset."); @@ -1071,22 +1088,20 @@ DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { return ranges; } -llvm::Expected<DWARFRangeList> -DWARFUnit::FindRnglistFromIndex(uint32_t index) { +llvm::Expected<DWARFRangeList> DWARFUnit::FindRnglistFromIndex(uint32_t index) { llvm::Expected<uint64_t> maybe_offset = GetRnglistOffset(index); if (!maybe_offset) return maybe_offset.takeError(); return FindRnglistFromOffset(*maybe_offset); } - bool DWARFUnit::HasAny(llvm::ArrayRef<dw_tag_t> tags) { ExtractUnitDIEIfNeeded(); if (m_dwo) return m_dwo->HasAny(tags); - for (const auto &die: m_die_array) { - for (const auto tag: tags) { + for (const auto &die : m_die_array) { + for (const auto tag : tags) { if (tag == die.Tag()) return true; } 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 bc55b093e894..3f528e913d8c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -13,11 +13,14 @@ #include "DWARFDebugInfoEntry.h" #include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-enumerations.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" #include "llvm/Support/RWMutex.h" #include <atomic> #include <optional> +namespace lldb_private::plugin { +namespace dwarf { class DWARFUnit; class DWARFCompileUnit; class NameToDIE; @@ -73,23 +76,25 @@ public: return m_unit_type == llvm::dwarf::DW_UT_type || m_unit_type == llvm::dwarf::DW_UT_split_type; } - uint32_t GetNextUnitOffset() const { return m_offset + m_length + 4; } + dw_offset_t GetNextUnitOffset() const { return m_offset + m_length + 4; } - static llvm::Expected<DWARFUnitHeader> - extract(const lldb_private::DWARFDataExtractor &data, DIERef::Section section, - lldb_private::DWARFContext &dwarf_context, - lldb::offset_t *offset_ptr); + llvm::Error ApplyIndexEntry(const llvm::DWARFUnitIndex::Entry *index_entry); + + static llvm::Expected<DWARFUnitHeader> extract(const DWARFDataExtractor &data, + DIERef::Section section, + DWARFContext &dwarf_context, + lldb::offset_t *offset_ptr); }; -class DWARFUnit : public lldb_private::UserID { +class DWARFUnit : public UserID { using die_iterator_range = llvm::iterator_range<DWARFDebugInfoEntry::collection::iterator>; public: static llvm::Expected<DWARFUnitSP> extract(SymbolFileDWARF &dwarf2Data, lldb::user_id_t uid, - const lldb_private::DWARFDataExtractor &debug_info, - DIERef::Section section, lldb::offset_t *offset_ptr); + const DWARFDataExtractor &debug_info, DIERef::Section section, + lldb::offset_t *offset_ptr); virtual ~DWARFUnit(); bool IsDWOUnit() { return m_is_dwo; } @@ -101,6 +106,7 @@ public: class ScopedExtractDIEs { DWARFUnit *m_cu; + public: bool m_clear_dies = false; ScopedExtractDIEs(DWARFUnit &cu); @@ -112,8 +118,8 @@ public: }; ScopedExtractDIEs ExtractDIEsScoped(); - bool Verify(lldb_private::Stream *s) const; - virtual void Dump(lldb_private::Stream *s) const = 0; + bool Verify(Stream *s) const; + virtual void Dump(Stream *s) const = 0; /// Get the data that contains the DIE information for this unit. /// /// This will return the correct bytes that contain the data for @@ -122,7 +128,7 @@ public: /// /// \return /// The correct data for the DIE information in this unit. - const lldb_private::DWARFDataExtractor &GetData() const; + const DWARFDataExtractor &GetData() const; /// Get the size in bytes of the unit header. /// @@ -151,9 +157,9 @@ public: // Size of the CU data (without initial length and without header). size_t GetDebugInfoSize() const; // Size of the CU data incl. header but without initial length. - uint32_t GetLength() const { return m_header.GetLength(); } + dw_offset_t GetLength() const { return m_header.GetLength(); } uint16_t GetVersion() const { return m_header.GetVersion(); } - const DWARFAbbreviationDeclarationSet *GetAbbreviations() const; + const llvm::DWARFAbbreviationDeclarationSet *GetAbbreviations() const; dw_offset_t GetAbbrevOffset() const; uint8_t GetAddressByteSize() const { return m_header.GetAddressByteSize(); } dw_addr_t GetAddrBase() const { return m_addr_base.value_or(0); } @@ -207,10 +213,10 @@ public: bool GetIsOptimized(); - const lldb_private::FileSpec &GetCompilationDirectory(); - const lldb_private::FileSpec &GetAbsolutePath(); - lldb_private::FileSpec GetFile(size_t file_idx); - lldb_private::FileSpec::Style GetPathStyle(); + const FileSpec &GetCompilationDirectory(); + const FileSpec &GetAbsolutePath(); + FileSpec GetFile(size_t file_idx); + FileSpec::Style GetPathStyle(); SymbolFileDWARFDwo *GetDwoSymbolFile(); @@ -224,7 +230,9 @@ public: uint8_t GetUnitType() const { return m_header.GetUnitType(); } bool IsTypeUnit() const { return m_header.IsTypeUnit(); } /// Note that this check only works for DWARF5+. - bool IsSkeletonUnit() const { return GetUnitType() == llvm::dwarf::DW_UT_skeleton; } + bool IsSkeletonUnit() const { + return GetUnitType() == llvm::dwarf::DW_UT_skeleton; + } std::optional<uint64_t> GetStringOffsetSectionItem(uint32_t index) const; @@ -256,9 +264,9 @@ public: /// Return the location table for parsing the given location list data. The /// format is chosen according to the unit type. Never returns null. std::unique_ptr<llvm::DWARFLocationTable> - GetLocationTable(const lldb_private::DataExtractor &data) const; + GetLocationTable(const DataExtractor &data) const; - lldb_private::DWARFDataExtractor GetLocationData() const; + DWARFDataExtractor GetLocationData() const; /// Returns true if any DIEs in the unit match any DW_TAG values in \a tags. /// @@ -269,7 +277,6 @@ public: /// True if any DIEs match any tag in \a tags, false otherwise. bool HasAny(llvm::ArrayRef<dw_tag_t> tags); - /// Get the fission .dwo file specific error for this compile unit. /// /// The skeleton compile unit only can have a DWO error. Any other type @@ -278,7 +285,7 @@ public: /// \returns /// A valid DWO error if there is a problem with anything in the /// locating or parsing inforamtion in the .dwo file - const lldb_private::Status &GetDwoError() const { return m_dwo_error; } + const Status &GetDwoError() const { return m_dwo_error; } /// Set the fission .dwo file specific error for this compile unit. /// @@ -286,16 +293,16 @@ public: /// .dwo file. Things like a missing .dwo file, DWO ID mismatch, and other /// .dwo errors can be stored in each compile unit so the issues can be /// communicated to the user. - void SetDwoError(const lldb_private::Status &error) { m_dwo_error = error; } + void SetDwoError(const Status &error) { m_dwo_error = error; } protected: DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, - const DWARFAbbreviationDeclarationSet &abbrevs, + const llvm::DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo); llvm::Error ExtractHeader(SymbolFileDWARF &dwarf, - const lldb_private::DWARFDataExtractor &data, + const DWARFDataExtractor &data, lldb::offset_t *offset_ptr); // Get the DWARF unit DWARF debug information entry. Parse the single DIE @@ -318,12 +325,12 @@ protected: const std::optional<llvm::DWARFDebugRnglistTable> &GetRnglistTable(); - lldb_private::DWARFDataExtractor GetRnglistData() const; + DWARFDataExtractor GetRnglistData() const; SymbolFileDWARF &m_dwarf; std::shared_ptr<DWARFUnit> m_dwo; DWARFUnitHeader m_header; - const DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; + const llvm::DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; void *m_user_data = nullptr; // The compile unit debug information entry item DWARFDebugInfoEntry::collection m_die_array; @@ -345,12 +352,12 @@ protected: DWARFProducer m_producer = eProducerInvalid; llvm::VersionTuple m_producer_version; std::optional<uint64_t> m_language_type; - lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; - std::optional<lldb_private::FileSpec> m_comp_dir; - std::optional<lldb_private::FileSpec> m_file_spec; - std::optional<dw_addr_t> m_addr_base; ///< Value of DW_AT_addr_base. - dw_addr_t m_loclists_base = 0; ///< Value of DW_AT_loclists_base. - dw_addr_t m_ranges_base = 0; ///< Value of DW_AT_rnglists_base. + LazyBool m_is_optimized = eLazyBoolCalculate; + std::optional<FileSpec> m_comp_dir; + std::optional<FileSpec> m_file_spec; + std::optional<dw_addr_t> m_addr_base; ///< Value of DW_AT_addr_base. + dw_addr_t m_loclists_base = 0; ///< Value of DW_AT_loclists_base. + dw_addr_t m_ranges_base = 0; ///< Value of DW_AT_rnglists_base. std::optional<uint64_t> m_gnu_addr_base; std::optional<uint64_t> m_gnu_ranges_base; @@ -371,7 +378,7 @@ protected: /// If we get an error when trying to load a .dwo file, save that error here. /// Errors include .dwo/.dwp file not found, or the .dwp/.dwp file was found /// but DWO ID doesn't match, etc. - lldb_private::Status m_dwo_error; + Status m_dwo_error; private: void ParseProducerInfo(); @@ -387,5 +394,7 @@ private: DWARFUnit(const DWARFUnit &) = delete; const DWARFUnit &operator=(const DWARFUnit &) = delete; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index af2d6c554140..7c253553d57b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -18,6 +18,7 @@ using namespace lldb_private; using namespace lldb; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, @@ -36,19 +37,29 @@ llvm::DenseSet<dw_offset_t> DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { llvm::DenseSet<dw_offset_t> result; for (const DebugNames::NameIndex &ni : debug_names) { - for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu) + const uint32_t num_cus = ni.getCUCount(); + for (uint32_t cu = 0; cu < num_cus; ++cu) result.insert(ni.getCUOffset(cu)); + const uint32_t num_tus = ni.getLocalTUCount(); + for (uint32_t tu = 0; tu < num_tus; ++tu) + result.insert(ni.getLocalTUOffset(tu)); } return result; } std::optional<DIERef> DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) { - std::optional<uint64_t> cu_offset = entry.getCUOffset(); - if (!cu_offset) - return std::nullopt; + // Look for a DWARF unit offset (CU offset or local TU offset) as they are + // both offsets into the .debug_info section. + std::optional<uint64_t> unit_offset = entry.getCUOffset(); + if (!unit_offset) { + unit_offset = entry.getLocalTUOffset(); + if (!unit_offset) + return std::nullopt; + } - DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset); + DWARFUnit *cu = + m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset); if (!cu) return std::nullopt; @@ -128,8 +139,19 @@ void DebugNamesDWARFIndex::GetGlobalVariables( DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) { uint64_t cu_offset = cu.GetOffset(); bool found_entry_for_cu = false; - for (const DebugNames::NameIndex &ni: *m_debug_names_up) { - for (DebugNames::NameTableEntry nte: ni) { + for (const DebugNames::NameIndex &ni : *m_debug_names_up) { + // Check if this name index contains an entry for the given CU. + bool cu_matches = false; + for (uint32_t i = 0; i < ni.getCUCount(); ++i) { + if (ni.getCUOffset(i) == cu_offset) { + cu_matches = true; + break; + } + } + if (!cu_matches) + continue; + + for (DebugNames::NameTableEntry nte : ni) { uint64_t entry_offset = nte.getEntryOffset(); llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { @@ -227,7 +249,7 @@ void DebugNamesDWARFIndex::GetNamespaces( ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name.GetStringRef())) { - dwarf::Tag entry_tag = entry.tag(); + lldb_private::dwarf::Tag entry_tag = entry.tag(); if (entry_tag == DW_TAG_namespace || entry_tag == DW_TAG_imported_declaration) { if (!ProcessEntry(entry, callback)) diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index abbd700f1603..7ce630a56137 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -17,7 +17,8 @@ #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include <optional> -namespace lldb_private { +namespace lldb_private::plugin { +namespace dwarf { class DebugNamesDWARFIndex : public DWARFIndex { public: static llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> @@ -89,6 +90,7 @@ private: static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names); }; -} // namespace lldb_private +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DEBUGNAMESDWARFINDEX_H 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 57b962ff60df..16ff5f7d4842 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -28,6 +28,7 @@ using namespace lldb_private; using namespace lldb; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; void ManualDWARFIndex::Index() { if (m_indexed) @@ -654,7 +655,7 @@ void ManualDWARFIndex::IndexSet::Encode(DataEncoder &encoder) const { // Now that all strings have been gathered, we will emit the string table. strtab.Encode(encoder); - // Followed the the symbol table data. + // Followed by the symbol table data. encoder.AppendData(index_encoder.GetData()); } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h index d95cf501face..0126e587e52d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -13,10 +13,11 @@ #include "Plugins/SymbolFile/DWARF/NameToDIE.h" #include "llvm/ADT/DenseSet.h" +namespace lldb_private::plugin { +namespace dwarf { class DWARFDebugInfo; class SymbolFileDWARFDwo; -namespace lldb_private { class ManualDWARFIndex : public DWARFIndex { public: ManualDWARFIndex(Module &module, SymbolFileDWARF &dwarf, @@ -173,6 +174,7 @@ private: IndexSet m_set; bool m_indexed = false; }; -} // namespace lldb_private +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp index 89e628f5eaf1..44d90648700c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp @@ -20,6 +20,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; void NameToDIE::Finalize() { m_map.Sort(std::less<DIERef>()); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h index 61df1a628ab5..90eac1fa3733 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h @@ -16,6 +16,8 @@ #include "lldb/Core/dwarf.h" #include "lldb/lldb-defines.h" +namespace lldb_private::plugin { +namespace dwarf { class DWARFUnit; class NameToDIE { @@ -24,18 +26,18 @@ public: ~NameToDIE() = default; - void Dump(lldb_private::Stream *s); + void Dump(Stream *s); - void Insert(lldb_private::ConstString name, const DIERef &die_ref); + void Insert(ConstString name, const DIERef &die_ref); void Append(const NameToDIE &other); void Finalize(); - bool Find(lldb_private::ConstString name, + bool Find(ConstString name, llvm::function_ref<bool(DIERef ref)> callback) const; - bool Find(const lldb_private::RegularExpression ®ex, + bool Find(const RegularExpression ®ex, llvm::function_ref<bool(DIERef ref)> callback) const; /// \a unit must be the skeleton unit if possible, not GetNonSkeletonUnit(). @@ -44,8 +46,7 @@ public: llvm::function_ref<bool(DIERef ref)> callback) const; void - ForEach(std::function<bool(lldb_private::ConstString name, - const DIERef &die_ref)> const + ForEach(std::function<bool(ConstString name, const DIERef &die_ref)> const &callback) const; /// Decode a serialized version of this object from data. @@ -61,9 +62,8 @@ public: /// All strings in cache files are put into string tables for efficiency /// and cache file size reduction. Strings are stored as uint32_t string /// table offsets in the cache data. - bool Decode(const lldb_private::DataExtractor &data, - lldb::offset_t *offset_ptr, - const lldb_private::StringTableReader &strtab); + bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr, + const StringTableReader &strtab); /// Encode this object into a data encoder object. /// @@ -76,8 +76,7 @@ public: /// All strings in cache files are put into string tables for efficiency /// and cache file size reduction. Strings are stored as uint32_t string /// table offsets in the cache data. - void Encode(lldb_private::DataEncoder &encoder, - lldb_private::ConstStringTable &strtab) const; + void Encode(DataEncoder &encoder, ConstStringTable &strtab) const; /// Used for unit testing the encoding and decoding. bool operator==(const NameToDIE &rhs) const; @@ -87,7 +86,9 @@ public: void Clear() { m_map.Clear(); } protected: - lldb_private::UniqueCStringMap<DIERef> m_map; + UniqueCStringMap<DIERef> m_map; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_NAMETODIE_H 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 6e5482dba9d2..505ea29ca4d4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Format.h" #include "llvm/Support/Threading.h" #include "lldb/Core/Module.h" @@ -18,13 +19,13 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Scalar.h" #include "lldb/Utility/StreamString.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/Timer.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" @@ -45,7 +46,6 @@ #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/LineTable.h" -#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeMap.h" @@ -59,7 +59,6 @@ #include "DWARFASTParser.h" #include "DWARFASTParserClang.h" #include "DWARFCompileUnit.h" -#include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "DWARFDebugMacro.h" @@ -75,6 +74,7 @@ #include "SymbolFileDWARFDwo.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" @@ -98,6 +98,7 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; LLDB_PLUGIN_DEFINE(SymbolFileDWARF) @@ -115,8 +116,8 @@ enum { class PluginProperties : public Properties { public: - static ConstString GetSettingName() { - return ConstString(SymbolFileDWARF::GetPluginNameStatic()); + static llvm::StringRef GetSettingName() { + return SymbolFileDWARF::GetPluginNameStatic(); } PluginProperties() { @@ -131,15 +132,19 @@ public: } // namespace +bool IsStructOrClassTag(llvm::dwarf::Tag Tag) { + return Tag == llvm::dwarf::Tag::DW_TAG_class_type || + Tag == llvm::dwarf::Tag::DW_TAG_structure_type; +} + static PluginProperties &GetGlobalPluginProperties() { static PluginProperties g_settings; return g_settings; } static const llvm::DWARFDebugLine::LineTable * -ParseLLVMLineTable(lldb_private::DWARFContext &context, - llvm::DWARFDebugLine &line, dw_offset_t line_offset, - dw_offset_t unit_offset) { +ParseLLVMLineTable(DWARFContext &context, llvm::DWARFDebugLine &line, + dw_offset_t line_offset, dw_offset_t unit_offset) { Log *log = GetLog(DWARFLog::DebugInfo); llvm::DWARFDataExtractor data = context.getOrLoadLineData().GetAsLLVMDWARF(); @@ -160,7 +165,7 @@ ParseLLVMLineTable(lldb_private::DWARFContext &context, return *line_table; } -static bool ParseLLVMLineTablePrologue(lldb_private::DWARFContext &context, +static bool ParseLLVMLineTablePrologue(DWARFContext &context, llvm::DWARFDebugLine::Prologue &prologue, dw_offset_t line_offset, dw_offset_t unit_offset) { @@ -210,17 +215,24 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, FileSpec::Style style, llvm::StringRef compile_dir = {}) { FileSpecList support_files; - size_t first_file = 0; - if (prologue.getVersion() <= 4) { - // File index 0 is not valid before DWARF v5. Add a dummy entry to ensure - // support file list indices match those we get from the debug info and line - // tables. + + // Handle the case where there are no files first to avoid having to special + // case this later. + if (prologue.FileNames.empty()) + return support_files; + + // Before DWARF v5, the line table indexes were one based. + const bool is_one_based = prologue.getVersion() < 5; + const size_t file_names = prologue.FileNames.size(); + const size_t first_file_idx = is_one_based ? 1 : 0; + const size_t last_file_idx = is_one_based ? file_names : file_names - 1; + + // Add a dummy entry to ensure the support file list indices match those we + // get from the debug info and line tables. + if (is_one_based) support_files.Append(FileSpec()); - first_file = 1; - } - const size_t number_of_files = prologue.FileNames.size(); - for (size_t idx = first_file; idx <= number_of_files; ++idx) { + for (size_t idx = first_file_idx; idx <= last_file_idx; ++idx) { std::string remapped_file; if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) { if (auto remapped = module->RemapSourceFile(llvm::StringRef(*file_path))) @@ -229,8 +241,15 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, remapped_file = std::move(*file_path); } + Checksum checksum; + if (prologue.ContentTypes.HasMD5) { + const llvm::DWARFDebugLine::FileNameEntry &file_name_entry = + prologue.getFileNameEntry(idx); + checksum = file_name_entry.Checksum; + } + // Unconditionally add an entry, so the indices match up. - support_files.EmplaceBack(remapped_file, style); + support_files.EmplaceBack(remapped_file, style, checksum); } return support_files; @@ -512,6 +531,21 @@ bool SymbolFileDWARF::SupportedVersion(uint16_t version) { return version >= 2 && version <= 5; } +static std::set<dw_form_t> +GetUnsupportedForms(llvm::DWARFDebugAbbrev *debug_abbrev) { + if (!debug_abbrev) + return {}; + + std::set<dw_form_t> unsupported_forms; + for (const auto &[_, decl_set] : *debug_abbrev) + for (const auto &decl : decl_set) + for (const auto &attr : decl.attributes()) + if (!DWARFFormValue::FormIsSupported(attr.Form)) + unsupported_forms.insert(attr.Form); + + return unsupported_forms; +} + uint32_t SymbolFileDWARF::CalculateAbilities() { uint32_t abilities = 0; if (m_objfile_sp != nullptr) { @@ -540,20 +574,16 @@ uint32_t SymbolFileDWARF::CalculateAbilities() { if (section) debug_abbrev_file_size = section->GetFileSize(); - DWARFDebugAbbrev *abbrev = DebugAbbrev(); - if (abbrev) { - std::set<dw_form_t> invalid_forms; - abbrev->GetUnsupportedForms(invalid_forms); - if (!invalid_forms.empty()) { - StreamString error; - error.Printf("unsupported DW_FORM value%s:", - invalid_forms.size() > 1 ? "s" : ""); - for (auto form : invalid_forms) - error.Printf(" %#x", form); - m_objfile_sp->GetModule()->ReportWarning( - "{0}", error.GetString().str().c_str()); - return 0; - } + llvm::DWARFDebugAbbrev *abbrev = DebugAbbrev(); + std::set<dw_form_t> unsupported_forms = GetUnsupportedForms(abbrev); + if (!unsupported_forms.empty()) { + StreamString error; + error.Printf("unsupported DW_FORM value%s:", + unsupported_forms.size() > 1 ? "s" : ""); + for (auto form : unsupported_forms) + error.Printf(" %#x", form); + m_objfile_sp->GetModule()->ReportWarning("{0}", error.GetString()); + return 0; } section = @@ -615,7 +645,7 @@ void SymbolFileDWARF::LoadSectionData(lldb::SectionType sect_type, m_objfile_sp->ReadSectionData(section_sp.get(), data); } -DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { +llvm::DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (m_abbr) return m_abbr.get(); @@ -623,8 +653,9 @@ DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (debug_abbrev_data.GetByteSize() == 0) return nullptr; - auto abbr = std::make_unique<DWARFDebugAbbrev>(); - llvm::Error error = abbr->parse(debug_abbrev_data); + auto abbr = + std::make_unique<llvm::DWARFDebugAbbrev>(debug_abbrev_data.GetAsLLVM()); + llvm::Error error = abbr->parse(); if (error) { Log *log = GetLog(DWARFLog::DebugInfo); LLDB_LOG_ERROR(log, std::move(error), @@ -1441,6 +1472,17 @@ SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) { return CompilerDeclContext(); } +std::vector<CompilerContext> +SymbolFileDWARF::GetCompilerContextForUID(lldb::user_id_t type_uid) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + // Anytime we have a lldb::user_id_t, we must get the DIE by calling + // SymbolFileDWARF::GetDIE(). See comments inside the + // SymbolFileDWARF::GetDIE() for details. + if (DWARFDIE die = GetDIE(type_uid)) + return die.GetDeclContext(); + return {}; +} + Type *SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); // Anytime we have a lldb::user_id_t, we must get the DIE by calling @@ -1508,11 +1550,11 @@ Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die, // This function is used when SymbolFileDWARFDebugMap owns a bunch of // SymbolFileDWARF objects to detect if this DWARF file is the one that can // resolve a compiler_type. -bool SymbolFileDWARF::HasForwardDeclForClangType( +bool SymbolFileDWARF::HasForwardDeclForCompilerType( const CompilerType &compiler_type) { CompilerType compiler_type_no_qualifiers = ClangUtil::RemoveFastQualifiers(compiler_type); - if (GetForwardDeclClangTypeToDie().count( + if (GetForwardDeclCompilerTypeToDIE().count( compiler_type_no_qualifiers.GetOpaqueQualType())) { return true; } @@ -1540,9 +1582,9 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { // We have a struct/union/class/enum that needs to be fully resolved. CompilerType compiler_type_no_qualifiers = ClangUtil::RemoveFastQualifiers(compiler_type); - auto die_it = GetForwardDeclClangTypeToDie().find( + auto die_it = GetForwardDeclCompilerTypeToDIE().find( compiler_type_no_qualifiers.GetOpaqueQualType()); - if (die_it == GetForwardDeclClangTypeToDie().end()) { + if (die_it == GetForwardDeclCompilerTypeToDIE().end()) { // We have already resolved this type... return true; } @@ -1553,7 +1595,7 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { // declaration map in case anyone child members or other types require this // type to get resolved. The type will get resolved when all of the calls // to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition are done. - GetForwardDeclClangTypeToDie().erase(die_it); + GetForwardDeclCompilerTypeToDIE().erase(die_it); Type *type = GetDIEToType().lookup(dwarf_die.GetDIE()); @@ -1729,38 +1771,129 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( if (std::shared_ptr<SymbolFileDWARFDwo> dwp_sp = GetDwpSymbolFile()) return dwp_sp; - const char *comp_dir = nullptr; FileSpec dwo_file(dwo_name); FileSystem::Instance().Resolve(dwo_file); - if (dwo_file.IsRelative()) { - comp_dir = cu_die.GetAttributeValueAsString(dwarf_cu, DW_AT_comp_dir, - nullptr); - if (!comp_dir) { - unit.SetDwoError(Status::createWithFormat( - "unable to locate relative .dwo debug file \"{0}\" for " - "skeleton DIE {1:x16} without valid DW_AT_comp_dir " - "attribute", - dwo_name, cu_die.GetOffset())); - return nullptr; + bool found = false; + + const FileSpecList &debug_file_search_paths = + Target::GetDefaultDebugFileSearchPaths(); + size_t num_search_paths = debug_file_search_paths.GetSize(); + + // It's relative, e.g. "foo.dwo", but we just to happen to be right next to + // it. Or it's absolute. + found = FileSystem::Instance().Exists(dwo_file); + + const char *comp_dir = + cu_die.GetAttributeValueAsString(dwarf_cu, DW_AT_comp_dir, nullptr); + if (!found) { + // It could be a relative path that also uses DW_AT_COMP_DIR. + if (comp_dir) { + dwo_file.SetFile(comp_dir, FileSpec::Style::native); + if (!dwo_file.IsRelative()) { + FileSystem::Instance().Resolve(dwo_file); + dwo_file.AppendPathComponent(dwo_name); + found = FileSystem::Instance().Exists(dwo_file); + } else { + FileSpecList dwo_paths; + + // if DW_AT_comp_dir is relative, it should be relative to the location + // of the executable, not to the location from which the debugger was + // launched. + FileSpec relative_to_binary = dwo_file; + relative_to_binary.PrependPathComponent( + m_objfile_sp->GetFileSpec().GetDirectory().GetStringRef()); + FileSystem::Instance().Resolve(relative_to_binary); + relative_to_binary.AppendPathComponent(dwo_name); + dwo_paths.Append(relative_to_binary); + + // Or it's relative to one of the user specified debug directories. + for (size_t idx = 0; idx < num_search_paths; ++idx) { + FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); + dirspec.AppendPathComponent(comp_dir); + FileSystem::Instance().Resolve(dirspec); + if (!FileSystem::Instance().IsDirectory(dirspec)) + continue; + + dirspec.AppendPathComponent(dwo_name); + dwo_paths.Append(dirspec); + } + + size_t num_possible = dwo_paths.GetSize(); + for (size_t idx = 0; idx < num_possible && !found; ++idx) { + FileSpec dwo_spec = dwo_paths.GetFileSpecAtIndex(idx); + if (FileSystem::Instance().Exists(dwo_spec)) { + dwo_file = dwo_spec; + found = true; + } + } + } + } else { + Log *log = GetLog(LLDBLog::Symbols); + LLDB_LOGF(log, + "unable to locate relative .dwo debug file \"%s\" for " + "skeleton DIE 0x%016" PRIx64 " without valid DW_AT_comp_dir " + "attribute", + dwo_name, cu_die.GetOffset()); + } + } + + if (!found) { + // Try adding the DW_AT_dwo_name ( e.g. "c/d/main-main.dwo"), and just the + // filename ("main-main.dwo") to binary dir and search paths. + FileSpecList dwo_paths; + FileSpec dwo_name_spec(dwo_name); + llvm::StringRef filename_only = dwo_name_spec.GetFilename(); + + FileSpec binary_directory( + m_objfile_sp->GetFileSpec().GetDirectory().GetStringRef()); + FileSystem::Instance().Resolve(binary_directory); + + if (dwo_name_spec.IsRelative()) { + FileSpec dwo_name_binary_directory(binary_directory); + dwo_name_binary_directory.AppendPathComponent(dwo_name); + dwo_paths.Append(dwo_name_binary_directory); + } + + FileSpec filename_binary_directory(binary_directory); + filename_binary_directory.AppendPathComponent(filename_only); + dwo_paths.Append(filename_binary_directory); + + for (size_t idx = 0; idx < num_search_paths; ++idx) { + FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); + FileSystem::Instance().Resolve(dirspec); + if (!FileSystem::Instance().IsDirectory(dirspec)) + continue; + + FileSpec dwo_name_dirspec(dirspec); + dwo_name_dirspec.AppendPathComponent(dwo_name); + dwo_paths.Append(dwo_name_dirspec); + + FileSpec filename_dirspec(dirspec); + filename_dirspec.AppendPathComponent(filename_only); + dwo_paths.Append(filename_dirspec); } - dwo_file.SetFile(comp_dir, FileSpec::Style::native); - if (dwo_file.IsRelative()) { - // if DW_AT_comp_dir is relative, it should be relative to the location - // of the executable, not to the location from which the debugger was - // launched. - dwo_file.PrependPathComponent( - m_objfile_sp->GetFileSpec().GetDirectory().GetStringRef()); + size_t num_possible = dwo_paths.GetSize(); + for (size_t idx = 0; idx < num_possible && !found; ++idx) { + FileSpec dwo_spec = dwo_paths.GetFileSpecAtIndex(idx); + if (FileSystem::Instance().Exists(dwo_spec)) { + dwo_file = dwo_spec; + found = true; + } } - FileSystem::Instance().Resolve(dwo_file); - dwo_file.AppendPathComponent(dwo_name); } - if (!FileSystem::Instance().Exists(dwo_file)) { + if (!found) { + FileSpec error_dwo_path(dwo_name); + FileSystem::Instance().Resolve(error_dwo_path); + if (error_dwo_path.IsRelative() && comp_dir != nullptr) { + error_dwo_path.PrependPathComponent(comp_dir); + FileSystem::Instance().Resolve(error_dwo_path); + } unit.SetDwoError(Status::createWithFormat( "unable to locate .dwo debug file \"{0}\" for skeleton DIE " "{1:x16}", - dwo_file.GetPath().c_str(), cu_die.GetOffset())); + error_dwo_path.GetPath().c_str(), cu_die.GetOffset())); if (m_dwo_warning_issued.test_and_set(std::memory_order_relaxed) == false) { GetObjectFile()->GetModule()->ReportWarning( @@ -1849,7 +1982,7 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { // (corresponding to .dwo) so we simply skip it. if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" && llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath()) - .endswith(dwo_module_spec.GetFileSpec().GetPath())) { + .ends_with(dwo_module_spec.GetFileSpec().GetPath())) { continue; } @@ -2331,7 +2464,7 @@ bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx, // ...But if we are only checking root decl contexts, confirm that the // 'die' is a top-level context. if (only_root_namespaces) - return die.GetParent().Tag() == dwarf::DW_TAG_compile_unit; + return die.GetParent().Tag() == llvm::dwarf::DW_TAG_compile_unit; return true; } @@ -2463,178 +2596,157 @@ void SymbolFileDWARF::GetMangledNamesForFunction( } } -void SymbolFileDWARF::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - TypeMap &types) { - std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - // Make sure we haven't already searched this SymbolFile before. - if (!searched_symbol_files.insert(this).second) - return; - - Log *log = GetLog(DWARFLog::Lookups); +/// Split a name up into a basename and template parameters. +static bool SplitTemplateParams(llvm::StringRef fullname, + llvm::StringRef &basename, + llvm::StringRef &template_params) { + auto it = fullname.find('<'); + if (it == llvm::StringRef::npos) { + basename = fullname; + template_params = llvm::StringRef(); + return false; + } + basename = fullname.slice(0, it); + template_params = fullname.slice(it, fullname.size()); + return true; +} - if (log) { - if (parent_decl_ctx) - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindTypes (sc, name=\"{0}\", parent_decl_ctx = " - "{1:p} (\"{2}\"), max_matches={3}, type_list)", - name.GetCString(), static_cast<const void *>(&parent_decl_ctx), - parent_decl_ctx.GetName().AsCString("<NULL>"), max_matches); - else - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindTypes (sc, name=\"{0}\", parent_decl_ctx = " - "NULL, max_matches={1}, type_list)", - name.GetCString(), max_matches); +static bool UpdateCompilerContextForSimpleTemplateNames(TypeQuery &match) { + // We need to find any names in the context that have template parameters + // and strip them so the context can be matched when -gsimple-template-names + // is being used. Returns true if any of the context items were updated. + bool any_context_updated = false; + for (auto &context : match.GetContextRef()) { + llvm::StringRef basename, params; + if (SplitTemplateParams(context.name.GetStringRef(), basename, params)) { + context.name = ConstString(basename); + any_context_updated = true; + } } + return any_context_updated; +} +void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) { - if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) + // Make sure we haven't already searched this SymbolFile before. + if (results.AlreadySearched(this)) return; - // Unlike FindFunctions(), FindTypes() following cannot produce false - // positives. - - const llvm::StringRef name_ref = name.GetStringRef(); - auto name_bracket_index = name_ref.find('<'); - m_index->GetTypes(name, [&](DWARFDIE die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - return true; // The containing decl contexts don't match + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - Type *matching_type = ResolveType(die, true, true); - if (!matching_type) - return true; + bool have_index_match = false; + m_index->GetTypes(query.GetTypeBasename(), [&](DWARFDIE die) { + // Check the language, but only if we have a language filter. + if (query.HasLanguage()) { + if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU()))) + return true; // Keep iterating over index types, language mismatch. + } - // With -gsimple-template-names, a templated type's DW_AT_name will not - // contain the template parameters. Make sure that if the original query - // didn't contain a '<', we filter out entries with template parameters. - if (name_bracket_index == llvm::StringRef::npos && - matching_type->IsTemplateType()) - return true; + // Check the context matches + std::vector<lldb_private::CompilerContext> die_context; + if (query.GetModuleSearch()) + die_context = die.GetDeclContext(); + else + die_context = die.GetTypeLookupContext(); + assert(!die_context.empty()); + if (!query.ContextMatches(die_context)) + return true; // Keep iterating over index types, context mismatch. - // We found a type pointer, now find the shared pointer form our type - // list - types.InsertUnique(matching_type->shared_from_this()); - return types.GetSize() < max_matches; + // Try to resolve the type. + if (Type *matching_type = ResolveType(die, true, true)) { + if (matching_type->IsTemplateType()) { + // We have to watch out for case where we lookup a type by basename and + // it matches a template with simple template names. Like looking up + // "Foo" and if we have simple template names then we will match + // "Foo<int>" and "Foo<double>" because all the DWARF has is "Foo" in + // the accelerator tables. The main case we see this in is when the + // expression parser is trying to parse "Foo<int>" and it will first do + // a lookup on just "Foo". We verify the type basename matches before + // inserting the type in the results. + auto CompilerTypeBasename = + matching_type->GetForwardCompilerType().GetTypeName(true); + if (CompilerTypeBasename != query.GetTypeBasename()) + return true; // Keep iterating over index types, basename mismatch. + } + have_index_match = true; + results.InsertUnique(matching_type->shared_from_this()); + } + return !results.Done(query); // Keep iterating if we aren't done. }); + if (results.Done(query)) + return; + // With -gsimple-template-names, a templated type's DW_AT_name will not // contain the template parameters. Try again stripping '<' and anything // after, filtering out entries with template parameters that don't match. - if (types.GetSize() < max_matches) { - if (name_bracket_index != llvm::StringRef::npos) { - const llvm::StringRef name_no_template_params = - name_ref.slice(0, name_bracket_index); - const llvm::StringRef template_params = - name_ref.slice(name_bracket_index, name_ref.size()); - m_index->GetTypes(ConstString(name_no_template_params), [&](DWARFDIE die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - return true; // The containing decl contexts don't match - - const llvm::StringRef base_name = GetTypeForDIE(die)->GetBaseName().AsCString(); - auto it = base_name.find('<'); - // If the candidate qualified name doesn't have '<', it doesn't have - // template params to compare. - if (it == llvm::StringRef::npos) - return true; - - // Filter out non-matching instantiations by comparing template params. - const llvm::StringRef base_name_template_params = - base_name.slice(it, base_name.size()); - - if (template_params != base_name_template_params) - return true; - - Type *matching_type = ResolveType(die, true, true); - if (!matching_type) - return true; + if (!have_index_match) { + // Create a type matcher with a compiler context that is tuned for + // -gsimple-template-names. We will use this for the index lookup and the + // context matching, but will use the original "match" to insert matches + // into if things match. The "match_simple" has a compiler context with + // all template parameters removed to allow the names and context to match. + // The UpdateCompilerContextForSimpleTemplateNames(...) will return true if + // it trims any context items down by removing template parameter names. + TypeQuery query_simple(query); + if (UpdateCompilerContextForSimpleTemplateNames(query_simple)) { + + // Copy our match's context and update the basename we are looking for + // so we can use this only to compare the context correctly. + m_index->GetTypes(query_simple.GetTypeBasename(), [&](DWARFDIE die) { + // Check the language, but only if we have a language filter. + if (query.HasLanguage()) { + if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU()))) + return true; // Keep iterating over index types, language mismatch. + } - // We found a type pointer, now find the shared pointer form our type - // list. - types.InsertUnique(matching_type->shared_from_this()); - return types.GetSize() < max_matches; + // Check the context matches + std::vector<lldb_private::CompilerContext> die_context; + if (query.GetModuleSearch()) + die_context = die.GetDeclContext(); + else + die_context = die.GetTypeLookupContext(); + assert(!die_context.empty()); + if (!query_simple.ContextMatches(die_context)) + return true; // Keep iterating over index types, context mismatch. + + // Try to resolve the type. + if (Type *matching_type = ResolveType(die, true, true)) { + ConstString name = matching_type->GetQualifiedName(); + // We have found a type that still might not match due to template + // parameters. If we create a new TypeQuery that uses the new type's + // fully qualified name, we can find out if this type matches at all + // context levels. We can't use just the "match_simple" context + // because all template parameters were stripped off. The fully + // qualified name of the type will have the template parameters and + // will allow us to make sure it matches correctly. + TypeQuery die_query(name.GetStringRef(), + TypeQueryOptions::e_exact_match); + if (!query.ContextMatches(die_query.GetContextRef())) + return true; // Keep iterating over index types, context mismatch. + + results.InsertUnique(matching_type->shared_from_this()); + } + return !results.Done(query); // Keep iterating if we aren't done. }); + if (results.Done(query)) + return; } } // Next search through the reachable Clang modules. This only applies for // DWARF objects compiled with -gmodules that haven't been processed by // dsymutil. - if (types.GetSize() < max_matches) { - UpdateExternalModuleListIfNeeded(); - - for (const auto &pair : m_external_type_modules) - if (ModuleSP external_module_sp = pair.second) - if (SymbolFile *sym_file = external_module_sp->GetSymbolFile()) - sym_file->FindTypes(name, parent_decl_ctx, max_matches, - searched_symbol_files, types); - } + UpdateExternalModuleListIfNeeded(); - if (log && types.GetSize()) { - if (parent_decl_ctx) { - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindTypes (sc, name=\"{0}\", parent_decl_ctx " - "= {1:p} (\"{2}\"), max_matches={3}, type_list) => {4}", - name.GetCString(), static_cast<const void *>(&parent_decl_ctx), - parent_decl_ctx.GetName().AsCString("<NULL>"), max_matches, - types.GetSize()); - } else { - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindTypes (sc, name=\"{0}\", parent_decl_ctx " - "= NULL, max_matches={1}, type_list) => {2}", - name.GetCString(), max_matches, types.GetSize()); + for (const auto &pair : m_external_type_modules) { + if (ModuleSP external_module_sp = pair.second) { + external_module_sp->FindTypes(query, results); + if (results.Done(query)) + return; } } } -void SymbolFileDWARF::FindTypes( - llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) { - // Make sure we haven't already searched this SymbolFile before. - if (!searched_symbol_files.insert(this).second) - return; - - std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - if (pattern.empty()) - return; - - ConstString name = pattern.back().name; - - if (!name) - return; - - m_index->GetTypes(name, [&](DWARFDIE die) { - if (!languages[GetLanguageFamily(*die.GetCU())]) - return true; - - llvm::SmallVector<CompilerContext, 4> die_context; - die.GetDeclContext(die_context); - if (!contextMatches(die_context, pattern)) - return true; - - if (Type *matching_type = ResolveType(die, true, true)) { - // We found a type pointer, now find the shared pointer form our type - // list. - types.InsertUnique(matching_type->shared_from_this()); - } - return true; - }); - - // Next search through the reachable Clang modules. This only applies for - // DWARF objects compiled with -gmodules that haven't been processed by - // dsymutil. - UpdateExternalModuleListIfNeeded(); - - for (const auto &pair : m_external_type_modules) - if (ModuleSP external_module_sp = pair.second) - external_module_sp->FindTypes(pattern, languages, searched_symbol_files, - types); -} - CompilerDeclContext SymbolFileDWARF::FindNamespace(ConstString name, const CompilerDeclContext &parent_decl_ctx, @@ -2820,29 +2932,18 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( m_index->GetCompleteObjCClass( type_name, must_be_implementation, [&](DWARFDIE type_die) { - bool try_resolving_type = false; - // Don't try and resolve the DIE we are looking for with the DIE // itself! - if (type_die != die) { - switch (type_die.Tag()) { - case DW_TAG_class_type: - case DW_TAG_structure_type: - try_resolving_type = true; - break; - default: - break; - } - } - if (!try_resolving_type) + if (type_die == die || !IsStructOrClassTag(type_die.Tag())) return true; if (must_be_implementation && - type_die.Supports_DW_AT_APPLE_objc_complete_type()) - try_resolving_type = type_die.GetAttributeValueAsUnsigned( + type_die.Supports_DW_AT_APPLE_objc_complete_type()) { + const bool try_resolving_type = type_die.GetAttributeValueAsUnsigned( DW_AT_APPLE_objc_complete_type, 0); - if (!try_resolving_type) - return true; + if (!try_resolving_type) + return true; + } Type *resolved_type = ResolveType(type_die, false, true); if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED) @@ -2993,43 +3094,20 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) { template_params = dwarf_ast->GetDIEClassTemplateParams(die); } - m_index->GetTypes(GetDWARFDeclContext(die), [&](DWARFDIE type_die) { + const DWARFDeclContext die_dwarf_decl_ctx = GetDWARFDeclContext(die); + m_index->GetTypes(die_dwarf_decl_ctx, [&](DWARFDIE type_die) { // Make sure type_die's language matches the type system we are // looking for. We don't want to find a "Foo" type from Java if we // are looking for a "Foo" type for C, C++, ObjC, or ObjC++. if (type_system && !type_system->SupportsLanguage(GetLanguage(*type_die.GetCU()))) return true; - bool try_resolving_type = false; - // Don't try and resolve the DIE we are looking for with the DIE - // itself! const dw_tag_t type_tag = type_die.Tag(); - // Make sure the tags match - if (type_tag == tag) { - // The tags match, lets try resolving this type - try_resolving_type = true; - } else { - // The tags don't match, but we need to watch our for a forward - // declaration for a struct and ("struct foo") ends up being a - // class ("class foo { ... };") or vice versa. - switch (type_tag) { - case DW_TAG_class_type: - // We had a "class foo", see if we ended up with a "struct foo - // { ... };" - try_resolving_type = (tag == DW_TAG_structure_type); - break; - case DW_TAG_structure_type: - // We had a "struct foo", see if we ended up with a "class foo - // { ... };" - try_resolving_type = (tag == DW_TAG_class_type); - break; - default: - // Tags don't match, don't event try to resolve using this type - // whose name matches.... - break; - } - } + // Resolve the type if both have the same tag or {class, struct} tags. + const bool try_resolving_type = + type_tag == tag || + (IsStructOrClassTag(type_tag) && IsStructOrClassTag(tag)); if (!try_resolving_type) { if (log) { @@ -3057,7 +3135,7 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) { } // Make sure the decl contexts match all the way up - if (GetDWARFDeclContext(die) != type_dwarf_decl_ctx) + if (die_dwarf_decl_ctx != type_dwarf_decl_ctx) return true; Type *resolved_type = ResolveType(type_die, false); @@ -3437,9 +3515,8 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, } // 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. + // for static constexpr member variables -- DW_AT_const_value and + // DW_AT_location will both be present in the DIE defining the member. bool location_is_const_value_data = const_value_form.IsValid() && !location_form.IsValid(); @@ -4129,6 +4206,72 @@ void SymbolFileDWARF::DumpClangAST(Stream &s) { clang->Dump(s.AsRawOstream()); } +bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d, + bool errors_only) { + StructuredData::Array separate_debug_info_files; + DWARFDebugInfo &info = DebugInfo(); + const size_t num_cus = info.GetNumUnits(); + for (size_t cu_idx = 0; cu_idx < num_cus; cu_idx++) { + DWARFUnit *unit = info.GetUnitAtIndex(cu_idx); + DWARFCompileUnit *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(unit); + if (dwarf_cu == nullptr) + continue; + + // Check if this is a DWO unit by checking if it has a DWO ID. + // NOTE: it seems that `DWARFUnit::IsDWOUnit` is always false? + if (!dwarf_cu->GetDWOId().has_value()) + continue; + + StructuredData::DictionarySP dwo_data = + std::make_shared<StructuredData::Dictionary>(); + const uint64_t dwo_id = dwarf_cu->GetDWOId().value(); + dwo_data->AddIntegerItem("dwo_id", dwo_id); + + if (const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly()) { + const char *dwo_name = GetDWOName(*dwarf_cu, *die.GetDIE()); + if (dwo_name) { + dwo_data->AddStringItem("dwo_name", dwo_name); + } else { + dwo_data->AddStringItem("error", "missing dwo name"); + } + + const char *comp_dir = die.GetDIE()->GetAttributeValueAsString( + dwarf_cu, DW_AT_comp_dir, nullptr); + if (comp_dir) { + dwo_data->AddStringItem("comp_dir", comp_dir); + } + } else { + dwo_data->AddStringItem( + "error", + llvm::formatv("unable to get unit DIE for DWARFUnit at {0:x}", + dwarf_cu->GetOffset()) + .str()); + } + + // If we have a DWO symbol file, that means we were able to successfully + // load it. + SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile(); + if (dwo_symfile) { + dwo_data->AddStringItem( + "resolved_dwo_path", + dwo_symfile->GetObjectFile()->GetFileSpec().GetPath()); + } else { + dwo_data->AddStringItem("error", + dwarf_cu->GetDwoError().AsCString("unknown")); + } + dwo_data->AddBooleanItem("loaded", dwo_symfile != nullptr); + if (!errors_only || dwo_data->HasKey("error")) + separate_debug_info_files.AddItem(dwo_data); + } + + d.AddStringItem("type", "dwo"); + d.AddStringItem("symfile", GetMainObjectFile()->GetFileSpec().GetPath()); + d.AddItem("separate-debug-info-files", + std::make_shared<StructuredData::Array>( + std::move(separate_debug_info_files))); + return true; +} + SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { if (m_debug_map_symfile == nullptr) { lldb::ModuleSP module_sp(m_debug_map_module_wp.lock()); @@ -4147,9 +4290,10 @@ const std::shared_ptr<SymbolFileDWARFDwo> &SymbolFileDWARF::GetDwpSymbolFile() { module_spec.GetSymbolFileSpec() = FileSpec(m_objfile_sp->GetModule()->GetFileSpec().GetPath() + ".dwp"); + module_spec.GetUUID() = m_objfile_sp->GetUUID(); FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); FileSpec dwp_filespec = - Symbols::LocateExecutableSymbolFile(module_spec, search_paths); + PluginManager::LocateExecutableSymbolFile(module_spec, search_paths); if (FileSystem::Instance().Exists(dwp_filespec)) { DataBufferSP dwp_file_data_sp; lldb::offset_t dwp_file_data_offset = 0; 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 191a5abcf265..78819edd0062 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -30,6 +30,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Flags.h" #include "lldb/Utility/RangeMap.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/lldb-private.h" #include "DWARFContext.h" @@ -38,10 +39,17 @@ #include "DWARFIndex.h" #include "UniqueDWARFASTType.h" +class DWARFASTParserClang; + +namespace llvm { +class DWARFDebugAbbrev; +} // namespace llvm + +namespace lldb_private::plugin { +namespace dwarf { // Forward Declarations for this DWARF plugin class DebugMapModule; class DWARFCompileUnit; -class DWARFDebugAbbrev; class DWARFDebugAranges; class DWARFDebugInfo; class DWARFDebugInfoEntry; @@ -53,11 +61,10 @@ class DWARFTypeUnit; class SymbolFileDWARFDebugMap; class SymbolFileDWARFDwo; class SymbolFileDWARFDwp; -class UserID; #define DIE_IS_BEING_PARSED ((lldb_private::Type *)1) -class SymbolFileDWARF : public lldb_private::SymbolFileCommon { +class SymbolFileDWARF : public SymbolFileCommon { /// LLVM RTTI support. static char ID; @@ -75,26 +82,24 @@ public: friend class DebugMapModule; friend class DWARFCompileUnit; friend class DWARFDIE; - friend class DWARFASTParserClang; + friend class DWARFASTParser; // Static Functions static void Initialize(); static void Terminate(); - static void DebuggerInitialize(lldb_private::Debugger &debugger); + static void DebuggerInitialize(Debugger &debugger); static llvm::StringRef GetPluginNameStatic() { return "dwarf"; } static llvm::StringRef GetPluginDescriptionStatic(); - static lldb_private::SymbolFile * - CreateInstance(lldb::ObjectFileSP objfile_sp); + static SymbolFile *CreateInstance(lldb::ObjectFileSP objfile_sp); // Constructors and Destructors - SymbolFileDWARF(lldb::ObjectFileSP objfile_sp, - lldb_private::SectionList *dwo_section_list); + SymbolFileDWARF(lldb::ObjectFileSP objfile_sp, SectionList *dwo_section_list); ~SymbolFileDWARF() override; @@ -104,118 +109,95 @@ public: // Compile Unit function calls - lldb::LanguageType - ParseLanguage(lldb_private::CompileUnit &comp_unit) override; + lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override; - lldb_private::XcodeSDK - ParseXcodeSDK(lldb_private::CompileUnit &comp_unit) override; + XcodeSDK ParseXcodeSDK(CompileUnit &comp_unit) override; - size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override; + size_t ParseFunctions(CompileUnit &comp_unit) override; - bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override; + bool ParseLineTable(CompileUnit &comp_unit) override; - bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; + bool ParseDebugMacros(CompileUnit &comp_unit) override; - bool ForEachExternalModule( - lldb_private::CompileUnit &, llvm::DenseSet<lldb_private::SymbolFile *> &, - llvm::function_ref<bool(lldb_private::Module &)>) override; + bool ForEachExternalModule(CompileUnit &, llvm::DenseSet<SymbolFile *> &, + llvm::function_ref<bool(Module &)>) override; - bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, - lldb_private::FileSpecList &support_files) override; + bool ParseSupportFiles(CompileUnit &comp_unit, + FileSpecList &support_files) override; - bool ParseIsOptimized(lldb_private::CompileUnit &comp_unit) override; + bool ParseIsOptimized(CompileUnit &comp_unit) override; - size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override; + size_t ParseTypes(CompileUnit &comp_unit) override; - bool ParseImportedModules( - const lldb_private::SymbolContext &sc, - std::vector<lldb_private::SourceModule> &imported_modules) override; + bool + ParseImportedModules(const SymbolContext &sc, + std::vector<SourceModule> &imported_modules) override; - size_t ParseBlocksRecursive(lldb_private::Function &func) override; + size_t ParseBlocksRecursive(Function &func) override; - size_t - ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; + size_t ParseVariablesForContext(const SymbolContext &sc) override; - lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override; - std::optional<ArrayInfo> GetDynamicArrayInfoForUID( - lldb::user_id_t type_uid, - const lldb_private::ExecutionContext *exe_ctx) override; + std::optional<ArrayInfo> + GetDynamicArrayInfoForUID(lldb::user_id_t type_uid, + const ExecutionContext *exe_ctx) override; - bool CompleteType(lldb_private::CompilerType &compiler_type) override; + bool CompleteType(CompilerType &compiler_type) override; - lldb_private::Type *ResolveType(const DWARFDIE &die, - bool assert_not_being_parsed = true, - bool resolve_function_context = false); + Type *ResolveType(const DWARFDIE &die, bool assert_not_being_parsed = true, + bool resolve_function_context = false); - lldb_private::CompilerDecl GetDeclForUID(lldb::user_id_t uid) override; + CompilerDecl GetDeclForUID(lldb::user_id_t uid) override; - lldb_private::CompilerDeclContext - GetDeclContextForUID(lldb::user_id_t uid) override; + CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override; - lldb_private::CompilerDeclContext - GetDeclContextContainingUID(lldb::user_id_t uid) override; + CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override; - void - ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override; + std::vector<CompilerContext> + GetCompilerContextForUID(lldb::user_id_t uid) override; - uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr, - lldb::SymbolContextItem resolve_scope, - lldb_private::SymbolContext &sc) override; + void ParseDeclsForContext(CompilerDeclContext decl_ctx) override; - lldb_private::Status - CalculateFrameVariableError(lldb_private::StackFrame &frame) override; + uint32_t ResolveSymbolContext(const Address &so_addr, + lldb::SymbolContextItem resolve_scope, + SymbolContext &sc) override; - uint32_t ResolveSymbolContext( - const lldb_private::SourceLocationSpec &src_location_spec, - lldb::SymbolContextItem resolve_scope, - lldb_private::SymbolContextList &sc_list) override; + Status CalculateFrameVariableError(StackFrame &frame) override; - void - FindGlobalVariables(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - lldb_private::VariableList &variables) override; + uint32_t ResolveSymbolContext(const SourceLocationSpec &src_location_spec, + lldb::SymbolContextItem resolve_scope, + SymbolContextList &sc_list) override; - void FindGlobalVariables(const lldb_private::RegularExpression ®ex, + void FindGlobalVariables(ConstString name, + const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, - lldb_private::VariableList &variables) override; + VariableList &variables) override; - void FindFunctions(const lldb_private::Module::LookupInfo &lookup_info, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - bool include_inlines, - lldb_private::SymbolContextList &sc_list) override; + void FindGlobalVariables(const RegularExpression ®ex, uint32_t max_matches, + VariableList &variables) override; - void FindFunctions(const lldb_private::RegularExpression ®ex, - bool include_inlines, - lldb_private::SymbolContextList &sc_list) override; + void FindFunctions(const Module::LookupInfo &lookup_info, + const CompilerDeclContext &parent_decl_ctx, + bool include_inlines, SymbolContextList &sc_list) override; - void GetMangledNamesForFunction( - const std::string &scope_qualified_name, - std::vector<lldb_private::ConstString> &mangled_names) override; + void FindFunctions(const RegularExpression ®ex, bool include_inlines, + SymbolContextList &sc_list) override; void - FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) override; + GetMangledNamesForFunction(const std::string &scope_qualified_name, + std::vector<ConstString> &mangled_names) override; - void FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> pattern, - lldb_private::LanguageSet languages, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) override; + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; - void GetTypes(lldb_private::SymbolContextScope *sc_scope, - lldb::TypeClass type_mask, - lldb_private::TypeList &type_list) override; + void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, + TypeList &type_list) override; llvm::Expected<lldb::TypeSystemSP> GetTypeSystemForLanguage(lldb::LanguageType language) override; - lldb_private::CompilerDeclContext - FindNamespace(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - bool only_root_namespaces) override; + CompilerDeclContext FindNamespace(ConstString name, + const CompilerDeclContext &parent_decl_ctx, + bool only_root_namespaces) override; void PreloadSymbols() override; @@ -224,7 +206,7 @@ public: // PluginInterface protocol llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } - DWARFDebugAbbrev *DebugAbbrev(); + llvm::DWARFDebugAbbrev *DebugAbbrev(); DWARFDebugInfo &DebugInfo(); @@ -235,25 +217,22 @@ public: DWARFDIE GetDeclContextDIEContainingDIE(const DWARFDIE &die); - bool - HasForwardDeclForClangType(const lldb_private::CompilerType &compiler_type); + bool HasForwardDeclForCompilerType(const CompilerType &compiler_type); - lldb_private::CompileUnit * - GetCompUnitForDWARFCompUnit(DWARFCompileUnit &dwarf_cu); + CompileUnit *GetCompUnitForDWARFCompUnit(DWARFCompileUnit &dwarf_cu); - virtual void GetObjCMethods(lldb_private::ConstString class_name, + virtual void GetObjCMethods(ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback); bool Supports_DW_AT_APPLE_objc_complete_type(DWARFUnit *cu); - lldb_private::DebugMacrosSP ParseDebugMacros(lldb::offset_t *offset); + DebugMacrosSP ParseDebugMacros(lldb::offset_t *offset); static DWARFDIE GetParentSymbolContextDIE(const DWARFDIE &die); - lldb::ModuleSP GetExternalModule(lldb_private::ConstString name); + lldb::ModuleSP GetExternalModule(ConstString name); - typedef std::map<lldb_private::ConstString, lldb::ModuleSP> - ExternalTypeModuleMap; + typedef std::map<ConstString, lldb::ModuleSP> ExternalTypeModuleMap; /// Return the list of Clang modules imported by this SymbolFile. const ExternalTypeModuleMap &getExternalTypeModules() const { @@ -271,22 +250,26 @@ public: /// If this is a DWARF object with a single CU, return its DW_AT_dwo_id. std::optional<uint64_t> GetDWOId(); - static bool - DIEInDeclContext(const lldb_private::CompilerDeclContext &parent_decl_ctx, - const DWARFDIE &die, bool only_root_namespaces = false); + static bool DIEInDeclContext(const CompilerDeclContext &parent_decl_ctx, + const DWARFDIE &die, + bool only_root_namespaces = false); - std::vector<std::unique_ptr<lldb_private::CallEdge>> - ParseCallEdgesInFunction(lldb_private::UserID func_id) override; + std::vector<std::unique_ptr<CallEdge>> + ParseCallEdgesInFunction(UserID func_id) override; - void Dump(lldb_private::Stream &s) override; + void Dump(Stream &s) override; - void DumpClangAST(lldb_private::Stream &s) override; + void DumpClangAST(Stream &s) override; - lldb_private::DWARFContext &GetDWARFContext() { return m_context; } + /// List separate dwo files. + bool GetSeparateDebugInfo(StructuredData::Dictionary &d, + bool errors_only) override; + + DWARFContext &GetDWARFContext() { return m_context; } const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile(); - lldb_private::FileSpec GetFile(DWARFUnit &unit, size_t file_idx); + FileSpec GetFile(DWARFUnit &unit, size_t file_idx); static llvm::Expected<lldb::TypeSystemSP> GetTypeSystem(DWARFUnit &unit); @@ -294,12 +277,11 @@ public: // CompilerDecl related functions - static lldb_private::CompilerDecl GetDecl(const DWARFDIE &die); + static CompilerDecl GetDecl(const DWARFDIE &die); - static lldb_private::CompilerDeclContext GetDeclContext(const DWARFDIE &die); + static CompilerDeclContext GetDeclContext(const DWARFDIE &die); - static lldb_private::CompilerDeclContext - GetContainingDeclContext(const DWARFDIE &die); + static CompilerDeclContext GetContainingDeclContext(const DWARFDIE &die); static DWARFDeclContext GetDWARFDeclContext(const DWARFDIE &die); @@ -309,142 +291,152 @@ public: /// Same as GetLanguage() but reports all C++ versions as C++ (no version). static lldb::LanguageType GetLanguageFamily(DWARFUnit &unit); - lldb_private::StatsDuration::Duration GetDebugInfoParseTime() override { + StatsDuration::Duration GetDebugInfoParseTime() override { return m_parse_time; } - lldb_private::StatsDuration::Duration GetDebugInfoIndexTime() override; + StatsDuration::Duration GetDebugInfoIndexTime() override; - lldb_private::StatsDuration &GetDebugInfoParseTimeRef() { - return m_parse_time; - } + StatsDuration &GetDebugInfoParseTimeRef() { return m_parse_time; } virtual lldb::offset_t - GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data, + GetVendorDWARFOpcodeSize(const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op) const { return LLDB_INVALID_OFFSET; } - virtual bool - ParseVendorDWARFOpcode(uint8_t op, const lldb_private::DataExtractor &opcodes, - lldb::offset_t &offset, - std::vector<lldb_private::Value> &stack) const { + virtual bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, + lldb::offset_t &offset, + std::vector<Value> &stack) const { return false; } - lldb_private::ConstString ConstructFunctionDemangledName(const DWARFDIE &die); + ConstString ConstructFunctionDemangledName(const DWARFDIE &die); std::optional<uint64_t> GetFileIndex() const { return m_file_index; } void SetFileIndex(std::optional<uint64_t> file_index) { m_file_index = file_index; } -protected: - typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> - DIEToTypePtr; - typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP> - DIEToVariableSP; + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> DIEToTypePtr; + + virtual DIEToTypePtr &GetDIEToType() { return m_die_to_type; } + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::opaque_compiler_type_t> - DIEToClangType; - typedef llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> ClangTypeToDIE; + DIEToCompilerType; + + virtual DIEToCompilerType &GetForwardDeclDIEToCompilerType() { + return m_forward_decl_die_to_compiler_type; + } + + typedef llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> + CompilerTypeToDIE; + + virtual CompilerTypeToDIE &GetForwardDeclCompilerTypeToDIE() { + return m_forward_decl_compiler_type_to_die; + } + + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP> + DIEToVariableSP; + + virtual DIEToVariableSP &GetDIEToVariable() { return m_die_to_variable_sp; } + + virtual UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap(); + + bool ClassOrStructIsVirtual(const DWARFDIE &die); + SymbolFileDWARFDebugMap *GetDebugMapSymfile(); + + virtual lldb::TypeSP + FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die); + + virtual lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE( + const DWARFDIE &die, ConstString type_name, bool must_be_implementation); + + Type *ResolveTypeUID(lldb::user_id_t type_uid) override; + + Type *ResolveTypeUID(const DWARFDIE &die, bool assert_not_being_parsed); + + Type *ResolveTypeUID(const DIERef &die_ref); + +protected: SymbolFileDWARF(const SymbolFileDWARF &) = delete; const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete; virtual void LoadSectionData(lldb::SectionType sect_type, - lldb_private::DWARFDataExtractor &data); + DWARFDataExtractor &data); - bool DeclContextMatchesThisSymbolFile( - const lldb_private::CompilerDeclContext &decl_ctx); + bool DeclContextMatchesThisSymbolFile(const CompilerDeclContext &decl_ctx); uint32_t CalculateNumCompileUnits() override; lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; - lldb_private::TypeList &GetTypeList() override; + TypeList &GetTypeList() override; lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu); - virtual DWARFCompileUnit * - GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit); + virtual DWARFCompileUnit *GetDWARFCompileUnit(CompileUnit *comp_unit); DWARFUnit *GetNextUnparsedDWARFCompileUnit(DWARFUnit *prev_cu); - bool GetFunction(const DWARFDIE &die, lldb_private::SymbolContext &sc); + bool GetFunction(const DWARFDIE &die, SymbolContext &sc); - lldb_private::Function *ParseFunction(lldb_private::CompileUnit &comp_unit, - const DWARFDIE &die); + Function *ParseFunction(CompileUnit &comp_unit, const DWARFDIE &die); - size_t ParseBlocksRecursive(lldb_private::CompileUnit &comp_unit, - lldb_private::Block *parent_block, + size_t ParseBlocksRecursive(CompileUnit &comp_unit, Block *parent_block, const DWARFDIE &die, lldb::addr_t subprogram_low_pc, uint32_t depth); - size_t ParseTypes(const lldb_private::SymbolContext &sc, const DWARFDIE &die, + size_t ParseTypes(const SymbolContext &sc, const DWARFDIE &die, bool parse_siblings, bool parse_children); - lldb::TypeSP ParseType(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, bool *type_is_new); + lldb::TypeSP ParseType(const SymbolContext &sc, const DWARFDIE &die, + bool *type_is_new); bool ParseSupportFiles(DWARFUnit &dwarf_cu, const lldb::ModuleSP &module, - lldb_private::FileSpecList &support_files); - - lldb_private::Type *ResolveTypeUID(const DWARFDIE &die, - bool assert_not_being_parsed); - - lldb_private::Type *ResolveTypeUID(const DIERef &die_ref); + FileSpecList &support_files); - lldb::VariableSP ParseVariableDIE(const lldb_private::SymbolContext &sc, + lldb::VariableSP ParseVariableDIE(const SymbolContext &sc, const DWARFDIE &die, const lldb::addr_t func_low_pc); - lldb::VariableSP ParseVariableDIECached(const lldb_private::SymbolContext &sc, + lldb::VariableSP ParseVariableDIECached(const SymbolContext &sc, const DWARFDIE &die); - void - ParseAndAppendGlobalVariable(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, - lldb_private::VariableList &cc_variable_list); + void ParseAndAppendGlobalVariable(const SymbolContext &sc, + const DWARFDIE &die, + VariableList &cc_variable_list); - size_t ParseVariablesInFunctionContext(const lldb_private::SymbolContext &sc, + size_t ParseVariablesInFunctionContext(const SymbolContext &sc, const DWARFDIE &die, const lldb::addr_t func_low_pc); - size_t ParseVariablesInFunctionContextRecursive( - const lldb_private::SymbolContext &sc, const DWARFDIE &die, - lldb::addr_t func_low_pc, DIEArray &accumulator); + size_t ParseVariablesInFunctionContextRecursive(const SymbolContext &sc, + const DWARFDIE &die, + lldb::addr_t func_low_pc, + DIEArray &accumulator); - size_t PopulateBlockVariableList(lldb_private::VariableList &variable_list, - const lldb_private::SymbolContext &sc, + size_t PopulateBlockVariableList(VariableList &variable_list, + const SymbolContext &sc, llvm::ArrayRef<DIERef> variable_dies, lldb::addr_t func_low_pc); DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die, DIEArray &&variable_dies); - bool ClassOrStructIsVirtual(const DWARFDIE &die); - // Given a die_offset, figure out the symbol context representing that die. bool ResolveFunction(const DWARFDIE &die, bool include_inlines, - lldb_private::SymbolContextList &sc_list); + SymbolContextList &sc_list); /// Resolve functions and (possibly) blocks for the given file address and a /// compile unit. The compile unit comes from the sc argument and it must be /// set. The results of the lookup (if any) are written back to the symbol /// context. void ResolveFunctionAndBlock(lldb::addr_t file_vm_addr, bool lookup_block, - lldb_private::SymbolContext &sc); + SymbolContext &sc); - virtual lldb::TypeSP - FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die); - - virtual lldb::TypeSP - FindCompleteObjCDefinitionTypeForDIE(const DWARFDIE &die, - lldb_private::ConstString type_name, - bool must_be_implementation); - - lldb_private::Symbol * - GetObjCClassSymbol(lldb_private::ConstString objc_class_name); + Symbol *GetObjCClassSymbol(ConstString objc_class_name); lldb::TypeSP GetTypeForDIE(const DWARFDIE &die, bool resolve_function_context = false); @@ -453,8 +445,6 @@ protected: m_debug_map_module_wp = module_sp; } - SymbolFileDWARFDebugMap *GetDebugMapSymfile(); - DWARFDIE FindBlockContainingSpecification(const DIERef &func_die_ref, dw_offset_t spec_block_die_offset); @@ -463,16 +453,13 @@ protected: FindBlockContainingSpecification(const DWARFDIE &die, dw_offset_t spec_block_die_offset); - virtual UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap(); - bool DIEDeclContextsMatch(const DWARFDIE &die1, const DWARFDIE &die2); - bool ClassContainsSelector(const DWARFDIE &class_die, - lldb_private::ConstString selector); + bool ClassContainsSelector(const DWARFDIE &class_die, ConstString selector); /// Parse call site entries (DW_TAG_call_site), including any nested call site /// parameters (DW_TAG_call_site_parameter). - std::vector<std::unique_ptr<lldb_private::CallEdge>> + std::vector<std::unique_ptr<CallEdge>> CollectCallEdges(lldb::ModuleSP module, DWARFDIE function_die); /// If this symbol file is linked to by a debug map (see @@ -482,48 +469,34 @@ protected: /// needed, on success and LLDB_INVALID_ADDRESS otherwise. lldb::addr_t FixupAddress(lldb::addr_t file_addr); - bool FixupAddress(lldb_private::Address &addr); + bool FixupAddress(Address &addr); - typedef llvm::SetVector<lldb_private::Type *> TypeSet; + typedef llvm::SetVector<Type *> TypeSet; void GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset, dw_offset_t max_die_offset, uint32_t type_mask, TypeSet &type_set); - typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, - lldb_private::Variable *> + typedef RangeDataVector<lldb::addr_t, lldb::addr_t, Variable *> GlobalVariableMap; GlobalVariableMap &GetGlobalAranges(); void UpdateExternalModuleListIfNeeded(); - virtual DIEToTypePtr &GetDIEToType() { return m_die_to_type; } - - virtual DIEToVariableSP &GetDIEToVariable() { return m_die_to_variable_sp; } - - virtual DIEToClangType &GetForwardDeclDieToClangType() { - return m_forward_decl_die_to_clang_type; - } - - virtual ClangTypeToDIE &GetForwardDeclClangTypeToDie() { - return m_forward_decl_clang_type_to_die; - } - void BuildCuTranslationTable(); std::optional<uint32_t> GetDWARFUnitIndex(uint32_t cu_idx); void FindDwpSymbolFile(); - const lldb_private::FileSpecList &GetTypeUnitSupportFiles(DWARFTypeUnit &tu); + const FileSpecList &GetTypeUnitSupportFiles(DWARFTypeUnit &tu); - void InitializeFirstCodeAddressRecursive( - const lldb_private::SectionList §ion_list); + void InitializeFirstCodeAddressRecursive(const SectionList §ion_list); void InitializeFirstCodeAddress(); - void GetCompileOptions( - std::unordered_map<lldb::CompUnitSP, lldb_private::Args> &args) override; + void + GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override; lldb::ModuleWP m_debug_map_module_wp; SymbolFileDWARFDebugMap *m_debug_map_symfile; @@ -531,22 +504,21 @@ protected: llvm::once_flag m_dwp_symfile_once_flag; std::shared_ptr<SymbolFileDWARFDwo> m_dwp_symfile; - lldb_private::DWARFContext m_context; + DWARFContext m_context; llvm::once_flag m_info_once_flag; std::unique_ptr<DWARFDebugInfo> m_info; - std::unique_ptr<DWARFDebugAbbrev> m_abbr; + std::unique_ptr<llvm::DWARFDebugAbbrev> m_abbr; std::unique_ptr<GlobalVariableMap> m_global_aranges_up; - typedef std::unordered_map<lldb::offset_t, lldb_private::DebugMacrosSP> - DebugMacrosMap; + typedef std::unordered_map<lldb::offset_t, DebugMacrosSP> DebugMacrosMap; DebugMacrosMap m_debug_macros_map; ExternalTypeModuleMap m_external_type_modules; - std::unique_ptr<lldb_private::DWARFIndex> m_index; + std::unique_ptr<DWARFIndex> m_index; bool m_fetched_external_modules : 1; - lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; + LazyBool m_supports_DW_AT_APPLE_objc_complete_type; typedef std::set<DIERef> DIERefSet; typedef llvm::StringMap<DIERefSet> NameToOffsetMap; @@ -555,10 +527,9 @@ protected: UniqueDWARFASTTypeMap m_unique_ast_type_map; DIEToTypePtr m_die_to_type; DIEToVariableSP m_die_to_variable_sp; - DIEToClangType m_forward_decl_die_to_clang_type; - ClangTypeToDIE m_forward_decl_clang_type_to_die; - llvm::DenseMap<dw_offset_t, lldb_private::FileSpecList> - m_type_unit_support_files; + DIEToCompilerType m_forward_decl_die_to_compiler_type; + CompilerTypeToDIE m_forward_decl_compiler_type_to_die; + llvm::DenseMap<dw_offset_t, FileSpecList> m_type_unit_support_files; std::vector<uint32_t> m_lldb_cu_to_dwarf_unit; /// DWARF does not provide a good way for traditional (concatenating) linkers /// to invalidate debug info describing dead-stripped code. These linkers will @@ -567,7 +538,7 @@ protected: /// Try to filter out this debug info by comparing it to the lowest code /// address in the module. lldb::addr_t m_first_code_address = LLDB_INVALID_ADDRESS; - lldb_private::StatsDuration m_parse_time; + StatsDuration m_parse_time; std::atomic_flag m_dwo_warning_issued = ATOMIC_FLAG_INIT; /// If this DWARF file a .DWO file or a DWARF .o file on mac when /// no dSYM file is being used, this file index will be set to a @@ -575,5 +546,7 @@ protected: /// an index that identifies the .DWO or .o file. std::optional<uint64_t> m_file_index; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARF_H 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 bb66fbadfb64..e5b59460cb85 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -18,13 +18,11 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Utility/RangeMap.h" #include "lldb/Utility/RegularExpression.h" -#include "lldb/Utility/Timer.h" #include "lldb/Utility/StreamString.h" +#include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/Timer.h" //#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT -#if defined(DEBUG_OSO_DMAP) -#include "lldb/Core/StreamFile.h" -#endif #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" @@ -45,6 +43,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; char SymbolFileDWARFDebugMap::ID; @@ -169,11 +168,13 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( return file_range_map; } +namespace lldb_private::plugin { +namespace dwarf { class DebugMapModule : public Module { public: DebugMapModule(const ModuleSP &exe_module_sp, uint32_t cu_idx, const FileSpec &file_spec, const ArchSpec &arch, - const ConstString *object_name, off_t object_offset, + ConstString object_name, off_t object_offset, const llvm::sys::TimePoint<> object_mod_time) : Module(file_spec, arch, object_name, object_offset, object_mod_time), m_exe_module_wp(exe_module_sp), m_cu_idx(cu_idx) {} @@ -225,6 +226,8 @@ protected: ModuleWP m_exe_module_wp; const uint32_t m_cu_idx; }; +} // namespace dwarf +} // namespace lldb_private::plugin void SymbolFileDWARFDebugMap::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), @@ -462,7 +465,7 @@ Module *SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo( .c_str()); comp_unit_info->oso_sp->module_sp = std::make_shared<DebugMapModule>( obj_file->GetModule(), GetCompUnitInfoIndex(comp_unit_info), oso_file, - oso_arch, oso_object ? &oso_object : nullptr, 0, + oso_arch, oso_object, 0, oso_object ? comp_unit_info->oso_mod_time : llvm::sys::TimePoint<>()); if (oso_object && !comp_unit_info->oso_sp->module_sp->GetObjectFile() && @@ -800,7 +803,7 @@ bool SymbolFileDWARFDebugMap::CompleteType(CompilerType &compiler_type) { bool success = false; if (compiler_type) { ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - if (oso_dwarf->HasForwardDeclForClangType(compiler_type)) { + if (oso_dwarf->HasForwardDeclForCompilerType(compiler_type)) { oso_dwarf->CompleteType(compiler_type); success = true; return true; @@ -1224,27 +1227,12 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( return TypeSP(); } -void SymbolFileDWARFDebugMap::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - TypeMap &types) { +void SymbolFileDWARFDebugMap::FindTypes(const TypeQuery &query, + TypeResults &results) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - oso_dwarf->FindTypes(name, parent_decl_ctx, max_matches, - searched_symbol_files, types); - return types.GetSize() >= max_matches; - }); -} - -void SymbolFileDWARFDebugMap::FindTypes( - llvm::ArrayRef<CompilerContext> context, LanguageSet languages, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - TypeMap &types) { - LLDB_SCOPED_TIMER(); - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - oso_dwarf->FindTypes(context, languages, searched_symbol_files, types); - return false; + oso_dwarf->FindTypes(query, results); + return !results.Done(query); // Keep iterating if we aren't done. }); } @@ -1274,6 +1262,43 @@ void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s) { }); } +bool SymbolFileDWARFDebugMap::GetSeparateDebugInfo( + lldb_private::StructuredData::Dictionary &d, bool errors_only) { + StructuredData::Array separate_debug_info_files; + const uint32_t cu_count = GetNumCompileUnits(); + for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) { + const auto &info = m_compile_unit_infos[cu_idx]; + StructuredData::DictionarySP oso_data = + std::make_shared<StructuredData::Dictionary>(); + oso_data->AddStringItem("so_file", info.so_file.GetPath()); + oso_data->AddStringItem("oso_path", info.oso_path); + oso_data->AddIntegerItem("oso_mod_time", + (uint32_t)llvm::sys::toTimeT(info.oso_mod_time)); + + bool loaded_successfully = false; + if (GetModuleByOSOIndex(cu_idx)) { + // If we have a valid pointer to the module, we successfully + // loaded the oso if there are no load errors. + if (!info.oso_load_error.Fail()) { + loaded_successfully = true; + } + } + if (!loaded_successfully) { + oso_data->AddStringItem("error", info.oso_load_error.AsCString()); + } + oso_data->AddBooleanItem("loaded", loaded_successfully); + if (!errors_only || oso_data->HasKey("error")) + separate_debug_info_files.AddItem(oso_data); + } + + d.AddStringItem("type", "oso"); + d.AddStringItem("symfile", GetMainObjectFile()->GetFileSpec().GetPath()); + d.AddItem("separate-debug-info-files", + std::make_shared<StructuredData::Array>( + std::move(separate_debug_info_files))); + return true; +} + lldb::CompUnitSP SymbolFileDWARFDebugMap::GetCompileUnit(SymbolFileDWARF *oso_dwarf, DWARFCompileUnit &dwarf_cu) { if (oso_dwarf) { @@ -1340,19 +1365,25 @@ void SymbolFileDWARFDebugMap::SetCompileUnit(SymbolFileDWARF *oso_dwarf, CompilerDeclContext SymbolFileDWARFDebugMap::GetDeclContextForUID(lldb::user_id_t type_uid) { const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid); - SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); - if (oso_dwarf) + if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx)) return oso_dwarf->GetDeclContextForUID(type_uid); - return CompilerDeclContext(); + return {}; } CompilerDeclContext SymbolFileDWARFDebugMap::GetDeclContextContainingUID(lldb::user_id_t type_uid) { const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid); - SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); - if (oso_dwarf) + if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx)) return oso_dwarf->GetDeclContextContainingUID(type_uid); - return CompilerDeclContext(); + return {}; +} + +std::vector<CompilerContext> +SymbolFileDWARFDebugMap::GetCompilerContextForUID(lldb::user_id_t type_uid) { + const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid); + if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx)) + return oso_dwarf->GetCompilerContextForUID(type_uid); + return {}; } void SymbolFileDWARFDebugMap::ParseDeclsForContext( diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 881fd4c45ff0..cd0a4bb6e41c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -19,13 +19,18 @@ #include <vector> #include "UniqueDWARFASTType.h" +#include "lldb/Utility/StructuredData.h" +class DWARFASTParserClang; + +namespace lldb_private::plugin { +namespace dwarf { class SymbolFileDWARF; class DWARFCompileUnit; class DWARFDebugAranges; class DWARFDeclContext; -class SymbolFileDWARFDebugMap : public lldb_private::SymbolFileCommon { +class SymbolFileDWARFDebugMap : public SymbolFileCommon { /// LLVM RTTI support. static char ID; @@ -47,8 +52,7 @@ public: static llvm::StringRef GetPluginDescriptionStatic(); - static lldb_private::SymbolFile * - CreateInstance(lldb::ObjectFileSP objfile_sp); + static SymbolFile *CreateInstance(lldb::ObjectFileSP objfile_sp); // Constructors and Destructors SymbolFileDWARFDebugMap(lldb::ObjectFileSP objfile_sp); @@ -58,110 +62,92 @@ public: void InitializeObject() override; // Compile Unit function calls - lldb::LanguageType - ParseLanguage(lldb_private::CompileUnit &comp_unit) override; - lldb_private::XcodeSDK - ParseXcodeSDK(lldb_private::CompileUnit &comp_unit) override; + lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override; + XcodeSDK ParseXcodeSDK(CompileUnit &comp_unit) override; llvm::SmallSet<lldb::LanguageType, 4> - ParseAllLanguages(lldb_private::CompileUnit &comp_unit) override; - size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override; - bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override; - bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; - - bool ForEachExternalModule( - lldb_private::CompileUnit &, llvm::DenseSet<lldb_private::SymbolFile *> &, - llvm::function_ref<bool(lldb_private::Module &)>) override; - - bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, - lldb_private::FileSpecList &support_files) override; - - bool ParseIsOptimized(lldb_private::CompileUnit &comp_unit) override; - - size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override; - - bool ParseImportedModules( - const lldb_private::SymbolContext &sc, - std::vector<lldb_private::SourceModule> &imported_modules) override; - size_t ParseBlocksRecursive(lldb_private::Function &func) override; - size_t - ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; - - lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override; - std::optional<ArrayInfo> GetDynamicArrayInfoForUID( - lldb::user_id_t type_uid, - const lldb_private::ExecutionContext *exe_ctx) override; - - lldb_private::CompilerDeclContext - GetDeclContextForUID(lldb::user_id_t uid) override; - lldb_private::CompilerDeclContext - GetDeclContextContainingUID(lldb::user_id_t uid) override; - void - ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override; + ParseAllLanguages(CompileUnit &comp_unit) override; + size_t ParseFunctions(CompileUnit &comp_unit) override; + bool ParseLineTable(CompileUnit &comp_unit) override; + bool ParseDebugMacros(CompileUnit &comp_unit) override; + + bool ForEachExternalModule(CompileUnit &, llvm::DenseSet<SymbolFile *> &, + llvm::function_ref<bool(Module &)>) override; + + bool ParseSupportFiles(CompileUnit &comp_unit, + FileSpecList &support_files) override; + + bool ParseIsOptimized(CompileUnit &comp_unit) override; + + size_t ParseTypes(CompileUnit &comp_unit) override; + + bool + ParseImportedModules(const SymbolContext &sc, + std::vector<SourceModule> &imported_modules) override; + size_t ParseBlocksRecursive(Function &func) override; + size_t ParseVariablesForContext(const SymbolContext &sc) override; + + Type *ResolveTypeUID(lldb::user_id_t type_uid) override; + std::optional<ArrayInfo> + GetDynamicArrayInfoForUID(lldb::user_id_t type_uid, + const ExecutionContext *exe_ctx) override; - bool CompleteType(lldb_private::CompilerType &compiler_type) override; - uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr, + CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override; + CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override; + std::vector<CompilerContext> + GetCompilerContextForUID(lldb::user_id_t uid) override; + void ParseDeclsForContext(CompilerDeclContext decl_ctx) override; + + bool CompleteType(CompilerType &compiler_type) override; + uint32_t ResolveSymbolContext(const Address &so_addr, + lldb::SymbolContextItem resolve_scope, + SymbolContext &sc) override; + uint32_t ResolveSymbolContext(const SourceLocationSpec &src_location_spec, lldb::SymbolContextItem resolve_scope, - lldb_private::SymbolContext &sc) override; - uint32_t ResolveSymbolContext( - const lldb_private::SourceLocationSpec &src_location_spec, - lldb::SymbolContextItem resolve_scope, - lldb_private::SymbolContextList &sc_list) override; + SymbolContextList &sc_list) override; - lldb_private::Status - CalculateFrameVariableError(lldb_private::StackFrame &frame) override; + Status CalculateFrameVariableError(StackFrame &frame) override; - void - FindGlobalVariables(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - lldb_private::VariableList &variables) override; - void FindGlobalVariables(const lldb_private::RegularExpression ®ex, + void FindGlobalVariables(ConstString name, + const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, - lldb_private::VariableList &variables) override; - void FindFunctions(const lldb_private::Module::LookupInfo &lookup_info, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - bool include_inlines, - lldb_private::SymbolContextList &sc_list) override; - void FindFunctions(const lldb_private::RegularExpression ®ex, - bool include_inlines, - lldb_private::SymbolContextList &sc_list) override; - void - FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) override; - void - FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> context, - lldb_private::LanguageSet languages, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) override; - lldb_private::CompilerDeclContext - FindNamespace(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - bool only_root_namespaces) override; - void GetTypes(lldb_private::SymbolContextScope *sc_scope, - lldb::TypeClass type_mask, - lldb_private::TypeList &type_list) override; - std::vector<std::unique_ptr<lldb_private::CallEdge>> - ParseCallEdgesInFunction(lldb_private::UserID func_id) override; - - void DumpClangAST(lldb_private::Stream &s) override; + VariableList &variables) override; + void FindGlobalVariables(const RegularExpression ®ex, uint32_t max_matches, + VariableList &variables) override; + void FindFunctions(const Module::LookupInfo &lookup_info, + const CompilerDeclContext &parent_decl_ctx, + bool include_inlines, SymbolContextList &sc_list) override; + void FindFunctions(const RegularExpression ®ex, bool include_inlines, + SymbolContextList &sc_list) override; + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; + CompilerDeclContext FindNamespace(ConstString name, + const CompilerDeclContext &parent_decl_ctx, + bool only_root_namespaces) override; + void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, + TypeList &type_list) override; + std::vector<std::unique_ptr<CallEdge>> + ParseCallEdgesInFunction(UserID func_id) override; + + void DumpClangAST(Stream &s) override; + + /// List separate oso files. + bool GetSeparateDebugInfo(StructuredData::Dictionary &d, + bool errors_only) override; // PluginInterface protocol llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } // Statistics overrides. - lldb_private::ModuleList GetDebugInfoModules() override; + ModuleList GetDebugInfoModules() override; - void GetCompileOptions( - std::unordered_map<lldb::CompUnitSP, lldb_private::Args> &args) override; + void + GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override; protected: enum { kHaveInitializedOSOs = (1 << 0), kNumFlags }; friend class DebugMapModule; - friend class DWARFASTParserClang; + friend class ::DWARFASTParserClang; friend class DWARFCompileUnit; friend class SymbolFileDWARF; struct OSOInfo { @@ -172,16 +158,15 @@ protected: typedef std::shared_ptr<OSOInfo> OSOInfoSP; - typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, - lldb::addr_t> + typedef RangeDataVector<lldb::addr_t, lldb::addr_t, lldb::addr_t> FileRangeMap; // Class specific types struct CompileUnitInfo { - lldb_private::FileSpec so_file; - lldb_private::ConstString oso_path; + FileSpec so_file; + ConstString oso_path; llvm::sys::TimePoint<> oso_mod_time; - lldb_private::Status oso_load_error; + Status oso_load_error; OSOInfoSP oso_sp; /// The compile units that an object file contains. llvm::SmallVector<lldb::CompUnitSP, 2> compile_units_sps; @@ -223,28 +208,26 @@ protected: static SymbolFileDWARF *GetSymbolFileAsSymbolFileDWARF(SymbolFile *sym_file); - bool GetFileSpecForSO(uint32_t oso_idx, lldb_private::FileSpec &file_spec); + bool GetFileSpecForSO(uint32_t oso_idx, FileSpec &file_spec); - CompileUnitInfo *GetCompUnitInfo(const lldb_private::SymbolContext &sc); - CompileUnitInfo *GetCompUnitInfo(const lldb_private::CompileUnit &comp_unit); + CompileUnitInfo *GetCompUnitInfo(const SymbolContext &sc); + CompileUnitInfo *GetCompUnitInfo(const CompileUnit &comp_unit); - size_t GetCompUnitInfosForModule(const lldb_private::Module *oso_module, + size_t GetCompUnitInfosForModule(const Module *oso_module, std::vector<CompileUnitInfo *> &cu_infos); - lldb_private::Module * - GetModuleByCompUnitInfo(CompileUnitInfo *comp_unit_info); + Module *GetModuleByCompUnitInfo(CompileUnitInfo *comp_unit_info); - lldb_private::Module *GetModuleByOSOIndex(uint32_t oso_idx); + Module *GetModuleByOSOIndex(uint32_t oso_idx); - lldb_private::ObjectFile * - GetObjectFileByCompUnitInfo(CompileUnitInfo *comp_unit_info); + ObjectFile *GetObjectFileByCompUnitInfo(CompileUnitInfo *comp_unit_info); - lldb_private::ObjectFile *GetObjectFileByOSOIndex(uint32_t oso_idx); + ObjectFile *GetObjectFileByOSOIndex(uint32_t oso_idx); uint32_t GetCompUnitInfoIndex(const CompileUnitInfo *comp_unit_info); - SymbolFileDWARF *GetSymbolFile(const lldb_private::SymbolContext &sc); - SymbolFileDWARF *GetSymbolFile(const lldb_private::CompileUnit &comp_unit); + SymbolFileDWARF *GetSymbolFile(const SymbolContext &sc); + SymbolFileDWARF *GetSymbolFile(const CompileUnit &comp_unit); SymbolFileDWARF *GetSymbolFileByCompUnitInfo(CompileUnitInfo *comp_unit_info); @@ -275,11 +258,11 @@ protected: static int SymbolContainsSymbolWithID(lldb::user_id_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info); - void PrivateFindGlobalVariables( - lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - const std::vector<uint32_t> &name_symbol_indexes, uint32_t max_matches, - lldb_private::VariableList &variables); + void + PrivateFindGlobalVariables(ConstString name, + const CompilerDeclContext &parent_decl_ctx, + const std::vector<uint32_t> &name_symbol_indexes, + uint32_t max_matches, VariableList &variables); void SetCompileUnit(SymbolFileDWARF *oso_dwarf, const lldb::CompUnitSP &cu_sp); @@ -297,8 +280,7 @@ protected: bool Supports_DW_AT_APPLE_objc_complete_type(SymbolFileDWARF *skip_dwarf_oso); lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE( - const DWARFDIE &die, lldb_private::ConstString type_name, - bool must_be_implementation); + const DWARFDIE &die, ConstString type_name, bool must_be_implementation); UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() { return m_unique_ast_type_map; @@ -329,19 +311,16 @@ protected: lldb::addr_t m_oso_file_addr = LLDB_INVALID_ADDRESS; }; - typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, OSOEntry> - DebugMap; + typedef RangeDataVector<lldb::addr_t, lldb::addr_t, OSOEntry> DebugMap; // Member Variables std::bitset<kNumFlags> m_flags; std::vector<CompileUnitInfo> m_compile_unit_infos; std::vector<uint32_t> m_func_indexes; // Sorted by address std::vector<uint32_t> m_glob_indexes; - std::map<std::pair<lldb_private::ConstString, llvm::sys::TimePoint<>>, - OSOInfoSP> - m_oso_map; + std::map<std::pair<ConstString, llvm::sys::TimePoint<>>, OSOInfoSP> m_oso_map; UniqueDWARFASTTypeMap m_unique_ast_type_map; - lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; + LazyBool m_supports_DW_AT_APPLE_objc_complete_type; DebugMap m_debug_map; // When an object file from the debug map gets parsed in @@ -365,7 +344,7 @@ protected: /// \return /// Returns true if \a addr was converted to be an executable /// section/offset address, false otherwise. - bool LinkOSOAddress(lldb_private::Address &addr); + bool LinkOSOAddress(Address &addr); /// Convert a .o file "file address" to an executable "file address". /// @@ -396,12 +375,13 @@ protected: /// Returns a valid line table full of linked addresses, or NULL /// if none of the line table addresses exist in the main /// executable. - lldb_private::LineTable * - LinkOSOLineTable(SymbolFileDWARF *oso_symfile, - lldb_private::LineTable *line_table); + LineTable *LinkOSOLineTable(SymbolFileDWARF *oso_symfile, + LineTable *line_table); size_t AddOSOARanges(SymbolFileDWARF *dwarf2Data, DWARFDebugAranges *debug_aranges); }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H 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 78c3c19684e1..ca698a84a914 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -21,6 +21,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; char SymbolFileDWARFDwo::ID; @@ -98,14 +99,14 @@ SymbolFileDWARF::DIEToVariableSP &SymbolFileDWARFDwo::GetDIEToVariable() { return GetBaseSymbolFile().GetDIEToVariable(); } -SymbolFileDWARF::DIEToClangType & -SymbolFileDWARFDwo::GetForwardDeclDieToClangType() { - return GetBaseSymbolFile().GetForwardDeclDieToClangType(); +SymbolFileDWARF::DIEToCompilerType & +SymbolFileDWARFDwo::GetForwardDeclDIEToCompilerType() { + return GetBaseSymbolFile().GetForwardDeclDIEToCompilerType(); } -SymbolFileDWARF::ClangTypeToDIE & -SymbolFileDWARFDwo::GetForwardDeclClangTypeToDie() { - return GetBaseSymbolFile().GetForwardDeclClangTypeToDie(); +SymbolFileDWARF::CompilerTypeToDIE & +SymbolFileDWARFDwo::GetForwardDeclCompilerTypeToDIE() { + return GetBaseSymbolFile().GetForwardDeclCompilerTypeToDIE(); } void SymbolFileDWARFDwo::GetObjCMethods( @@ -141,3 +142,10 @@ SymbolFileDWARFDwo::GetDIE(const DIERef &die_ref) { return DebugInfo().GetDIE(die_ref); return GetBaseSymbolFile().GetDIE(die_ref); } + +void SymbolFileDWARFDwo::FindGlobalVariables( + ConstString name, const CompilerDeclContext &parent_decl_ctx, + uint32_t max_matches, VariableList &variables) { + GetBaseSymbolFile().FindGlobalVariables(name, parent_decl_ctx, max_matches, + variables); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index e98ea49d939b..9f5950e51b0c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -12,6 +12,8 @@ #include "SymbolFileDWARF.h" #include <optional> +namespace lldb_private::plugin { +namespace dwarf { class SymbolFileDWARFDwo : public SymbolFileDWARF { /// LLVM RTTI support. static char ID; @@ -32,7 +34,7 @@ public: DWARFCompileUnit *GetDWOCompileUnitForHash(uint64_t hash); - void GetObjCMethods(lldb_private::ConstString class_name, + void GetObjCMethods(ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) override; llvm::Expected<lldb::TypeSystemSP> @@ -41,33 +43,37 @@ public: DWARFDIE GetDIE(const DIERef &die_ref) override; - lldb::offset_t - GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data, - const lldb::offset_t data_offset, - const uint8_t op) const override; + lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data, + const lldb::offset_t data_offset, + const uint8_t op) const override; - bool ParseVendorDWARFOpcode( - uint8_t op, const lldb_private::DataExtractor &opcodes, - lldb::offset_t &offset, - std::vector<lldb_private::Value> &stack) const override; + bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, + lldb::offset_t &offset, + std::vector<Value> &stack) const override; + + void FindGlobalVariables(ConstString name, + const CompilerDeclContext &parent_decl_ctx, + uint32_t max_matches, + VariableList &variables) override; protected: DIEToTypePtr &GetDIEToType() override; DIEToVariableSP &GetDIEToVariable() override; - DIEToClangType &GetForwardDeclDieToClangType() override; + DIEToCompilerType &GetForwardDeclDIEToCompilerType() override; - ClangTypeToDIE &GetForwardDeclClangTypeToDie() override; + CompilerTypeToDIE &GetForwardDeclCompilerTypeToDIE() override; UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() override; lldb::TypeSP FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) override; - lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE( - const DWARFDIE &die, lldb_private::ConstString type_name, - bool must_be_implementation) override; + lldb::TypeSP + FindCompleteObjCDefinitionTypeForDIE(const DWARFDIE &die, + ConstString type_name, + bool must_be_implementation) override; SymbolFileDWARF &GetBaseSymbolFile() const { return m_base_symbol_file; } @@ -77,5 +83,7 @@ protected: SymbolFileDWARF &m_base_symbol_file; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp index 22a921cf6138..223518f0ae82 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp @@ -11,6 +11,7 @@ #include "lldb/Core/Declaration.h" using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die, const lldb_private::Declaration &decl, diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h index 0947d1e581c5..bf3cbae55e5c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h @@ -16,13 +16,15 @@ #include "DWARFDIE.h" #include "lldb/Core/Declaration.h" +namespace lldb_private::plugin { +namespace dwarf { class UniqueDWARFASTType { public: // Constructors and Destructors UniqueDWARFASTType() : m_type_sp(), m_die(), m_declaration() {} UniqueDWARFASTType(lldb::TypeSP &type_sp, const DWARFDIE &die, - const lldb_private::Declaration &decl, int32_t byte_size) + const Declaration &decl, int32_t byte_size) : m_type_sp(type_sp), m_die(die), m_declaration(decl), m_byte_size(byte_size) {} @@ -44,7 +46,7 @@ public: lldb::TypeSP m_type_sp; DWARFDIE m_die; - lldb_private::Declaration m_declaration; + Declaration m_declaration; int32_t m_byte_size = -1; }; @@ -60,7 +62,7 @@ public: m_collection.push_back(entry); } - bool Find(const DWARFDIE &die, const lldb_private::Declaration &decl, + bool Find(const DWARFDIE &die, const Declaration &decl, const int32_t byte_size, UniqueDWARFASTType &entry) const; protected: @@ -74,14 +76,12 @@ public: ~UniqueDWARFASTTypeMap() = default; - void Insert(lldb_private::ConstString name, - const UniqueDWARFASTType &entry) { + void Insert(ConstString name, const UniqueDWARFASTType &entry) { m_collection[name.GetCString()].Append(entry); } - bool Find(lldb_private::ConstString name, const DWARFDIE &die, - const lldb_private::Declaration &decl, const int32_t byte_size, - UniqueDWARFASTType &entry) const { + bool Find(ConstString name, const DWARFDIE &die, const Declaration &decl, + const int32_t byte_size, UniqueDWARFASTType &entry) const { const char *unique_name_cstr = name.GetCString(); collection::const_iterator pos = m_collection.find(unique_name_cstr); if (pos != m_collection.end()) { @@ -95,5 +95,7 @@ protected: typedef llvm::DenseMap<const char *, UniqueDWARFASTTypeList> collection; collection m_collection; }; +} // namespace dwarf +} // namespace lldb_private::plugin #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_UNIQUEDWARFASTTYPE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp index 06cb720b1e9f..25d04f999ad6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp @@ -236,7 +236,7 @@ CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const { llvm::cantFail( TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name)); - llvm::sys::path::Style style = working_dir.String.startswith("/") + llvm::sys::path::Style style = working_dir.String.starts_with("/") ? llvm::sys::path::Style::posix : llvm::sys::path::Style::windows; if (llvm::sys::path::is_absolute(file_name.String, style)) diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp index 9623daa416bb..75adf7302f00 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp @@ -10,10 +10,10 @@ #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" -#include "lldb/Core/StreamBuffer.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/StreamBuffer.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" 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 c7ff25e904ab..b79d3e63f72b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -99,18 +99,18 @@ struct CreateMethodDecl : public TypeVisitorCallbacks { static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) { switch (cr.Kind) { case TypeRecordKind::Class: - return clang::TTK_Class; + return clang::TagTypeKind::Class; case TypeRecordKind::Struct: - return clang::TTK_Struct; + return clang::TagTypeKind::Struct; case TypeRecordKind::Union: - return clang::TTK_Union; + return clang::TagTypeKind::Union; case TypeRecordKind::Interface: - return clang::TTK_Interface; + return clang::TagTypeKind::Interface; case TypeRecordKind::Enum: - return clang::TTK_Enum; + return clang::TagTypeKind::Enum; default: lldbassert(false && "Invalid tag record kind!"); - return clang::TTK_Struct; + return clang::TagTypeKind::Struct; } } @@ -608,16 +608,17 @@ clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, return {}; clang::TagTypeKind ttk = TranslateUdtKind(record); - lldb::AccessType access = - (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; + lldb::AccessType access = (ttk == clang::TagTypeKind::Class) + ? lldb::eAccessPrivate + : lldb::eAccessPublic; ClangASTMetadata metadata; metadata.SetUserID(toOpaqueUid(id)); metadata.SetIsDynamicCXXType(false); - CompilerType ct = - m_clang.CreateRecordType(context, OptionalClangModuleID(), access, uname, - ttk, lldb::eLanguageTypeC_plus_plus, &metadata); + CompilerType ct = m_clang.CreateRecordType( + context, OptionalClangModuleID(), access, uname, llvm::to_underlying(ttk), + lldb::eLanguageTypeC_plus_plus, &metadata); lldbassert(ct.IsValid()); @@ -1263,9 +1264,9 @@ void PdbAstBuilder::ParseNamespace(clang::DeclContext &context) { clang::NamespaceDecl *ns = llvm::cast<clang::NamespaceDecl>(context); llvm::StringRef ns_name = ns->getName(); - if (ns_name.startswith(qname)) { + if (ns_name.starts_with(qname)) { ns_name = ns_name.drop_front(qname.size()); - if (ns_name.startswith("::")) + if (ns_name.starts_with("::")) GetOrCreateType(tid); } } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp index c45db174e534..f28509acbf79 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp @@ -9,7 +9,6 @@ #include "PdbFPOProgramToDWARFExpression.h" #include "CodeViewRegisterMapping.h" -#include "lldb/Core/StreamBuffer.h" #include "lldb/Symbol/PostfixExpression.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Stream.h" 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 f14fb32621b3..ad0801339936 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -14,8 +14,6 @@ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamBuffer.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" @@ -1381,7 +1379,7 @@ bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit, for (llvm::StringRef f : cci->m_file_list) { FileSpec::Style style = - f.startswith("/") ? FileSpec::Style::posix : FileSpec::Style::windows; + f.starts_with("/") ? FileSpec::Style::posix : FileSpec::Style::windows; FileSpec spec(f, style); support_files.Append(spec); } @@ -1719,24 +1717,33 @@ void SymbolFileNativePDB::FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) {} -void SymbolFileNativePDB::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, - TypeMap &types) { - std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - if (!name) +void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query, + lldb_private::TypeResults &results) { + + // Make sure we haven't already searched this SymbolFile before. + if (results.AlreadySearched(this)) return; - searched_symbol_files.clear(); - searched_symbol_files.insert(this); + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - // There is an assumption 'name' is not a regex - FindTypesByName(name.GetStringRef(), max_matches, types); -} + std::vector<TypeIndex> matches = + m_index->tpi().findRecordsByName(query.GetTypeBasename().GetStringRef()); -void SymbolFileNativePDB::FindTypes( - llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {} + for (TypeIndex type_idx : matches) { + TypeSP type_sp = GetOrCreateType(type_idx); + if (!type_sp) + continue; + + // We resolved a type. Get the fully qualified name to ensure it matches. + ConstString name = type_sp->GetQualifiedName(); + TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match); + if (query.ContextMatches(type_match.GetContextRef())) { + results.InsertUnique(type_sp); + if (results.Done(query)) + return; + } + } +} void SymbolFileNativePDB::FindTypesByName(llvm::StringRef name, uint32_t max_matches, 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 bf64cd330c1f..9d0458cf7ebf 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -140,14 +140,8 @@ public: std::optional<PdbCompilandSymId> FindSymbolScope(PdbCompilandSymId id); - void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, - TypeMap &types) override; - - void FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, - TypeMap &types) override; + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; llvm::Expected<lldb::TypeSystemSP> GetTypeSystemForLanguage(lldb::LanguageType language) override; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index cf3868d077c3..fab3ca989c0e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -356,14 +356,14 @@ UdtRecordCompleter::AddMember(TypeSystemClang &clang, Member *field, case Member::Struct: case Member::Union: { clang::TagTypeKind kind = field->kind == Member::Struct - ? clang::TagTypeKind::TTK_Struct - : clang::TagTypeKind::TTK_Union; + ? clang::TagTypeKind::Struct + : clang::TagTypeKind::Union; ClangASTMetadata metadata; metadata.SetUserID(pdb->anonymous_id); metadata.SetIsDynamicCXXType(false); CompilerType record_ct = clang.CreateRecordType( - parent_decl_ctx, OptionalClangModuleID(), lldb::eAccessPublic, "", kind, - lldb::eLanguageTypeC_plus_plus, &metadata); + parent_decl_ctx, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(kind), lldb::eLanguageTypeC_plus_plus, &metadata); TypeSystemClang::StartTagDeclarationDefinition(record_ct); ClangASTImporter::LayoutInfo layout; clang::DeclContext *decl_ctx = clang.GetDeclContextForType(record_ct); 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 5efa5bccb85f..e915bff9e4a4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -49,13 +49,13 @@ using namespace llvm::pdb; static int TranslateUdtKind(PDB_UdtType pdb_kind) { switch (pdb_kind) { case PDB_UdtType::Class: - return clang::TTK_Class; + return llvm::to_underlying(clang::TagTypeKind::Class); case PDB_UdtType::Struct: - return clang::TTK_Struct; + return llvm::to_underlying(clang::TagTypeKind::Struct); case PDB_UdtType::Union: - return clang::TTK_Union; + return llvm::to_underlying(clang::TagTypeKind::Union); case PDB_UdtType::Interface: - return clang::TTK_Interface; + return llvm::to_underlying(clang::TagTypeKind::Interface); } llvm_unreachable("unsuported PDB UDT type"); } @@ -1387,9 +1387,9 @@ void PDBASTParser::AddRecordBases( auto is_virtual = base->isVirtualBaseClass(); std::unique_ptr<clang::CXXBaseSpecifier> base_spec = - m_ast.CreateBaseClassSpecifier(base_comp_type.GetOpaqueQualType(), - access, is_virtual, - record_kind == clang::TTK_Class); + m_ast.CreateBaseClassSpecifier( + base_comp_type.GetOpaqueQualType(), access, is_virtual, + record_kind == llvm::to_underlying(clang::TagTypeKind::Class)); lldbassert(base_spec); base_classes.push_back(std::move(base_spec)); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp index 94023737b2a2..95add31385df 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp @@ -9,11 +9,11 @@ #include "PDBLocationToDWARFExpression.h" #include "lldb/Core/Section.h" -#include "lldb/Core/StreamBuffer.h" #include "lldb/Core/dwarf.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/Variable.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/StreamBuffer.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" 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 78eabc35ebf9..9e1cd8360660 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -1446,24 +1446,6 @@ void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) { symtab.Finalize(); } -void SymbolFilePDB::FindTypes( - lldb_private::ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) { - std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - if (!name) - return; - if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) - return; - - searched_symbol_files.clear(); - searched_symbol_files.insert(this); - - // There is an assumption 'name' is not a regex - FindTypesByName(name.GetStringRef(), parent_decl_ctx, max_matches, types); -} - void SymbolFilePDB::DumpClangAST(Stream &s) { auto type_system_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); @@ -1536,26 +1518,24 @@ void SymbolFilePDB::FindTypesByRegex( } } -void SymbolFilePDB::FindTypesByName( - llvm::StringRef name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, lldb_private::TypeMap &types) { +void SymbolFilePDB::FindTypes(const lldb_private::TypeQuery &query, + lldb_private::TypeResults &type_results) { + + // Make sure we haven't already searched this SymbolFile before. + if (type_results.AlreadySearched(this)) + return; + + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + std::unique_ptr<IPDBEnumSymbols> results; - if (name.empty()) + llvm::StringRef basename = query.GetTypeBasename().GetStringRef(); + if (basename.empty()) return; results = m_global_scope_up->findAllChildren(PDB_SymType::None); if (!results) return; - uint32_t matches = 0; - while (auto result = results->getNext()) { - if (max_matches > 0 && matches >= max_matches) - break; - - if (MSVCUndecoratedNameParser::DropScope( - result->getRawSymbol().getName()) != name) - continue; switch (result->getSymTag()) { case PDB_SymType::Enum: @@ -1568,28 +1548,29 @@ void SymbolFilePDB::FindTypesByName( continue; } + if (MSVCUndecoratedNameParser::DropScope( + result->getRawSymbol().getName()) != basename) + continue; + // This should cause the type to get cached and stored in the `m_types` // lookup. if (!ResolveTypeUID(result->getSymIndexId())) continue; - if (parent_decl_ctx.IsValid() && - GetDeclContextContainingUID(result->getSymIndexId()) != parent_decl_ctx) - continue; - auto iter = m_types.find(result->getSymIndexId()); if (iter == m_types.end()) continue; - types.Insert(iter->second); - ++matches; + // We resolved a type. Get the fully qualified name to ensure it matches. + ConstString name = iter->second->GetQualifiedName(); + TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match); + if (query.ContextMatches(type_match.GetContextRef())) { + type_results.InsertUnique(iter->second); + if (type_results.Done(query)) + return; + } } } -void SymbolFilePDB::FindTypes( - llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) {} - void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol, uint32_t type_mask, TypeCollection &type_collection) { diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h index 5b98c6e8b486..01851f1418f3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -134,19 +134,8 @@ public: std::vector<lldb_private::ConstString> &mangled_names) override; void AddSymbols(lldb_private::Symtab &symtab) override; - - void - FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) override; - - void FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> pattern, - lldb_private::LanguageSet languages, - llvm::DenseSet<SymbolFile *> &searched_symbol_files, - lldb_private::TypeMap &types) override; - + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; void FindTypesByRegex(const lldb_private::RegularExpression ®ex, uint32_t max_matches, lldb_private::TypeMap &types); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp new file mode 100644 index 000000000000..9f32d252b22f --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp @@ -0,0 +1,1149 @@ +//===-- SymbolLocatorDebugSymbols.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 "SymbolLocatorDebugSymbols.h" + +#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/Timer.h" +#include "lldb/Utility/UUID.h" + +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ThreadPool.h" + +#include "Host/macosx/cfcpp/CFCBundle.h" +#include "Host/macosx/cfcpp/CFCData.h" +#include "Host/macosx/cfcpp/CFCReleaser.h" +#include "Host/macosx/cfcpp/CFCString.h" + +#include "mach/machine.h" + +#include <CoreFoundation/CoreFoundation.h> + +#include <cstring> +#include <dirent.h> +#include <dlfcn.h> +#include <optional> +#include <pwd.h> + +using namespace lldb; +using namespace lldb_private; + +static CFURLRef (*g_dlsym_DBGCopyFullDSYMURLForUUID)( + CFUUIDRef uuid, CFURLRef exec_url) = nullptr; +static CFDictionaryRef (*g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url) = + nullptr; + +LLDB_PLUGIN_DEFINE(SymbolLocatorDebugSymbols) + +SymbolLocatorDebugSymbols::SymbolLocatorDebugSymbols() : SymbolLocator() {} + +void SymbolLocatorDebugSymbols::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, + LocateExecutableObjectFile, LocateExecutableSymbolFile, + DownloadObjectAndSymbolFile, FindSymbolFileInBundle); +} + +void SymbolLocatorDebugSymbols::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +llvm::StringRef SymbolLocatorDebugSymbols::GetPluginDescriptionStatic() { + return "DebugSymbols symbol locator."; +} + +SymbolLocator *SymbolLocatorDebugSymbols::CreateInstance() { + return new SymbolLocatorDebugSymbols(); +} + +std::optional<ModuleSpec> SymbolLocatorDebugSymbols::LocateExecutableObjectFile( + const ModuleSpec &module_spec) { + Log *log = GetLog(LLDBLog::Host); + if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { + LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled."); + return {}; + } + ModuleSpec return_module_spec; + return_module_spec = module_spec; + return_module_spec.GetFileSpec().Clear(); + return_module_spec.GetSymbolFileSpec().Clear(); + + const UUID *uuid = module_spec.GetUUIDPtr(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + + int items_found = 0; + + if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || + g_dlsym_DBGCopyDSYMPropertyLists == nullptr) { + void *handle = dlopen( + "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols", + RTLD_LAZY | RTLD_LOCAL); + if (handle) { + g_dlsym_DBGCopyFullDSYMURLForUUID = + (CFURLRef(*)(CFUUIDRef, CFURLRef))dlsym(handle, + "DBGCopyFullDSYMURLForUUID"); + g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef(*)(CFURLRef))dlsym( + handle, "DBGCopyDSYMPropertyLists"); + } + } + + if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || + g_dlsym_DBGCopyDSYMPropertyLists == nullptr) { + return {}; + } + + if (uuid && uuid->IsValid()) { + // Try and locate the dSYM file using DebugSymbols first + llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes(); + if (module_uuid.size() == 16) { + CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes( + NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3], + module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7], + module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11], + module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15])); + + if (module_uuid_ref.get()) { + CFCReleaser<CFURLRef> exec_url; + const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); + if (exec_fspec) { + char exec_cf_path[PATH_MAX]; + if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path))) + exec_url.reset(::CFURLCreateFromFileSystemRepresentation( + NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path), + FALSE)); + } + + CFCReleaser<CFURLRef> dsym_url(g_dlsym_DBGCopyFullDSYMURLForUUID( + module_uuid_ref.get(), exec_url.get())); + char path[PATH_MAX]; + + if (dsym_url.get()) { + if (::CFURLGetFileSystemRepresentation( + dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { + LLDB_LOGF(log, + "DebugSymbols framework returned dSYM path of %s for " + "UUID %s -- looking for the dSYM", + path, uuid->GetAsString().c_str()); + FileSpec dsym_filespec(path); + if (path[0] == '~') + FileSystem::Instance().Resolve(dsym_filespec); + + if (FileSystem::Instance().IsDirectory(dsym_filespec)) { + dsym_filespec = PluginManager::FindSymbolFileInBundle( + dsym_filespec, uuid, arch); + ++items_found; + } else { + ++items_found; + } + return_module_spec.GetSymbolFileSpec() = dsym_filespec; + } + + bool success = false; + if (log) { + if (::CFURLGetFileSystemRepresentation( + dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { + LLDB_LOGF(log, + "DebugSymbols framework returned dSYM path of %s for " + "UUID %s -- looking for an exec file", + path, uuid->GetAsString().c_str()); + } + } + + CFCReleaser<CFDictionaryRef> dict( + g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get())); + CFDictionaryRef uuid_dict = NULL; + if (dict.get()) { + CFCString uuid_cfstr(uuid->GetAsString().c_str()); + uuid_dict = static_cast<CFDictionaryRef>( + ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get())); + } + + // Check to see if we have the file on the local filesystem. + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { + ModuleSpec exe_spec; + exe_spec.GetFileSpec() = module_spec.GetFileSpec(); + exe_spec.GetUUID() = module_spec.GetUUID(); + ModuleSP module_sp; + module_sp.reset(new Module(exe_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(exe_spec)) { + success = true; + return_module_spec.GetFileSpec() = module_spec.GetFileSpec(); + LLDB_LOGF(log, "using original binary filepath %s for UUID %s", + module_spec.GetFileSpec().GetPath().c_str(), + uuid->GetAsString().c_str()); + ++items_found; + } + } + + // Check if the requested image is in our shared cache. + if (!success) { + SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo( + module_spec.GetFileSpec().GetPath()); + + // If we found it and it has the correct UUID, let's proceed with + // creating a module from the memory contents. + if (image_info.uuid && (!module_spec.GetUUID() || + module_spec.GetUUID() == image_info.uuid)) { + success = true; + return_module_spec.GetFileSpec() = module_spec.GetFileSpec(); + LLDB_LOGF(log, + "using binary from shared cache for filepath %s for " + "UUID %s", + module_spec.GetFileSpec().GetPath().c_str(), + uuid->GetAsString().c_str()); + ++items_found; + } + } + + // Use the DBGSymbolRichExecutable filepath if present + if (!success && uuid_dict) { + CFStringRef exec_cf_path = + static_cast<CFStringRef>(::CFDictionaryGetValue( + uuid_dict, CFSTR("DBGSymbolRichExecutable"))); + if (exec_cf_path && ::CFStringGetFileSystemRepresentation( + exec_cf_path, path, sizeof(path))) { + LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s", + path, uuid->GetAsString().c_str()); + ++items_found; + FileSpec exec_filespec(path); + if (path[0] == '~') + FileSystem::Instance().Resolve(exec_filespec); + if (FileSystem::Instance().Exists(exec_filespec)) { + success = true; + return_module_spec.GetFileSpec() = exec_filespec; + } + } + } + + // Look next to the dSYM for the binary file. + if (!success) { + if (::CFURLGetFileSystemRepresentation( + dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { + char *dsym_extension_pos = ::strstr(path, ".dSYM"); + if (dsym_extension_pos) { + *dsym_extension_pos = '\0'; + LLDB_LOGF(log, + "Looking for executable binary next to dSYM " + "bundle with name with name %s", + path); + FileSpec file_spec(path); + FileSystem::Instance().Resolve(file_spec); + ModuleSpecList module_specs; + ModuleSpec matched_module_spec; + using namespace llvm::sys::fs; + switch (get_file_type(file_spec.GetPath())) { + + case file_type::directory_file: // Bundle directory? + { + CFCBundle bundle(path); + CFCReleaser<CFURLRef> bundle_exe_url( + bundle.CopyExecutableURL()); + if (bundle_exe_url.get()) { + if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(), + true, (UInt8 *)path, + sizeof(path) - 1)) { + FileSpec bundle_exe_file_spec(path); + FileSystem::Instance().Resolve(bundle_exe_file_spec); + if (ObjectFile::GetModuleSpecifications( + bundle_exe_file_spec, 0, 0, module_specs) && + module_specs.FindMatchingModuleSpec( + module_spec, matched_module_spec)) + + { + ++items_found; + return_module_spec.GetFileSpec() = bundle_exe_file_spec; + LLDB_LOGF(log, + "Executable binary %s next to dSYM is " + "compatible; using", + path); + } + } + } + } break; + + case file_type::fifo_file: // Forget pipes + case file_type::socket_file: // We can't process socket files + case file_type::file_not_found: // File doesn't exist... + case file_type::status_error: + break; + + case file_type::type_unknown: + case file_type::regular_file: + case file_type::symlink_file: + case file_type::block_file: + case file_type::character_file: + if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0, + module_specs) && + module_specs.FindMatchingModuleSpec(module_spec, + matched_module_spec)) + + { + ++items_found; + return_module_spec.GetFileSpec() = file_spec; + LLDB_LOGF(log, + "Executable binary %s next to dSYM is " + "compatible; using", + path); + } + break; + } + } + } + } + } + } + } + } + + if (items_found) + return return_module_spec; + + return {}; +} + +std::optional<FileSpec> SymbolLocatorDebugSymbols::FindSymbolFileInBundle( + const FileSpec &dsym_bundle_fspec, const UUID *uuid, const ArchSpec *arch) { + std::string dsym_bundle_path = dsym_bundle_fspec.GetPath(); + llvm::SmallString<128> buffer(dsym_bundle_path); + llvm::sys::path::append(buffer, "Contents", "Resources", "DWARF"); + + std::error_code EC; + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = + FileSystem::Instance().GetVirtualFileSystem(); + llvm::vfs::recursive_directory_iterator Iter(*vfs, buffer.str(), EC); + llvm::vfs::recursive_directory_iterator End; + for (; Iter != End && !EC; Iter.increment(EC)) { + llvm::ErrorOr<llvm::vfs::Status> Status = vfs->status(Iter->path()); + if (Status->isDirectory()) + continue; + + FileSpec dsym_fspec(Iter->path()); + ModuleSpecList module_specs; + if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) { + ModuleSpec spec; + for (size_t i = 0; i < module_specs.GetSize(); ++i) { + bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); + assert(got_spec); // The call has side-effects so can't be inlined. + UNUSED_IF_ASSERT_DISABLED(got_spec); + if ((uuid == nullptr || + (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && + (arch == nullptr || + (spec.GetArchitecturePtr() && + spec.GetArchitecture().IsCompatibleMatch(*arch)))) { + return dsym_fspec; + } + } + } + } + + return {}; +} + +static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec, + const ArchSpec *arch, + const lldb_private::UUID *uuid) { + ModuleSpecList module_specs; + if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) { + ModuleSpec spec; + for (size_t i = 0; i < module_specs.GetSize(); ++i) { + bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); + UNUSED_IF_ASSERT_DISABLED(got_spec); + assert(got_spec); + if ((uuid == nullptr || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && + (arch == nullptr || + (spec.GetArchitecturePtr() && + spec.GetArchitecture().IsCompatibleMatch(*arch)))) { + return true; + } + } + } + return false; +} + +// Given a binary exec_fspec, and a ModuleSpec with an architecture/uuid, +// return true if there is a matching dSYM bundle next to the exec_fspec, +// and return that value in dsym_fspec. +// If there is a .dSYM.yaa compressed archive next to the exec_fspec, +// call through PluginManager::DownloadObjectAndSymbolFile to download the +// expanded/uncompressed dSYM and return that filepath in dsym_fspec. +static bool LookForDsymNextToExecutablePath(const ModuleSpec &mod_spec, + const FileSpec &exec_fspec, + FileSpec &dsym_fspec) { + ConstString filename = exec_fspec.GetFilename(); + FileSpec dsym_directory = exec_fspec; + dsym_directory.RemoveLastPathComponent(); + + std::string dsym_filename = filename.AsCString(); + dsym_filename += ".dSYM"; + dsym_directory.AppendPathComponent(dsym_filename); + dsym_directory.AppendPathComponent("Contents"); + dsym_directory.AppendPathComponent("Resources"); + dsym_directory.AppendPathComponent("DWARF"); + + if (FileSystem::Instance().Exists(dsym_directory)) { + + // See if the binary name exists in the dSYM DWARF + // subdir. + dsym_fspec = dsym_directory; + dsym_fspec.AppendPathComponent(filename.AsCString()); + if (FileSystem::Instance().Exists(dsym_fspec) && + FileAtPathContainsArchAndUUID(dsym_fspec, mod_spec.GetArchitecturePtr(), + mod_spec.GetUUIDPtr())) { + return true; + } + + // See if we have "../CF.framework" - so we'll look for + // CF.framework.dSYM/Contents/Resources/DWARF/CF + // We need to drop the last suffix after '.' to match + // 'CF' in the DWARF subdir. + std::string binary_name(filename.AsCString()); + auto last_dot = binary_name.find_last_of('.'); + if (last_dot != std::string::npos) { + binary_name.erase(last_dot); + dsym_fspec = dsym_directory; + dsym_fspec.AppendPathComponent(binary_name); + if (FileSystem::Instance().Exists(dsym_fspec) && + FileAtPathContainsArchAndUUID(dsym_fspec, + mod_spec.GetArchitecturePtr(), + mod_spec.GetUUIDPtr())) { + return true; + } + } + } + + // See if we have a .dSYM.yaa next to this executable path. + FileSpec dsym_yaa_fspec = exec_fspec; + dsym_yaa_fspec.RemoveLastPathComponent(); + std::string dsym_yaa_filename = filename.AsCString(); + dsym_yaa_filename += ".dSYM.yaa"; + dsym_yaa_fspec.AppendPathComponent(dsym_yaa_filename); + + if (FileSystem::Instance().Exists(dsym_yaa_fspec)) { + ModuleSpec mutable_mod_spec = mod_spec; + Status error; + if (PluginManager::DownloadObjectAndSymbolFile(mutable_mod_spec, error, + true) && + FileSystem::Instance().Exists(mutable_mod_spec.GetSymbolFileSpec())) { + dsym_fspec = mutable_mod_spec.GetSymbolFileSpec(); + return true; + } + } + + return false; +} + +// Given a ModuleSpec with a FileSpec and optionally uuid/architecture +// filled in, look for a .dSYM bundle next to that binary. Returns true +// if a .dSYM bundle is found, and that path is returned in the dsym_fspec +// FileSpec. +// +// This routine looks a few directory layers above the given exec_path - +// exec_path might be /System/Library/Frameworks/CF.framework/CF and the +// dSYM might be /System/Library/Frameworks/CF.framework.dSYM. +// +// If there is a .dSYM.yaa compressed archive found next to the binary, +// we'll call DownloadObjectAndSymbolFile to expand it into a plain .dSYM +static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec, + FileSpec &dsym_fspec) { + Log *log = GetLog(LLDBLog::Host); + const FileSpec &exec_fspec = module_spec.GetFileSpec(); + if (exec_fspec) { + if (::LookForDsymNextToExecutablePath(module_spec, exec_fspec, + dsym_fspec)) { + if (log) { + LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s", + dsym_fspec.GetPath().c_str()); + } + return true; + } else { + FileSpec parent_dirs = exec_fspec; + + // Remove the binary name from the FileSpec + parent_dirs.RemoveLastPathComponent(); + + // Add a ".dSYM" name to each directory component of the path, + // stripping off components. e.g. we may have a binary like + // /S/L/F/Foundation.framework/Versions/A/Foundation and + // /S/L/F/Foundation.framework.dSYM + // + // so we'll need to start with + // /S/L/F/Foundation.framework/Versions/A, add the .dSYM part to the + // "A", and if that doesn't exist, strip off the "A" and try it again + // with "Versions", etc., until we find a dSYM bundle or we've + // stripped off enough path components that there's no need to + // continue. + + for (int i = 0; i < 4; i++) { + // Does this part of the path have a "." character - could it be a + // bundle's top level directory? + const char *fn = parent_dirs.GetFilename().AsCString(); + if (fn == nullptr) + break; + if (::strchr(fn, '.') != nullptr) { + if (::LookForDsymNextToExecutablePath(module_spec, parent_dirs, + dsym_fspec)) { + if (log) { + LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s", + dsym_fspec.GetPath().c_str()); + } + return true; + } + } + parent_dirs.RemoveLastPathComponent(); + } + } + } + dsym_fspec.Clear(); + return false; +} + +static int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, + ModuleSpec &return_module_spec) { + Log *log = GetLog(LLDBLog::Host); + if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { + LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled."); + return 0; + } + + return_module_spec = module_spec; + return_module_spec.GetFileSpec().Clear(); + return_module_spec.GetSymbolFileSpec().Clear(); + + const UUID *uuid = module_spec.GetUUIDPtr(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + + int items_found = 0; + + if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || + g_dlsym_DBGCopyDSYMPropertyLists == nullptr) { + void *handle = dlopen( + "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols", + RTLD_LAZY | RTLD_LOCAL); + if (handle) { + g_dlsym_DBGCopyFullDSYMURLForUUID = + (CFURLRef(*)(CFUUIDRef, CFURLRef))dlsym(handle, + "DBGCopyFullDSYMURLForUUID"); + g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef(*)(CFURLRef))dlsym( + handle, "DBGCopyDSYMPropertyLists"); + } + } + + if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || + g_dlsym_DBGCopyDSYMPropertyLists == nullptr) { + return items_found; + } + + if (uuid && uuid->IsValid()) { + // Try and locate the dSYM file using DebugSymbols first + llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes(); + if (module_uuid.size() == 16) { + CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes( + NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3], + module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7], + module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11], + module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15])); + + if (module_uuid_ref.get()) { + CFCReleaser<CFURLRef> exec_url; + const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); + if (exec_fspec) { + char exec_cf_path[PATH_MAX]; + if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path))) + exec_url.reset(::CFURLCreateFromFileSystemRepresentation( + NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path), + FALSE)); + } + + CFCReleaser<CFURLRef> dsym_url(g_dlsym_DBGCopyFullDSYMURLForUUID( + module_uuid_ref.get(), exec_url.get())); + char path[PATH_MAX]; + + if (dsym_url.get()) { + if (::CFURLGetFileSystemRepresentation( + dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { + LLDB_LOGF(log, + "DebugSymbols framework returned dSYM path of %s for " + "UUID %s -- looking for the dSYM", + path, uuid->GetAsString().c_str()); + FileSpec dsym_filespec(path); + if (path[0] == '~') + FileSystem::Instance().Resolve(dsym_filespec); + + if (FileSystem::Instance().IsDirectory(dsym_filespec)) { + dsym_filespec = PluginManager::FindSymbolFileInBundle( + dsym_filespec, uuid, arch); + ++items_found; + } else { + ++items_found; + } + return_module_spec.GetSymbolFileSpec() = dsym_filespec; + } + + bool success = false; + if (log) { + if (::CFURLGetFileSystemRepresentation( + dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { + LLDB_LOGF(log, + "DebugSymbols framework returned dSYM path of %s for " + "UUID %s -- looking for an exec file", + path, uuid->GetAsString().c_str()); + } + } + + CFCReleaser<CFDictionaryRef> dict( + g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get())); + CFDictionaryRef uuid_dict = NULL; + if (dict.get()) { + CFCString uuid_cfstr(uuid->GetAsString().c_str()); + uuid_dict = static_cast<CFDictionaryRef>( + ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get())); + } + + // Check to see if we have the file on the local filesystem. + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { + ModuleSpec exe_spec; + exe_spec.GetFileSpec() = module_spec.GetFileSpec(); + exe_spec.GetUUID() = module_spec.GetUUID(); + ModuleSP module_sp; + module_sp.reset(new Module(exe_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(exe_spec)) { + success = true; + return_module_spec.GetFileSpec() = module_spec.GetFileSpec(); + LLDB_LOGF(log, "using original binary filepath %s for UUID %s", + module_spec.GetFileSpec().GetPath().c_str(), + uuid->GetAsString().c_str()); + ++items_found; + } + } + + // Check if the requested image is in our shared cache. + if (!success) { + SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo( + module_spec.GetFileSpec().GetPath()); + + // If we found it and it has the correct UUID, let's proceed with + // creating a module from the memory contents. + if (image_info.uuid && (!module_spec.GetUUID() || + module_spec.GetUUID() == image_info.uuid)) { + success = true; + return_module_spec.GetFileSpec() = module_spec.GetFileSpec(); + LLDB_LOGF(log, + "using binary from shared cache for filepath %s for " + "UUID %s", + module_spec.GetFileSpec().GetPath().c_str(), + uuid->GetAsString().c_str()); + ++items_found; + } + } + + // Use the DBGSymbolRichExecutable filepath if present + if (!success && uuid_dict) { + CFStringRef exec_cf_path = + static_cast<CFStringRef>(::CFDictionaryGetValue( + uuid_dict, CFSTR("DBGSymbolRichExecutable"))); + if (exec_cf_path && ::CFStringGetFileSystemRepresentation( + exec_cf_path, path, sizeof(path))) { + LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s", + path, uuid->GetAsString().c_str()); + ++items_found; + FileSpec exec_filespec(path); + if (path[0] == '~') + FileSystem::Instance().Resolve(exec_filespec); + if (FileSystem::Instance().Exists(exec_filespec)) { + success = true; + return_module_spec.GetFileSpec() = exec_filespec; + } + } + } + + // Look next to the dSYM for the binary file. + if (!success) { + if (::CFURLGetFileSystemRepresentation( + dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { + char *dsym_extension_pos = ::strstr(path, ".dSYM"); + if (dsym_extension_pos) { + *dsym_extension_pos = '\0'; + LLDB_LOGF(log, + "Looking for executable binary next to dSYM " + "bundle with name with name %s", + path); + FileSpec file_spec(path); + FileSystem::Instance().Resolve(file_spec); + ModuleSpecList module_specs; + ModuleSpec matched_module_spec; + using namespace llvm::sys::fs; + switch (get_file_type(file_spec.GetPath())) { + + case file_type::directory_file: // Bundle directory? + { + CFCBundle bundle(path); + CFCReleaser<CFURLRef> bundle_exe_url( + bundle.CopyExecutableURL()); + if (bundle_exe_url.get()) { + if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(), + true, (UInt8 *)path, + sizeof(path) - 1)) { + FileSpec bundle_exe_file_spec(path); + FileSystem::Instance().Resolve(bundle_exe_file_spec); + if (ObjectFile::GetModuleSpecifications( + bundle_exe_file_spec, 0, 0, module_specs) && + module_specs.FindMatchingModuleSpec( + module_spec, matched_module_spec)) + + { + ++items_found; + return_module_spec.GetFileSpec() = bundle_exe_file_spec; + LLDB_LOGF(log, + "Executable binary %s next to dSYM is " + "compatible; using", + path); + } + } + } + } break; + + case file_type::fifo_file: // Forget pipes + case file_type::socket_file: // We can't process socket files + case file_type::file_not_found: // File doesn't exist... + case file_type::status_error: + break; + + case file_type::type_unknown: + case file_type::regular_file: + case file_type::symlink_file: + case file_type::block_file: + case file_type::character_file: + if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0, + module_specs) && + module_specs.FindMatchingModuleSpec(module_spec, + matched_module_spec)) + + { + ++items_found; + return_module_spec.GetFileSpec() = file_spec; + LLDB_LOGF(log, + "Executable binary %s next to dSYM is " + "compatible; using", + path); + } + break; + } + } + } + } + } + } + } + } + + return items_found; +} + +std::optional<FileSpec> SymbolLocatorDebugSymbols::LocateExecutableSymbolFile( + const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { + const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + const UUID *uuid = module_spec.GetUUIDPtr(); + + LLDB_SCOPED_TIMERF( + "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", + exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", + arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); + + FileSpec symbol_fspec; + ModuleSpec dsym_module_spec; + // First try and find the dSYM in the same directory as the executable or in + // an appropriate parent directory + if (!LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec)) { + // We failed to easily find the dSYM above, so use DebugSymbols + LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec); + } else { + dsym_module_spec.GetSymbolFileSpec() = symbol_fspec; + } + + return dsym_module_spec.GetSymbolFileSpec(); +} + +static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, + ModuleSpec &module_spec, + Status &error, + const std::string &command) { + Log *log = GetLog(LLDBLog::Host); + bool success = false; + if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) { + std::string str; + CFStringRef cf_str; + CFDictionaryRef cf_dict; + + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGError")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + if (CFCString::FileSystemRepresentation(cf_str, str)) { + std::string errorstr = command; + errorstr += ":\n"; + errorstr += str; + error.SetErrorString(errorstr); + } + } + + cf_str = (CFStringRef)CFDictionaryGetValue( + (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + if (CFCString::FileSystemRepresentation(cf_str, str)) { + module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native); + FileSystem::Instance().Resolve(module_spec.GetFileSpec()); + LLDB_LOGF(log, + "From dsymForUUID plist: Symbol rich executable is at '%s'", + str.c_str()); + } + } + + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGDSYMPath")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + if (CFCString::FileSystemRepresentation(cf_str, str)) { + module_spec.GetSymbolFileSpec().SetFile(str.c_str(), + FileSpec::Style::native); + FileSystem::Instance().Resolve(module_spec.GetFileSpec()); + success = true; + LLDB_LOGF(log, "From dsymForUUID plist: dSYM is at '%s'", str.c_str()); + } + } + + std::string DBGBuildSourcePath; + std::string DBGSourcePath; + + // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping. + // If DBGVersion 2, strip last two components of path remappings from + // entries to fix an issue with a specific set of + // DBGSourcePathRemapping entries that lldb worked + // with. + // If DBGVersion 3, trust & use the source path remappings as-is. + // + cf_dict = (CFDictionaryRef)CFDictionaryGetValue( + (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping")); + if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) { + // If we see DBGVersion with a value of 2 or higher, this is a new style + // DBGSourcePathRemapping dictionary + bool new_style_source_remapping_dictionary = false; + bool do_truncate_remapping_names = false; + std::string original_DBGSourcePath_value = DBGSourcePath; + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGVersion")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + std::string version; + CFCString::FileSystemRepresentation(cf_str, version); + if (!version.empty() && isdigit(version[0])) { + int version_number = atoi(version.c_str()); + if (version_number > 1) { + new_style_source_remapping_dictionary = true; + } + if (version_number == 2) { + do_truncate_remapping_names = true; + } + } + } + + CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict); + if (kv_pair_count > 0) { + CFStringRef *keys = + (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); + CFStringRef *values = + (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); + if (keys != nullptr && values != nullptr) { + CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict, + (const void **)keys, + (const void **)values); + } + for (CFIndex i = 0; i < kv_pair_count; i++) { + DBGBuildSourcePath.clear(); + DBGSourcePath.clear(); + if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) { + CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath); + } + if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) { + CFCString::FileSystemRepresentation(values[i], DBGSourcePath); + } + if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { + // In the "old style" DBGSourcePathRemapping dictionary, the + // DBGSourcePath values (the "values" half of key-value path pairs) + // were wrong. Ignore them and use the universal DBGSourcePath + // string from earlier. + if (new_style_source_remapping_dictionary && + !original_DBGSourcePath_value.empty()) { + DBGSourcePath = original_DBGSourcePath_value; + } + if (DBGSourcePath[0] == '~') { + FileSpec resolved_source_path(DBGSourcePath.c_str()); + FileSystem::Instance().Resolve(resolved_source_path); + DBGSourcePath = resolved_source_path.GetPath(); + } + // With version 2 of DBGSourcePathRemapping, we can chop off the + // last two filename parts from the source remapping and get a more + // general source remapping that still works. Add this as another + // option in addition to the full source path remap. + module_spec.GetSourceMappingList().Append(DBGBuildSourcePath, + DBGSourcePath, true); + if (do_truncate_remapping_names) { + FileSpec build_path(DBGBuildSourcePath.c_str()); + FileSpec source_path(DBGSourcePath.c_str()); + build_path.RemoveLastPathComponent(); + build_path.RemoveLastPathComponent(); + source_path.RemoveLastPathComponent(); + source_path.RemoveLastPathComponent(); + module_spec.GetSourceMappingList().Append( + build_path.GetPath(), source_path.GetPath(), true); + } + } + } + if (keys) + free(keys); + if (values) + free(values); + } + } + + // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the + // source remappings list. + + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGBuildSourcePath")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath); + } + + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGSourcePath")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + CFCString::FileSystemRepresentation(cf_str, DBGSourcePath); + } + + if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { + if (DBGSourcePath[0] == '~') { + FileSpec resolved_source_path(DBGSourcePath.c_str()); + FileSystem::Instance().Resolve(resolved_source_path); + DBGSourcePath = resolved_source_path.GetPath(); + } + module_spec.GetSourceMappingList().Append(DBGBuildSourcePath, + DBGSourcePath, true); + } + } + return success; +} + +/// It's expensive to check for the DBGShellCommands defaults setting. Only do +/// it once per lldb run and cache the result. +static llvm::StringRef GetDbgShellCommand() { + static std::once_flag g_once_flag; + static std::string g_dbgshell_command; + std::call_once(g_once_flag, [&]() { + CFTypeRef defaults_setting = CFPreferencesCopyAppValue( + CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols")); + if (defaults_setting && + CFGetTypeID(defaults_setting) == CFStringGetTypeID()) { + char buffer[PATH_MAX]; + if (CFStringGetCString((CFStringRef)defaults_setting, buffer, + sizeof(buffer), kCFStringEncodingUTF8)) { + g_dbgshell_command = buffer; + } + } + if (defaults_setting) { + CFRelease(defaults_setting); + } + }); + return g_dbgshell_command; +} + +/// Get the dsymForUUID executable and cache the result so we don't end up +/// stat'ing the binary over and over. +static FileSpec GetDsymForUUIDExecutable() { + // The LLDB_APPLE_DSYMFORUUID_EXECUTABLE environment variable is used by the + // test suite to override the dsymForUUID location. Because we must be able + // to change the value within a single test, don't bother caching it. + if (const char *dsymForUUID_env = + getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE")) { + FileSpec dsymForUUID_executable(dsymForUUID_env); + FileSystem::Instance().Resolve(dsymForUUID_executable); + if (FileSystem::Instance().Exists(dsymForUUID_executable)) + return dsymForUUID_executable; + } + + static std::once_flag g_once_flag; + static FileSpec g_dsymForUUID_executable; + std::call_once(g_once_flag, [&]() { + // Try the DBGShellCommand. + llvm::StringRef dbgshell_command = GetDbgShellCommand(); + if (!dbgshell_command.empty()) { + g_dsymForUUID_executable = FileSpec(dbgshell_command); + FileSystem::Instance().Resolve(g_dsymForUUID_executable); + if (FileSystem::Instance().Exists(g_dsymForUUID_executable)) + return; + } + + // Try dsymForUUID in /usr/local/bin + { + g_dsymForUUID_executable = FileSpec("/usr/local/bin/dsymForUUID"); + if (FileSystem::Instance().Exists(g_dsymForUUID_executable)) + return; + } + + // We couldn't find the dsymForUUID binary. + g_dsymForUUID_executable = {}; + }); + return g_dsymForUUID_executable; +} + +bool SymbolLocatorDebugSymbols::DownloadObjectAndSymbolFile( + ModuleSpec &module_spec, Status &error, bool force_lookup, + bool copy_executable) { + const UUID *uuid_ptr = module_spec.GetUUIDPtr(); + const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr(); + + // If \a dbgshell_command is set, the user has specified + // forced symbol lookup via that command. We'll get the + // path back from GetDsymForUUIDExecutable() later. + llvm::StringRef dbgshell_command = GetDbgShellCommand(); + + // If forced lookup isn't set, by the user's \a dbgshell_command or + // by the \a force_lookup argument, exit this method. + if (!force_lookup && dbgshell_command.empty()) + return false; + + // We need a UUID or valid existing FileSpec. + if (!uuid_ptr && + (!file_spec_ptr || !FileSystem::Instance().Exists(*file_spec_ptr))) + return false; + + // We need a dsymForUUID binary or an equivalent executable/script. + FileSpec dsymForUUID_exe_spec = GetDsymForUUIDExecutable(); + if (!dsymForUUID_exe_spec) + return false; + + const std::string dsymForUUID_exe_path = dsymForUUID_exe_spec.GetPath(); + const std::string uuid_str = uuid_ptr ? uuid_ptr->GetAsString() : ""; + const std::string file_path_str = + file_spec_ptr ? file_spec_ptr->GetPath() : ""; + + Log *log = GetLog(LLDBLog::Host); + + // Create the dsymForUUID command. + StreamString command; + const char *copy_executable_arg = copy_executable ? "--copyExecutable " : ""; + if (!uuid_str.empty()) { + command.Printf("%s --ignoreNegativeCache %s%s", + dsymForUUID_exe_path.c_str(), copy_executable_arg, + uuid_str.c_str()); + LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM: %s", + dsymForUUID_exe_path.c_str(), uuid_str.c_str(), + command.GetString().data()); + } else if (!file_path_str.empty()) { + command.Printf("%s --ignoreNegativeCache %s%s", + dsymForUUID_exe_path.c_str(), copy_executable_arg, + file_path_str.c_str()); + LLDB_LOGF(log, "Calling %s with file %s to find dSYM: %s", + dsymForUUID_exe_path.c_str(), file_path_str.c_str(), + command.GetString().data()); + } else { + return false; + } + + // Invoke dsymForUUID. + int exit_status = -1; + int signo = -1; + std::string command_output; + error = Host::RunShellCommand( + command.GetData(), + FileSpec(), // current working directory + &exit_status, // Exit status + &signo, // Signal int * + &command_output, // Command output + std::chrono::seconds( + 640), // Large timeout to allow for long dsym download times + false); // Don't run in a shell (we don't need shell expansion) + + if (error.Fail() || exit_status != 0 || command_output.empty()) { + LLDB_LOGF(log, "'%s' failed (exit status: %d, error: '%s', output: '%s')", + command.GetData(), exit_status, error.AsCString(), + command_output.c_str()); + return false; + } + + CFCData data( + CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)command_output.data(), + command_output.size(), kCFAllocatorNull)); + + CFCReleaser<CFDictionaryRef> plist( + (CFDictionaryRef)::CFPropertyListCreateWithData( + NULL, data.get(), kCFPropertyListImmutable, NULL, NULL)); + + if (!plist.get()) { + LLDB_LOGF(log, "'%s' failed: output is not a valid plist", + command.GetData()); + return false; + } + + if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) { + LLDB_LOGF(log, "'%s' failed: output plist is not a valid CFDictionary", + command.GetData()); + return false; + } + + if (!uuid_str.empty()) { + CFCString uuid_cfstr(uuid_str.c_str()); + CFDictionaryRef uuid_dict = + (CFDictionaryRef)CFDictionaryGetValue(plist.get(), uuid_cfstr.get()); + return GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec, error, + command.GetData()); + } + + if (const CFIndex num_values = ::CFDictionaryGetCount(plist.get())) { + std::vector<CFStringRef> keys(num_values, NULL); + std::vector<CFDictionaryRef> values(num_values, NULL); + ::CFDictionaryGetKeysAndValues(plist.get(), NULL, + (const void **)&values[0]); + if (num_values == 1) { + return GetModuleSpecInfoFromUUIDDictionary(values[0], module_spec, error, + command.GetData()); + } + + for (CFIndex i = 0; i < num_values; ++i) { + ModuleSpec curr_module_spec; + if (GetModuleSpecInfoFromUUIDDictionary(values[i], curr_module_spec, + error, command.GetData())) { + if (module_spec.GetArchitecture().IsCompatibleMatch( + curr_module_spec.GetArchitecture())) { + module_spec = curr_module_spec; + return true; + } + } + } + } + + return false; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h new file mode 100644 index 000000000000..efbe68bc5dae --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h @@ -0,0 +1,68 @@ +//===-- SymbolLocatorDebugSymbols.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_SYMBOLLOCATOR_DEBUGSYMBOLS_SYMBOLLOCATORDEBUGSYMBOLS_H +#define LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_DEBUGSYMBOLS_SYMBOLLOCATORDEBUGSYMBOLS_H + +#include "lldb/Symbol/SymbolLocator.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class SymbolLocatorDebugSymbols : public SymbolLocator { +public: + SymbolLocatorDebugSymbols(); + + static void Initialize(); + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "DebugSymbols"; } + static llvm::StringRef GetPluginDescriptionStatic(); + + static lldb_private::SymbolLocator *CreateInstance(); + + /// PluginInterface protocol. + /// \{ + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + /// \} + + // Locate the executable file given a module specification. + // + // Locating the file should happen only on the local computer or using the + // current computers global settings. + static std::optional<ModuleSpec> + LocateExecutableObjectFile(const ModuleSpec &module_spec); + + // Locate the symbol file given a module specification. + // + // Locating the file should happen only on the local computer or using the + // current computers global settings. + static std::optional<FileSpec> + LocateExecutableSymbolFile(const ModuleSpec &module_spec, + const FileSpecList &default_search_paths); + + // Locate the object and symbol file given a module specification. + // + // Locating the file can try to download the file from a corporate build + // repository, or using any other means necessary to locate both the + // unstripped object file and the debug symbols. The force_lookup argument + // controls whether the external program is called unconditionally to find + // the symbol file, or if the user's settings are checked to see if they've + // enabled the external program before calling. + static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + Status &error, bool force_lookup, + bool copy_executable); + + static std::optional<FileSpec> + FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, const UUID *uuid, + const ArchSpec *arch); +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_DEBUGSYMBOLS_SYMBOLLOCATORDEBUGSYMBOLS_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfod.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfod.cpp new file mode 100644 index 000000000000..111be6be3652 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfod.cpp @@ -0,0 +1,142 @@ +//===-- SymbolLocatorDebuginfod.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 "SymbolLocatorDebuginfod.h" + +#include "lldb/Core/PluginManager.h" +#include "lldb/Utility/Args.h" + +#include "llvm/Debuginfod/Debuginfod.h" +#include "llvm/Debuginfod/HTTPClient.h" + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(SymbolLocatorDebuginfod) + +namespace { + +#define LLDB_PROPERTIES_symbollocatordebuginfod +#include "SymbolLocatorDebuginfodProperties.inc" + +enum { +#define LLDB_PROPERTIES_symbollocatordebuginfod +#include "SymbolLocatorDebuginfodPropertiesEnum.inc" +}; + +class PluginProperties : public Properties { +public: + static llvm::StringRef GetSettingName() { + return SymbolLocatorDebuginfod::GetPluginNameStatic(); + } + + PluginProperties() { + m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); + m_collection_sp->Initialize(g_symbollocatordebuginfod_properties); + + // We need to read the default value first to read the environment variable. + llvm::SmallVector<llvm::StringRef> urls = llvm::getDefaultDebuginfodUrls(); + Args arg_urls{urls}; + m_collection_sp->SetPropertyAtIndexFromArgs(ePropertyServerURLs, arg_urls); + + m_collection_sp->SetValueChangedCallback( + ePropertyServerURLs, [this] { ServerURLsChangedCallback(); }); + } + + Args GetDebugInfoDURLs() const { + Args urls; + m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyServerURLs, urls); + return urls; + } + +private: + void ServerURLsChangedCallback() { + m_server_urls = GetDebugInfoDURLs(); + llvm::SmallVector<llvm::StringRef> dbginfod_urls; + llvm::for_each(m_server_urls, [&](const auto &obj) { + dbginfod_urls.push_back(obj.ref()); + }); + llvm::setDefaultDebuginfodUrls(dbginfod_urls); + } + // Storage for the StringRef's used within the Debuginfod library. + Args m_server_urls; +}; + +} // namespace + +static PluginProperties &GetGlobalPluginProperties() { + static PluginProperties g_settings; + return g_settings; +} + +SymbolLocatorDebuginfod::SymbolLocatorDebuginfod() : SymbolLocator() {} + +void SymbolLocatorDebuginfod::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, + LocateExecutableObjectFile, LocateExecutableSymbolFile, nullptr, + nullptr, SymbolLocatorDebuginfod::DebuggerInitialize); + llvm::HTTPClient::initialize(); + }); +} + +void SymbolLocatorDebuginfod::DebuggerInitialize(Debugger &debugger) { + if (!PluginManager::GetSettingForSymbolLocatorPlugin( + debugger, PluginProperties::GetSettingName())) { + const bool is_global_setting = true; + PluginManager::CreateSettingForSymbolLocatorPlugin( + debugger, GetGlobalPluginProperties().GetValueProperties(), + "Properties for the Debuginfod Symbol Locator plug-in.", + is_global_setting); + } +} + +void SymbolLocatorDebuginfod::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); + llvm::HTTPClient::cleanup(); +} + +llvm::StringRef SymbolLocatorDebuginfod::GetPluginDescriptionStatic() { + return "Debuginfod symbol locator."; +} + +SymbolLocator *SymbolLocatorDebuginfod::CreateInstance() { + return new SymbolLocatorDebuginfod(); +} + +static std::optional<FileSpec> GetFileForModule( + const ModuleSpec &module_spec, + std::function<llvm::Expected<std::string>(llvm::object::BuildIDRef)> + PullFromServer) { + if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) + return {}; + const UUID &module_uuid = module_spec.GetUUID(); + if (module_uuid.IsValid() && llvm::canUseDebuginfod()) { + llvm::object::BuildID build_id(module_uuid.GetBytes()); + llvm::Expected<std::string> result = PullFromServer(build_id); + if (result) + return FileSpec(*result); + // An error here should be logged as a failure in the Debuginfod library, + // so just consume it here + consumeError(result.takeError()); + } + return {}; +} + +std::optional<ModuleSpec> SymbolLocatorDebuginfod::LocateExecutableObjectFile( + const ModuleSpec &module_spec) { + return GetFileForModule(module_spec, llvm::getCachedOrDownloadExecutable); +} + +std::optional<FileSpec> SymbolLocatorDebuginfod::LocateExecutableSymbolFile( + const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { + return GetFileForModule(module_spec, llvm::getCachedOrDownloadDebuginfo); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfod.h b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfod.h new file mode 100644 index 000000000000..0ea79fa1df2a --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfod.h @@ -0,0 +1,54 @@ +//===-- SymbolLocatorDebuginfod.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_SYMBOLLOCATOR_DEBUGINFOD_SYMBOLLOCATORDEBUGINFOD_H +#define LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_DEBUGINFOD_SYMBOLLOCATORDEBUGINFOD_H + +#include "lldb/Core/Debugger.h" +#include "lldb/Symbol/SymbolLocator.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class SymbolLocatorDebuginfod : public SymbolLocator { +public: + SymbolLocatorDebuginfod(); + + static void Initialize(); + static void Terminate(); + static void DebuggerInitialize(Debugger &debugger); + + static llvm::StringRef GetPluginNameStatic() { return "debuginfod"; } + static llvm::StringRef GetPluginDescriptionStatic(); + + static lldb_private::SymbolLocator *CreateInstance(); + + /// PluginInterface protocol. + /// \{ + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + /// \} + + // Locate the executable file given a module specification. + // + // Locating the file should happen only on the local computer or using the + // current computers global settings. + static std::optional<ModuleSpec> + LocateExecutableObjectFile(const ModuleSpec &module_spec); + + // Locate the symbol file given a module specification. + // + // Locating the file should happen only on the local computer or using the + // current computers global settings. + static std::optional<FileSpec> + LocateExecutableSymbolFile(const ModuleSpec &module_spec, + const FileSpecList &default_search_paths); +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_DEBUGINFOD_SYMBOLLOCATORDEBUGINFOD_H diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfodProperties.td b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfodProperties.td new file mode 100644 index 000000000000..1c668b001a16 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfodProperties.td @@ -0,0 +1,7 @@ +include "../../../../include/lldb/Core/PropertiesBase.td" + +let Definition = "symbollocatordebuginfod" in { + def ServerURLs : Property<"server_urls", "Array">, + ElementType<"String">, + Desc<"An ordered list of Debuginfod server URLs to query for symbols. This defaults to the contents of the DEBUGINFOD_URLS environment variable.">; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp new file mode 100644 index 000000000000..ed014f99fdb5 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp @@ -0,0 +1,239 @@ +//===-- SymbolLocatorDefault.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 "SymbolLocatorDefault.h" + +#include <cstring> +#include <optional> + +#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/Timer.h" +#include "lldb/Utility/UUID.h" + +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ThreadPool.h" + +// From MacOSX system header "mach/machine.h" +typedef int cpu_type_t; +typedef int cpu_subtype_t; + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(SymbolLocatorDefault) + +SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {} + +void SymbolLocatorDefault::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, + LocateExecutableObjectFile, LocateExecutableSymbolFile, + DownloadObjectAndSymbolFile); +} + +void SymbolLocatorDefault::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +llvm::StringRef SymbolLocatorDefault::GetPluginDescriptionStatic() { + return "Default symbol locator."; +} + +SymbolLocator *SymbolLocatorDefault::CreateInstance() { + return new SymbolLocatorDefault(); +} + +std::optional<ModuleSpec> SymbolLocatorDefault::LocateExecutableObjectFile( + const ModuleSpec &module_spec) { + const FileSpec &exec_fspec = module_spec.GetFileSpec(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + const UUID *uuid = module_spec.GetUUIDPtr(); + LLDB_SCOPED_TIMERF( + "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", + exec_fspec ? exec_fspec.GetFilename().AsCString("<NULL>") : "<NULL>", + arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); + + ModuleSpecList module_specs; + ModuleSpec matched_module_spec; + if (exec_fspec && + ObjectFile::GetModuleSpecifications(exec_fspec, 0, 0, module_specs) && + module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) { + ModuleSpec result; + result.GetFileSpec() = exec_fspec; + return result; + } + + return {}; +} + +// Keep "symbols.enable-external-lookup" description in sync with this function. +std::optional<FileSpec> SymbolLocatorDefault::LocateExecutableSymbolFile( + const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { + + FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); + if (symbol_file_spec.IsAbsolute() && + FileSystem::Instance().Exists(symbol_file_spec)) + return symbol_file_spec; + + Progress progress(llvm::formatv( + "Locating external symbol file for {0}", + module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>"))); + + FileSpecList debug_file_search_paths = default_search_paths; + + // Add module directory. + FileSpec module_file_spec = module_spec.GetFileSpec(); + // We keep the unresolved pathname if it fails. + FileSystem::Instance().ResolveSymbolicLink(module_file_spec, + module_file_spec); + + ConstString file_dir = module_file_spec.GetDirectory(); + { + FileSpec file_spec(file_dir.AsCString(".")); + FileSystem::Instance().Resolve(file_spec); + debug_file_search_paths.AppendIfUnique(file_spec); + } + + if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { + + // Add current working directory. + { + FileSpec file_spec("."); + FileSystem::Instance().Resolve(file_spec); + debug_file_search_paths.AppendIfUnique(file_spec); + } + +#ifndef _WIN32 +#if defined(__NetBSD__) + // Add /usr/libdata/debug directory. + { + FileSpec file_spec("/usr/libdata/debug"); + FileSystem::Instance().Resolve(file_spec); + debug_file_search_paths.AppendIfUnique(file_spec); + } +#else + // Add /usr/lib/debug directory. + { + FileSpec file_spec("/usr/lib/debug"); + FileSystem::Instance().Resolve(file_spec); + debug_file_search_paths.AppendIfUnique(file_spec); + } +#endif +#endif // _WIN32 + } + + std::string uuid_str; + const UUID &module_uuid = module_spec.GetUUID(); + if (module_uuid.IsValid()) { + // Some debug files are stored in the .build-id directory like this: + // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug + uuid_str = module_uuid.GetAsString(""); + std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(), + ::tolower); + uuid_str.insert(2, 1, '/'); + uuid_str = uuid_str + ".debug"; + } + + size_t num_directories = debug_file_search_paths.GetSize(); + for (size_t idx = 0; idx < num_directories; ++idx) { + FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); + FileSystem::Instance().Resolve(dirspec); + if (!FileSystem::Instance().IsDirectory(dirspec)) + continue; + + std::vector<std::string> files; + std::string dirname = dirspec.GetPath(); + + if (!uuid_str.empty()) + files.push_back(dirname + "/.build-id/" + uuid_str); + if (symbol_file_spec.GetFilename()) { + files.push_back(dirname + "/" + + symbol_file_spec.GetFilename().GetCString()); + files.push_back(dirname + "/.debug/" + + symbol_file_spec.GetFilename().GetCString()); + + // Some debug files may stored in the module directory like this: + // /usr/lib/debug/usr/lib/library.so.debug + if (!file_dir.IsEmpty()) + files.push_back(dirname + file_dir.AsCString() + "/" + + symbol_file_spec.GetFilename().GetCString()); + } + + const uint32_t num_files = files.size(); + for (size_t idx_file = 0; idx_file < num_files; ++idx_file) { + const std::string &filename = files[idx_file]; + FileSpec file_spec(filename); + FileSystem::Instance().Resolve(file_spec); + + if (llvm::sys::fs::equivalent(file_spec.GetPath(), + module_file_spec.GetPath())) + continue; + + if (FileSystem::Instance().Exists(file_spec)) { + lldb_private::ModuleSpecList specs; + const size_t num_specs = + ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs); + ModuleSpec mspec; + bool valid_mspec = false; + if (num_specs == 2) { + // Special case to handle both i386 and i686 from ObjectFilePECOFF + ModuleSpec mspec2; + if (specs.GetModuleSpecAtIndex(0, mspec) && + specs.GetModuleSpecAtIndex(1, mspec2) && + mspec.GetArchitecture().GetTriple().isCompatibleWith( + mspec2.GetArchitecture().GetTriple())) { + valid_mspec = true; + } + } + if (!valid_mspec) { + assert(num_specs <= 1 && + "Symbol Vendor supports only a single architecture"); + if (num_specs == 1) { + if (specs.GetModuleSpecAtIndex(0, mspec)) { + valid_mspec = true; + } + } + } + if (valid_mspec) { + // Skip the uuids check if module_uuid is invalid. For example, + // this happens for *.dwp files since at the moment llvm-dwp + // doesn't output build ids, nor does binutils dwp. + if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID()) + return file_spec; + } + } + } + } + + return {}; +} + +bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + Status &error, + bool force_lookup, + bool copy_executable) { + return false; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h new file mode 100644 index 000000000000..7bf0a2ad4a5b --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h @@ -0,0 +1,64 @@ +//===-- SymbolLocatorDefault.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_SYMBOLLOCATOR_DEFAULT_SYMBOLLOCATORDEFAULT_H +#define LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_DEFAULT_SYMBOLLOCATORDEFAULT_H + +#include "lldb/Symbol/SymbolLocator.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class SymbolLocatorDefault : public SymbolLocator { +public: + SymbolLocatorDefault(); + + static void Initialize(); + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "Default"; } + static llvm::StringRef GetPluginDescriptionStatic(); + + static lldb_private::SymbolLocator *CreateInstance(); + + /// PluginInterface protocol. + /// \{ + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + /// \} + + // Locate the executable file given a module specification. + // + // Locating the file should happen only on the local computer or using the + // current computers global settings. + static std::optional<ModuleSpec> + LocateExecutableObjectFile(const ModuleSpec &module_spec); + + // Locate the symbol file given a module specification. + // + // Locating the file should happen only on the local computer or using the + // current computers global settings. + static std::optional<FileSpec> + LocateExecutableSymbolFile(const ModuleSpec &module_spec, + const FileSpecList &default_search_paths); + + // Locate the object and symbol file given a module specification. + // + // Locating the file can try to download the file from a corporate build + // repository, or using any other means necessary to locate both the + // unstripped object file and the debug symbols. The force_lookup argument + // controls whether the external program is called unconditionally to find + // the symbol file, or if the user's settings are checked to see if they've + // enabled the external program before calling. + static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + Status &error, bool force_lookup, + bool copy_executable); +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_DEFAULT_SYMBOLLOCATORDEFAULT_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 55a663bb1b96..b5fe35d71032 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -16,7 +16,6 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Host/Host.h" -#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Target.h" #include "lldb/Utility/StreamString.h" @@ -87,7 +86,7 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, module_spec.GetUUID() = uuid; FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); FileSpec dsym_fspec = - Symbols::LocateExecutableSymbolFile(module_spec, search_paths); + PluginManager::LocateExecutableSymbolFile(module_spec, search_paths); if (!dsym_fspec) return nullptr; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp index 0f8d3108998d..6393363db51f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp @@ -16,7 +16,6 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Host/Host.h" -#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Target.h" #include "lldb/Utility/StreamString.h" @@ -87,7 +86,7 @@ SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP &module_sp, module_spec.GetUUID() = uuid; FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); FileSpec dsym_fspec = - Symbols::LocateExecutableSymbolFile(module_spec, search_paths); + PluginManager::LocateExecutableSymbolFile(module_spec, search_paths); if (!dsym_fspec) return nullptr; 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 91b10ea64535..f8a9389c0ff9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp @@ -17,7 +17,6 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Host/Host.h" -#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Target.h" #include "lldb/Utility/StreamString.h" @@ -87,7 +86,7 @@ SymbolVendorWasm::CreateInstance(const lldb::ModuleSP &module_sp, FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); FileSpec sym_fspec = - Symbols::LocateExecutableSymbolFile(module_spec, search_paths); + PluginManager::LocateExecutableSymbolFile(module_spec, search_paths); if (!sym_fspec) return nullptr; 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 index 254baaf3e673..82714dea3fcd 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h @@ -105,7 +105,7 @@ public: Options *GetOptions() override { return &m_options; } protected: - bool DoExecute(Args &command, CommandReturnObject &result) override; + void DoExecute(Args &command, CommandReturnObject &result) override; TraceIntelPT &m_trace; CommandOptions m_options; 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 index bcac731713bb..72e9948ffe81 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -48,8 +48,8 @@ enum { #include "TraceIntelPTPropertiesEnum.inc" }; -ConstString TraceIntelPT::PluginProperties::GetSettingName() { - return ConstString(TraceIntelPT::GetPluginNameStatic()); +llvm::StringRef TraceIntelPT::PluginProperties::GetSettingName() { + return TraceIntelPT::GetPluginNameStatic(); } TraceIntelPT::PluginProperties::PluginProperties() : Properties() { @@ -60,14 +60,14 @@ TraceIntelPT::PluginProperties::PluginProperties() : Properties() { uint64_t TraceIntelPT::PluginProperties::GetInfiniteDecodingLoopVerificationThreshold() { const uint32_t idx = ePropertyInfiniteDecodingLoopVerificationThreshold; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_traceintelpt_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_traceintelpt_properties[idx].default_uint_value); } uint64_t TraceIntelPT::PluginProperties::GetExtremelyLargeDecodingThreshold() { const uint32_t idx = ePropertyExtremelyLargeDecodingThreshold; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_traceintelpt_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_traceintelpt_properties[idx].default_uint_value); } TraceIntelPT::PluginProperties &TraceIntelPT::GetGlobalProperties() { 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 index 20faabdce790..da9cefe9ed95 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -26,7 +26,7 @@ public: /// Properties to be used with the `settings` command. class PluginProperties : public Properties { public: - static ConstString GetSettingName(); + static llvm::StringRef GetSettingName(); PluginProperties(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp index e183e592986a..bd9cca675f2d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleLoader.cpp @@ -103,10 +103,11 @@ TraceIntelPTBundleLoader::CreateEmptyProcess(lldb::pid_t pid, ParsedProcess parsed_process; parsed_process.target_sp = target_sp; - ProcessSP process_sp = target_sp->CreateProcess( - /*listener*/ nullptr, "trace", - /*crash_file*/ nullptr, - /*can_connect*/ false); + // This should instead try to directly create an instance of ProcessTrace. + // ProcessSP process_sp = target_sp->CreateProcess( + // /*listener*/ nullptr, "trace", + // /*crash_file*/ nullptr, + // /*can_connect*/ false); process_sp->SetID(static_cast<lldb::pid_t>(pid)); @@ -285,7 +286,7 @@ StringRef TraceIntelPTBundleLoader::GetSchema() { "tscPerfZeroConversion"?: { // Values used to convert between TSCs and nanoseconds. See the time_zero // section in https://man7.org/linux/man-pages/man2/perf_event_open.2.html - // for for information. + // for information. "timeMult": integer, "timeShift": integer, diff --git a/contrib/llvm-project/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp b/contrib/llvm-project/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp index 33d05ee2ac13..ee8970fb4de2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp @@ -62,7 +62,7 @@ CommandObjectThreadTraceExportCTF::CommandOptions::GetDefinitions() { return llvm::ArrayRef(g_thread_trace_export_ctf_options); } -bool CommandObjectThreadTraceExportCTF::DoExecute(Args &command, +void CommandObjectThreadTraceExportCTF::DoExecute(Args &command, CommandReturnObject &result) { const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace(); Process *process = m_exe_ctx.GetProcessPtr(); @@ -78,7 +78,6 @@ bool CommandObjectThreadTraceExportCTF::DoExecute(Args &command, result.AppendErrorWithFormatv( "Thread index {0} is out of range (valid values are 1 - {1}).\n", tid, num_threads); - return false; } else { auto do_work = [&]() -> Error { Expected<TraceCursorSP> cursor = trace_sp->CreateNewCursor(*thread); @@ -91,9 +90,6 @@ bool CommandObjectThreadTraceExportCTF::DoExecute(Args &command, if (llvm::Error err = do_work()) { result.AppendErrorWithFormat("%s\n", toString(std::move(err)).c_str()); - return false; - } else { - return true; } } } diff --git a/contrib/llvm-project/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h b/contrib/llvm-project/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h index c9f02a372ded..1a034e87cfb6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h +++ b/contrib/llvm-project/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h @@ -48,7 +48,7 @@ public: Options *GetOptions() override { return &m_options; } protected: - bool DoExecute(Args &command, CommandReturnObject &result) override; + void DoExecute(Args &command, CommandReturnObject &result) override; CommandOptions m_options; }; diff --git a/contrib/llvm-project/lldb/source/Plugins/TraceExporter/docs/htr.rst b/contrib/llvm-project/lldb/source/Plugins/TraceExporter/docs/htr.rst index 1341cf5f0c80..beee14dce25a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TraceExporter/docs/htr.rst +++ b/contrib/llvm-project/lldb/source/Plugins/TraceExporter/docs/htr.rst @@ -21,7 +21,7 @@ Concepts **Pass:** A transformation applied to a *layer* that generates a new *layer* that is a more summarized, consolidated representation of the trace data. A pass merges instructions/blocks based on its specific purpose - for example, a pass designed to summarize a processor trace by function calls would merge all the blocks of a function into a single block representing the entire function. -The image below illusrates the transformation of a trace's representation (HTR) +The image below illustrates the transformation of a trace's representation (HTR) .. image:: media/htr-example.png 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 c7430882adb5..503cbedce982 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -56,8 +56,8 @@ #include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Target/ExecutionContext.h" @@ -86,6 +86,7 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::dwarf; +using namespace lldb_private::plugin::dwarf; using namespace clang; using llvm::StringSwitch; @@ -2293,12 +2294,13 @@ CompilerType TypeSystemClang::CreateArrayType(const CompilerType &element_type, llvm::APInt ap_element_count(64, element_count); if (element_count == 0) { - return GetType(ast.getIncompleteArrayType( - ClangUtil::GetQualType(element_type), clang::ArrayType::Normal, 0)); + return GetType( + ast.getIncompleteArrayType(ClangUtil::GetQualType(element_type), + clang::ArraySizeModifier::Normal, 0)); } else { return GetType(ast.getConstantArrayType( ClangUtil::GetQualType(element_type), ap_element_count, nullptr, - clang::ArrayType::Normal, 0)); + clang::ArraySizeModifier::Normal, 0)); } } } @@ -2318,8 +2320,9 @@ CompilerType TypeSystemClang::CreateStructForIdentifier( return type; } - type = CreateRecordType(nullptr, OptionalClangModuleID(), lldb::eAccessPublic, - type_name, clang::TTK_Struct, lldb::eLanguageTypeC); + type = CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, type_name, + llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); StartTagDeclarationDefinition(type); for (const auto &field : type_fields) AddFieldToRecordType(type, field.first, field.second, lldb::eAccessPublic, @@ -2458,89 +2461,6 @@ void TypeSystemClang::DumpDeclHiearchy(clang::Decl *decl) { } } -bool TypeSystemClang::DeclsAreEquivalent(clang::Decl *lhs_decl, - clang::Decl *rhs_decl) { - if (lhs_decl && rhs_decl) { - // Make sure the decl kinds match first - const clang::Decl::Kind lhs_decl_kind = lhs_decl->getKind(); - const clang::Decl::Kind rhs_decl_kind = rhs_decl->getKind(); - - if (lhs_decl_kind == rhs_decl_kind) { - // Now check that the decl contexts kinds are all equivalent before we - // have to check any names of the decl contexts... - clang::DeclContext *lhs_decl_ctx = lhs_decl->getDeclContext(); - clang::DeclContext *rhs_decl_ctx = rhs_decl->getDeclContext(); - if (lhs_decl_ctx && rhs_decl_ctx) { - while (true) { - if (lhs_decl_ctx && rhs_decl_ctx) { - const clang::Decl::Kind lhs_decl_ctx_kind = - lhs_decl_ctx->getDeclKind(); - const clang::Decl::Kind rhs_decl_ctx_kind = - rhs_decl_ctx->getDeclKind(); - if (lhs_decl_ctx_kind == rhs_decl_ctx_kind) { - lhs_decl_ctx = lhs_decl_ctx->getParent(); - rhs_decl_ctx = rhs_decl_ctx->getParent(); - - if (lhs_decl_ctx == nullptr && rhs_decl_ctx == nullptr) - break; - } else - return false; - } else - return false; - } - - // Now make sure the name of the decls match - clang::NamedDecl *lhs_named_decl = - llvm::dyn_cast<clang::NamedDecl>(lhs_decl); - clang::NamedDecl *rhs_named_decl = - llvm::dyn_cast<clang::NamedDecl>(rhs_decl); - if (lhs_named_decl && rhs_named_decl) { - clang::DeclarationName lhs_decl_name = lhs_named_decl->getDeclName(); - clang::DeclarationName rhs_decl_name = rhs_named_decl->getDeclName(); - if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) { - if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString()) - return false; - } else - return false; - } else - return false; - - // We know that the decl context kinds all match, so now we need to - // make sure the names match as well - lhs_decl_ctx = lhs_decl->getDeclContext(); - rhs_decl_ctx = rhs_decl->getDeclContext(); - while (true) { - switch (lhs_decl_ctx->getDeclKind()) { - case clang::Decl::TranslationUnit: - // We don't care about the translation unit names - return true; - default: { - clang::NamedDecl *lhs_named_decl = - llvm::dyn_cast<clang::NamedDecl>(lhs_decl_ctx); - clang::NamedDecl *rhs_named_decl = - llvm::dyn_cast<clang::NamedDecl>(rhs_decl_ctx); - if (lhs_named_decl && rhs_named_decl) { - clang::DeclarationName lhs_decl_name = - lhs_named_decl->getDeclName(); - clang::DeclarationName rhs_decl_name = - rhs_named_decl->getDeclName(); - if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) { - if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString()) - return false; - } else - return false; - } else - return false; - } break; - } - lhs_decl_ctx = lhs_decl_ctx->getParent(); - rhs_decl_ctx = rhs_decl_ctx->getParent(); - } - } - } - } - return false; -} bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast, clang::Decl *decl) { if (!decl) @@ -2636,6 +2556,13 @@ TypeSystemClang::GetDeclContextForType(const CompilerType &type) { return GetDeclContextForType(ClangUtil::GetQualType(type)); } +CompilerDeclContext +TypeSystemClang::GetCompilerDeclContextForType(const CompilerType &type) { + if (auto *decl_context = GetDeclContextForType(type)) + return CreateDeclContext(decl_context); + return CompilerDeclContext(); +} + /// Aggressively desugar the provided type, skipping past various kinds of /// syntactic sugar and other constructs one typically wants to ignore. /// The \p mask argument allows one to skip certain kinds of simplifications, @@ -3549,8 +3476,15 @@ bool TypeSystemClang::IsPolymorphicClass(lldb::opaque_compiler_type_t type) { if (record_decl) { const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); - if (cxx_record_decl) - return cxx_record_decl->isPolymorphic(); + if (cxx_record_decl) { + // We can't just call is isPolymorphic() here because that just + // means the current class has virtual functions, it doesn't check + // if any inherited classes have virtual functions. The doc string + // in SBType::IsPolymorphicClass() says it is looking for both + // if the class has virtual methods or if any bases do, so this + // should be more correct. + return cxx_record_decl->isDynamicClass(); + } } } break; @@ -4293,10 +4227,10 @@ CompilerType TypeSystemClang::GetArrayType(lldb::opaque_compiler_type_t type, if (size != 0) return GetType(ast_ctx.getConstantArrayType( qual_type, llvm::APInt(64, size), nullptr, - clang::ArrayType::ArraySizeModifier::Normal, 0)); + clang::ArraySizeModifier::Normal, 0)); else return GetType(ast_ctx.getIncompleteArrayType( - qual_type, clang::ArrayType::ArraySizeModifier::Normal, 0)); + qual_type, clang::ArraySizeModifier::Normal, 0)); } return CompilerType(); @@ -4700,6 +4634,21 @@ TypeSystemClang::GetTypedefedType(lldb::opaque_compiler_type_t type) { CompilerType TypeSystemClang::GetBasicTypeFromAST(lldb::BasicType basic_type) { return TypeSystemClang::GetBasicType(basic_type); } + +CompilerType TypeSystemClang::CreateGenericFunctionPrototype() { + clang::ASTContext &ast = getASTContext(); + const FunctionType::ExtInfo generic_ext_info( + /*noReturn=*/false, + /*hasRegParm=*/false, + /*regParm=*/0, + CallingConv::CC_C, + /*producesResult=*/false, + /*noCallerSavedRegs=*/false, + /*NoCfCheck=*/false, + /*cmseNSCall=*/false); + QualType func_type = ast.getFunctionNoProtoType(ast.VoidTy, generic_ext_info); + return GetType(func_type); +} // Exploring the type const llvm::fltSemantics & @@ -4816,7 +4765,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::Type::FunctionNoProto: case clang::Type::FunctionProto: - break; + return lldb::eEncodingUint; case clang::Type::IncompleteArray: case clang::Type::VariableArray: @@ -5361,11 +5310,8 @@ uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, num_children += cxx_record_decl->getNumBases(); } } - clang::RecordDecl::field_iterator field, field_end; - for (field = record_decl->field_begin(), - field_end = record_decl->field_end(); - field != field_end; ++field) - ++num_children; + num_children += std::distance(record_decl->field_begin(), + record_decl->field_end()); } break; @@ -5576,13 +5522,8 @@ uint32_t TypeSystemClang::GetNumFields(lldb::opaque_compiler_type_t type) { if (record_type) { clang::RecordDecl *record_decl = record_type->getDecl(); if (record_decl) { - uint32_t field_idx = 0; - clang::RecordDecl::field_iterator field, field_end; - for (field = record_decl->field_begin(), - field_end = record_decl->field_end(); - field != field_end; ++field) - ++field_idx; - count = field_idx; + count = std::distance(record_decl->field_begin(), + record_decl->field_end()); } } } @@ -7183,7 +7124,8 @@ GetNthTemplateArgument(const clang::ClassTemplateSpecializationDecl *decl, // (including the ones preceding the parameter pack). const auto &pack = args[last_idx]; const size_t pack_idx = idx - last_idx; - assert(pack_idx < pack.pack_size() && "parameter pack index out-of-bounds"); + if (pack_idx >= pack.pack_size()) + return nullptr; return &pack.pack_elements()[pack_idx]; } @@ -7651,7 +7593,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( nullptr /*expr*/, is_explicit ? clang::ExplicitSpecKind::ResolvedTrue : clang::ExplicitSpecKind::ResolvedFalse); - if (name.startswith("~")) { + if (name.starts_with("~")) { cxx_dtor_decl = clang::CXXDestructorDecl::CreateDeserialized(getASTContext(), 0); cxx_dtor_decl->setDeclContext(cxx_record_decl); @@ -7986,8 +7928,8 @@ bool TypeSystemClang::AddObjCClassProperty( const bool isSynthesizedAccessorStub = false; const bool isImplicitlyDeclared = true; const bool isDefined = false; - const clang::ObjCMethodDecl::ImplementationControl impControl = - clang::ObjCMethodDecl::None; + const clang::ObjCImplementationControl impControl = + clang::ObjCImplementationControl::None; const bool HasRelatedResultType = false; getter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); @@ -8028,8 +7970,8 @@ bool TypeSystemClang::AddObjCClassProperty( const bool isSynthesizedAccessorStub = false; const bool isImplicitlyDeclared = true; const bool isDefined = false; - const clang::ObjCMethodDecl::ImplementationControl impControl = - clang::ObjCMethodDecl::None; + const clang::ObjCImplementationControl impControl = + clang::ObjCImplementationControl::None; const bool HasRelatedResultType = false; setter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); @@ -8085,8 +8027,8 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( const char *name, // the full symbol name as seen in the symbol table // (lldb::opaque_compiler_type_t type, "-[NString // stringWithCString:]") - const CompilerType &method_clang_type, lldb::AccessType access, - bool is_artificial, bool is_variadic, bool is_objc_direct_call) { + const CompilerType &method_clang_type, bool is_artificial, bool is_variadic, + bool is_objc_direct_call) { if (!type || !method_clang_type.IsValid()) return nullptr; @@ -8150,8 +8092,8 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( /// Force this to true because we don't have source locations. const bool isImplicitlyDeclared = true; const bool isDefined = false; - const clang::ObjCMethodDecl::ImplementationControl impControl = - clang::ObjCMethodDecl::None; + const clang::ObjCImplementationControl impControl = + clang::ObjCImplementationControl::None; const bool HasRelatedResultType = false; const unsigned num_args = method_function_prototype->getNumParams(); @@ -8520,380 +8462,6 @@ void TypeSystemClang::DumpFromSymbolFile(Stream &s, } } -void TypeSystemClang::DumpValue( - lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream &s, - lldb::Format format, const lldb_private::DataExtractor &data, - lldb::offset_t data_byte_offset, size_t data_byte_size, - uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, bool show_types, - bool show_summary, bool verbose, uint32_t depth) { - if (!type) - return; - - clang::QualType qual_type(GetQualType(type)); - switch (qual_type->getTypeClass()) { - case clang::Type::Record: - if (GetCompleteType(type)) { - const clang::RecordType *record_type = - llvm::cast<clang::RecordType>(qual_type.getTypePtr()); - const clang::RecordDecl *record_decl = record_type->getDecl(); - assert(record_decl); - uint32_t field_bit_offset = 0; - uint32_t field_byte_offset = 0; - const clang::ASTRecordLayout &record_layout = - getASTContext().getASTRecordLayout(record_decl); - uint32_t child_idx = 0; - - const clang::CXXRecordDecl *cxx_record_decl = - llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); - if (cxx_record_decl) { - // We might have base classes to print out first - clang::CXXRecordDecl::base_class_const_iterator base_class, - base_class_end; - for (base_class = cxx_record_decl->bases_begin(), - base_class_end = cxx_record_decl->bases_end(); - base_class != base_class_end; ++base_class) { - const clang::CXXRecordDecl *base_class_decl = - llvm::cast<clang::CXXRecordDecl>( - base_class->getType()->getAs<clang::RecordType>()->getDecl()); - - // Skip empty base classes - if (!verbose && !TypeSystemClang::RecordHasFields(base_class_decl)) - continue; - - if (base_class->isVirtual()) - field_bit_offset = - record_layout.getVBaseClassOffset(base_class_decl) - .getQuantity() * - 8; - else - field_bit_offset = record_layout.getBaseClassOffset(base_class_decl) - .getQuantity() * - 8; - field_byte_offset = field_bit_offset / 8; - assert(field_bit_offset % 8 == 0); - if (child_idx == 0) - s.PutChar('{'); - else - s.PutChar(','); - - clang::QualType base_class_qual_type = base_class->getType(); - std::string base_class_type_name(base_class_qual_type.getAsString()); - - // Indent and print the base class type name - s.Format("\n{0}{1}", llvm::fmt_repeat(" ", depth + DEPTH_INCREMENT), - base_class_type_name); - - clang::TypeInfo base_class_type_info = - getASTContext().getTypeInfo(base_class_qual_type); - - // Dump the value of the member - CompilerType base_clang_type = GetType(base_class_qual_type); - base_clang_type.DumpValue( - exe_ctx, - &s, // Stream to dump to - base_clang_type - .GetFormat(), // The format with which to display the member - data, // Data buffer containing all bytes for this type - data_byte_offset + field_byte_offset, // Offset into "data" where - // to grab value from - base_class_type_info.Width / 8, // Size of this type in bytes - 0, // Bitfield bit size - 0, // Bitfield bit offset - show_types, // Boolean indicating if we should show the variable - // types - show_summary, // Boolean indicating if we should show a summary - // for the current type - verbose, // Verbose output? - depth + DEPTH_INCREMENT); // Scope depth for any types that have - // children - - ++child_idx; - } - } - uint32_t field_idx = 0; - clang::RecordDecl::field_iterator field, field_end; - for (field = record_decl->field_begin(), - field_end = record_decl->field_end(); - field != field_end; ++field, ++field_idx, ++child_idx) { - // Print the starting squiggly bracket (if this is the first member) or - // comma (for member 2 and beyond) for the struct/union/class member. - if (child_idx == 0) - s.PutChar('{'); - else - s.PutChar(','); - - // Indent - s.Printf("\n%*s", depth + DEPTH_INCREMENT, ""); - - clang::QualType field_type = field->getType(); - // Print the member type if requested - // Figure out the type byte size (field_type_info.first) and alignment - // (field_type_info.second) from the AST context. - clang::TypeInfo field_type_info = - getASTContext().getTypeInfo(field_type); - assert(field_idx < record_layout.getFieldCount()); - // Figure out the field offset within the current struct/union/class - // type - field_bit_offset = record_layout.getFieldOffset(field_idx); - field_byte_offset = field_bit_offset / 8; - uint32_t field_bitfield_bit_size = 0; - uint32_t field_bitfield_bit_offset = 0; - if (FieldIsBitfield(*field, field_bitfield_bit_size)) - field_bitfield_bit_offset = field_bit_offset % 8; - - if (show_types) { - std::string field_type_name(field_type.getAsString()); - if (field_bitfield_bit_size > 0) - s.Printf("(%s:%u) ", field_type_name.c_str(), - field_bitfield_bit_size); - else - s.Printf("(%s) ", field_type_name.c_str()); - } - // Print the member name and equal sign - s.Printf("%s = ", field->getNameAsString().c_str()); - - // Dump the value of the member - CompilerType field_clang_type = GetType(field_type); - field_clang_type.DumpValue( - exe_ctx, - &s, // Stream to dump to - field_clang_type - .GetFormat(), // The format with which to display the member - data, // Data buffer containing all bytes for this type - data_byte_offset + field_byte_offset, // Offset into "data" where to - // grab value from - field_type_info.Width / 8, // Size of this type in bytes - field_bitfield_bit_size, // Bitfield bit size - field_bitfield_bit_offset, // Bitfield bit offset - show_types, // Boolean indicating if we should show the variable - // types - show_summary, // Boolean indicating if we should show a summary for - // the current type - verbose, // Verbose output? - depth + DEPTH_INCREMENT); // Scope depth for any types that have - // children - } - - // Indent the trailing squiggly bracket - if (child_idx > 0) - s.Printf("\n%*s}", depth, ""); - } - return; - - case clang::Type::Enum: - if (GetCompleteType(type)) { - const clang::EnumType *enutype = - llvm::cast<clang::EnumType>(qual_type.getTypePtr()); - const clang::EnumDecl *enum_decl = enutype->getDecl(); - assert(enum_decl); - clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; - lldb::offset_t offset = data_byte_offset; - const int64_t enum_value = data.GetMaxU64Bitfield( - &offset, data_byte_size, bitfield_bit_size, bitfield_bit_offset); - for (enum_pos = enum_decl->enumerator_begin(), - enum_end_pos = enum_decl->enumerator_end(); - enum_pos != enum_end_pos; ++enum_pos) { - if (enum_pos->getInitVal() == enum_value) { - s.Printf("%s", enum_pos->getNameAsString().c_str()); - return; - } - } - // If we have gotten here we didn't get find the enumerator in the enum - // decl, so just print the integer. - s.Printf("%" PRIi64, enum_value); - } - return; - - case clang::Type::ConstantArray: { - const clang::ConstantArrayType *array = - llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr()); - bool is_array_of_characters = false; - clang::QualType element_qual_type = array->getElementType(); - - const clang::Type *canonical_type = - element_qual_type->getCanonicalTypeInternal().getTypePtr(); - if (canonical_type) - is_array_of_characters = canonical_type->isCharType(); - - const uint64_t element_count = array->getSize().getLimitedValue(); - - clang::TypeInfo field_type_info = - getASTContext().getTypeInfo(element_qual_type); - - uint32_t element_idx = 0; - uint32_t element_offset = 0; - uint64_t element_byte_size = field_type_info.Width / 8; - uint32_t element_stride = element_byte_size; - - if (is_array_of_characters) { - s.PutChar('"'); - DumpDataExtractor(data, &s, data_byte_offset, lldb::eFormatChar, - element_byte_size, element_count, UINT32_MAX, - LLDB_INVALID_ADDRESS, 0, 0); - s.PutChar('"'); - return; - } else { - CompilerType element_clang_type = GetType(element_qual_type); - lldb::Format element_format = element_clang_type.GetFormat(); - - for (element_idx = 0; element_idx < element_count; ++element_idx) { - // Print the starting squiggly bracket (if this is the first member) or - // comman (for member 2 and beyong) for the struct/union/class member. - if (element_idx == 0) - s.PutChar('{'); - else - s.PutChar(','); - - // Indent and print the index - s.Printf("\n%*s[%u] ", depth + DEPTH_INCREMENT, "", element_idx); - - // Figure out the field offset within the current struct/union/class - // type - element_offset = element_idx * element_stride; - - // Dump the value of the member - element_clang_type.DumpValue( - exe_ctx, - &s, // Stream to dump to - element_format, // The format with which to display the element - data, // Data buffer containing all bytes for this type - data_byte_offset + - element_offset, // Offset into "data" where to grab value from - element_byte_size, // Size of this type in bytes - 0, // Bitfield bit size - 0, // Bitfield bit offset - show_types, // Boolean indicating if we should show the variable - // types - show_summary, // Boolean indicating if we should show a summary for - // the current type - verbose, // Verbose output? - depth + DEPTH_INCREMENT); // Scope depth for any types that have - // children - } - - // Indent the trailing squiggly bracket - if (element_idx > 0) - s.Printf("\n%*s}", depth, ""); - } - } - return; - - case clang::Type::Typedef: { - clang::QualType typedef_qual_type = - llvm::cast<clang::TypedefType>(qual_type) - ->getDecl() - ->getUnderlyingType(); - - CompilerType typedef_clang_type = GetType(typedef_qual_type); - lldb::Format typedef_format = typedef_clang_type.GetFormat(); - clang::TypeInfo typedef_type_info = - getASTContext().getTypeInfo(typedef_qual_type); - uint64_t typedef_byte_size = typedef_type_info.Width / 8; - - return typedef_clang_type.DumpValue( - exe_ctx, - &s, // Stream to dump to - typedef_format, // The format with which to display the element - data, // Data buffer containing all bytes for this type - data_byte_offset, // Offset into "data" where to grab value from - typedef_byte_size, // Size of this type in bytes - bitfield_bit_size, // Bitfield bit size - bitfield_bit_offset, // Bitfield bit offset - show_types, // Boolean indicating if we should show the variable types - show_summary, // Boolean indicating if we should show a summary for the - // current type - verbose, // Verbose output? - depth); // Scope depth for any types that have children - } break; - - case clang::Type::Auto: { - clang::QualType elaborated_qual_type = - llvm::cast<clang::AutoType>(qual_type)->getDeducedType(); - CompilerType elaborated_clang_type = GetType(elaborated_qual_type); - lldb::Format elaborated_format = elaborated_clang_type.GetFormat(); - clang::TypeInfo elaborated_type_info = - getASTContext().getTypeInfo(elaborated_qual_type); - uint64_t elaborated_byte_size = elaborated_type_info.Width / 8; - - return elaborated_clang_type.DumpValue( - exe_ctx, - &s, // Stream to dump to - elaborated_format, // The format with which to display the element - data, // Data buffer containing all bytes for this type - data_byte_offset, // Offset into "data" where to grab value from - elaborated_byte_size, // Size of this type in bytes - bitfield_bit_size, // Bitfield bit size - bitfield_bit_offset, // Bitfield bit offset - show_types, // Boolean indicating if we should show the variable types - show_summary, // Boolean indicating if we should show a summary for the - // current type - verbose, // Verbose output? - depth); // Scope depth for any types that have children - } break; - - case clang::Type::Elaborated: { - clang::QualType elaborated_qual_type = - llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType(); - CompilerType elaborated_clang_type = GetType(elaborated_qual_type); - lldb::Format elaborated_format = elaborated_clang_type.GetFormat(); - clang::TypeInfo elaborated_type_info = - getASTContext().getTypeInfo(elaborated_qual_type); - uint64_t elaborated_byte_size = elaborated_type_info.Width / 8; - - return elaborated_clang_type.DumpValue( - exe_ctx, - &s, // Stream to dump to - elaborated_format, // The format with which to display the element - data, // Data buffer containing all bytes for this type - data_byte_offset, // Offset into "data" where to grab value from - elaborated_byte_size, // Size of this type in bytes - bitfield_bit_size, // Bitfield bit size - bitfield_bit_offset, // Bitfield bit offset - show_types, // Boolean indicating if we should show the variable types - show_summary, // Boolean indicating if we should show a summary for the - // current type - verbose, // Verbose output? - depth); // Scope depth for any types that have children - } break; - - case clang::Type::Paren: { - clang::QualType desugar_qual_type = - llvm::cast<clang::ParenType>(qual_type)->desugar(); - CompilerType desugar_clang_type = GetType(desugar_qual_type); - - lldb::Format desugar_format = desugar_clang_type.GetFormat(); - clang::TypeInfo desugar_type_info = - getASTContext().getTypeInfo(desugar_qual_type); - uint64_t desugar_byte_size = desugar_type_info.Width / 8; - - return desugar_clang_type.DumpValue( - exe_ctx, - &s, // Stream to dump to - desugar_format, // The format with which to display the element - data, // Data buffer containing all bytes for this type - data_byte_offset, // Offset into "data" where to grab value from - desugar_byte_size, // Size of this type in bytes - bitfield_bit_size, // Bitfield bit size - bitfield_bit_offset, // Bitfield bit offset - show_types, // Boolean indicating if we should show the variable types - show_summary, // Boolean indicating if we should show a summary for the - // current type - verbose, // Verbose output? - depth); // Scope depth for any types that have children - } break; - - default: - // We are down to a scalar type that we just need to display. - DumpDataExtractor(data, &s, data_byte_offset, format, data_byte_size, 1, - UINT32_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size, - bitfield_bit_offset); - - if (show_summary) - DumpSummary(type, exe_ctx, s, data, data_byte_offset, data_byte_size); - break; - } -} - static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s, const DataExtractor &data, lldb::offset_t byte_offset, size_t byte_size, uint32_t bitfield_bit_offset, @@ -9099,51 +8667,6 @@ bool TypeSystemClang::DumpTypeValue( return false; } -void TypeSystemClang::DumpSummary(lldb::opaque_compiler_type_t type, - ExecutionContext *exe_ctx, Stream &s, - const lldb_private::DataExtractor &data, - lldb::offset_t data_byte_offset, - size_t data_byte_size) { - uint32_t length = 0; - if (IsCStringType(type, length)) { - if (exe_ctx) { - Process *process = exe_ctx->GetProcessPtr(); - if (process) { - lldb::offset_t offset = data_byte_offset; - lldb::addr_t pointer_address = data.GetMaxU64(&offset, data_byte_size); - std::vector<uint8_t> buf; - if (length > 0) - buf.resize(length); - else - buf.resize(256); - - DataExtractor cstr_data(&buf.front(), buf.size(), - process->GetByteOrder(), 4); - buf.back() = '\0'; - size_t bytes_read; - size_t total_cstr_len = 0; - Status error; - while ((bytes_read = process->ReadMemory(pointer_address, &buf.front(), - buf.size(), error)) > 0) { - const size_t len = strlen((const char *)&buf.front()); - if (len == 0) - break; - if (total_cstr_len == 0) - s.PutCString(" \""); - DumpDataExtractor(cstr_data, &s, 0, lldb::eFormatChar, 1, len, - UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0); - total_cstr_len += len; - if (len < buf.size()) - break; - pointer_address += total_cstr_len; - } - if (total_cstr_len > 0) - s.PutChar('"'); - } - } - } -} - void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type, lldb::DescriptionLevel level) { StreamFile s(stdout, false); @@ -9468,6 +8991,66 @@ size_t TypeSystemClang::DeclGetFunctionNumArguments(void *opaque_decl) { return 0; } +static CompilerContextKind GetCompilerKind(clang::Decl::Kind clang_kind, + clang::DeclContext const *decl_ctx) { + switch (clang_kind) { + case Decl::TranslationUnit: + return CompilerContextKind::TranslationUnit; + case Decl::Namespace: + return CompilerContextKind::Namespace; + case Decl::Var: + return CompilerContextKind::Variable; + case Decl::Enum: + return CompilerContextKind::Enum; + case Decl::Typedef: + return CompilerContextKind::Typedef; + default: + // Many other kinds have multiple values + if (decl_ctx) { + if (decl_ctx->isFunctionOrMethod()) + return CompilerContextKind::Function; + else if (decl_ctx->isRecord()) + return (CompilerContextKind)((uint16_t)CompilerContextKind::Class | + (uint16_t)CompilerContextKind::Struct | + (uint16_t)CompilerContextKind::Union); + } + break; + } + return CompilerContextKind::Any; +} + +static void +InsertCompilerContext(TypeSystemClang *ts, clang::DeclContext *decl_ctx, + std::vector<lldb_private::CompilerContext> &context) { + if (decl_ctx == nullptr) + return; + InsertCompilerContext(ts, decl_ctx->getParent(), context); + clang::Decl::Kind clang_kind = decl_ctx->getDeclKind(); + if (clang_kind == Decl::TranslationUnit) + return; // Stop at the translation unit. + const CompilerContextKind compiler_kind = + GetCompilerKind(clang_kind, decl_ctx); + ConstString decl_ctx_name = ts->DeclContextGetName(decl_ctx); + context.push_back({compiler_kind, decl_ctx_name}); +} + +std::vector<lldb_private::CompilerContext> +TypeSystemClang::DeclGetCompilerContext(void *opaque_decl) { + std::vector<lldb_private::CompilerContext> context; + ConstString decl_name = DeclGetName(opaque_decl); + if (decl_name) { + clang::Decl *decl = (clang::Decl *)opaque_decl; + // Add the entire decl context first + clang::DeclContext *decl_ctx = decl->getDeclContext(); + InsertCompilerContext(this, decl_ctx, context); + // Now add the decl information + auto compiler_kind = + GetCompilerKind(decl->getKind(), dyn_cast<DeclContext>(decl)); + context.push_back({compiler_kind, decl_name}); + } + return context; +} + CompilerType TypeSystemClang::DeclGetFunctionArgumentType(void *opaque_decl, size_t idx) { if (clang::FunctionDecl *func_decl = @@ -9706,6 +9289,14 @@ bool TypeSystemClang::DeclContextIsClassMethod(void *opaque_decl_ctx) { return false; } +std::vector<lldb_private::CompilerContext> +TypeSystemClang::DeclContextGetCompilerContext(void *opaque_decl_ctx) { + auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; + std::vector<lldb_private::CompilerContext> context; + InsertCompilerContext(this, decl_ctx, context); + return context; +} + bool TypeSystemClang::DeclContextIsContainedInLookup( void *opaque_decl_ctx, void *other_opaque_decl_ctx) { auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; 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 3105e5b2e80f..878ab8f01e61 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -183,8 +183,6 @@ public: static void DumpDeclContextHiearchy(clang::DeclContext *decl_ctx); - static bool DeclsAreEquivalent(clang::Decl *lhs_decl, clang::Decl *rhs_decl); - static bool GetCompleteDecl(clang::ASTContext *ast, clang::Decl *decl); void SetMetadataAsUserID(const clang::Decl *decl, lldb::user_id_t user_id); @@ -219,6 +217,9 @@ public: static clang::DeclContext *GetDeclContextForType(const CompilerType &type); + CompilerDeclContext + GetCompilerDeclContextForType(const CompilerType &type) override; + uint32_t GetPointerByteSize() override; clang::TranslationUnitDecl *GetTranslationUnitDecl() { @@ -514,7 +515,7 @@ public: size_t bit_size); // TypeSystem methods - DWARFASTParser *GetDWARFParser() override; + plugin::dwarf::DWARFASTParser *GetDWARFParser() override; #ifdef LLDB_ENABLE_ALL PDBASTParser *GetPDBParser() override; npdb::PdbAstBuilder *GetNativePDBParser() override; @@ -557,6 +558,9 @@ public: CompilerType DeclGetFunctionArgumentType(void *opaque_decl, size_t arg_idx) override; + std::vector<lldb_private::CompilerContext> + DeclGetCompilerContext(void *opaque_decl) override; + CompilerType GetTypeForDecl(void *opaque_decl) override; // CompilerDeclContext override functions @@ -586,6 +590,9 @@ public: lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) override; + std::vector<lldb_private::CompilerContext> + DeclContextGetCompilerContext(void *opaque_decl_ctx) override; + // Clang specific clang::DeclContext functions static clang::DeclContext * @@ -634,8 +641,7 @@ public: bool IsConst(lldb::opaque_compiler_type_t type) override; - bool IsCStringType(lldb::opaque_compiler_type_t type, - uint32_t &length) override; + bool IsCStringType(lldb::opaque_compiler_type_t type, uint32_t &length); static bool IsCXXClassType(const CompilerType &type); @@ -802,6 +808,10 @@ public: // Create related types using the current type's AST CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override; + // Create a generic function prototype that can be used in ValuObject types + // to correctly display a function pointer with the right value and summary. + CompilerType CreateGenericFunctionPrototype() override; + // Exploring the type const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override; @@ -981,8 +991,8 @@ public: const char *name, // the full symbol name as seen in the symbol table // (lldb::opaque_compiler_type_t type, "-[NString // stringWithCString:]") - const CompilerType &method_compiler_type, lldb::AccessType access, - bool is_artificial, bool is_variadic, bool is_objc_direct_call); + const CompilerType &method_compiler_type, bool is_artificial, + bool is_variadic, bool is_objc_direct_call); static bool SetHasExternalStorage(lldb::opaque_compiler_type_t type, bool has_extern); @@ -1031,23 +1041,12 @@ public: /// The name of the symbol to dump, if it is empty dump all the symbols void DumpFromSymbolFile(Stream &s, llvm::StringRef symbol_name); - void DumpValue(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, - Stream &s, lldb::Format format, const DataExtractor &data, - lldb::offset_t data_offset, size_t data_byte_size, - uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, - bool show_types, bool show_summary, bool verbose, - uint32_t depth) override; - bool DumpTypeValue(lldb::opaque_compiler_type_t type, Stream &s, lldb::Format format, const DataExtractor &data, lldb::offset_t data_offset, size_t data_byte_size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, ExecutionContextScope *exe_scope) override; - void DumpSummary(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, - Stream &s, const DataExtractor &data, - lldb::offset_t data_offset, size_t data_byte_size) override; - void DumpTypeDescription( lldb::opaque_compiler_type_t type, lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override; |