diff options
Diffstat (limited to 'lldb/source/Plugins')
603 files changed, 25778 insertions, 24154 deletions
diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp new file mode 100644 index 000000000000..5cf9fb4ad37f --- /dev/null +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -0,0 +1,52 @@ +//===-- AArch66.h ---------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ABIAArch64.h" +#include "ABIMacOSX_arm64.h" +#include "ABISysV_arm64.h" +#include "Utility/ARM64_DWARF_Registers.h" +#include "lldb/Core/PluginManager.h" + +LLDB_PLUGIN_DEFINE(ABIAArch64) + +void ABIAArch64::Initialize() { + ABISysV_arm64::Initialize(); + ABIMacOSX_arm64::Initialize(); +} + +void ABIAArch64::Terminate() { + ABISysV_arm64::Terminate(); + ABIMacOSX_arm64::Terminate(); +} + +std::pair<uint32_t, uint32_t> +ABIAArch64::GetEHAndDWARFNums(llvm::StringRef name) { + if (name == "pc") + return {LLDB_INVALID_REGNUM, arm64_dwarf::pc}; + if (name == "cpsr") + return {LLDB_INVALID_REGNUM, arm64_dwarf::cpsr}; + return MCBasedABI::GetEHAndDWARFNums(name); +} + +uint32_t ABIAArch64::GetGenericNum(llvm::StringRef name) { + return llvm::StringSwitch<uint32_t>(name) + .Case("pc", LLDB_REGNUM_GENERIC_PC) + .Case("lr", LLDB_REGNUM_GENERIC_RA) + .Case("sp", LLDB_REGNUM_GENERIC_SP) + .Case("fp", LLDB_REGNUM_GENERIC_FP) + .Case("cpsr", LLDB_REGNUM_GENERIC_FLAGS) + .Case("x0", LLDB_REGNUM_GENERIC_ARG1) + .Case("x1", LLDB_REGNUM_GENERIC_ARG2) + .Case("x2", LLDB_REGNUM_GENERIC_ARG3) + .Case("x3", LLDB_REGNUM_GENERIC_ARG4) + .Case("x4", LLDB_REGNUM_GENERIC_ARG5) + .Case("x5", LLDB_REGNUM_GENERIC_ARG6) + .Case("x6", LLDB_REGNUM_GENERIC_ARG7) + .Case("x7", LLDB_REGNUM_GENERIC_ARG8) + .Default(LLDB_INVALID_REGNUM); +} diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h new file mode 100644 index 000000000000..981145e2017e --- /dev/null +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h @@ -0,0 +1,32 @@ +//===-- AArch64.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_ABI_AARCH64_ABIAARCH64_H +#define LLDB_SOURCE_PLUGINS_ABI_AARCH64_ABIAARCH64_H + +#include "lldb/Target/ABI.h" + +class ABIAArch64: public lldb_private::MCBasedABI { +public: + static void Initialize(); + static void Terminate(); + +protected: + std::pair<uint32_t, uint32_t> + GetEHAndDWARFNums(llvm::StringRef name) override; + + std::string GetMCName(std::string reg) override { + MapRegisterName(reg, "v", "q"); + return reg; + } + + uint32_t GetGenericNum(llvm::StringRef name) override; + + using lldb_private::MCBasedABI::MCBasedABI; +}; +#endif diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp new file mode 100644 index 000000000000..983da26a2a6d --- /dev/null +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp @@ -0,0 +1,831 @@ +//===-- ABIMacOSX_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 "ABIMacOSX_arm64.h" + +#include <vector> + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" +#include "lldb/Utility/Status.h" + +#include "Utility/ARM64_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +static const char *pluginDesc = "Mac OS X ABI for arm64 targets"; + +size_t ABIMacOSX_arm64::GetRedZoneSize() const { return 128; } + +// Static Functions + +ABISP +ABIMacOSX_arm64::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) { + const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch(); + const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor(); + + if (vendor_type == llvm::Triple::Apple) { + if (arch_type == llvm::Triple::aarch64 || + arch_type == llvm::Triple::aarch64_32) { + return ABISP( + new ABIMacOSX_arm64(std::move(process_sp), MakeMCRegisterInfo(arch))); + } + } + + return ABISP(); +} + +bool ABIMacOSX_arm64::PrepareTrivialCall( + Thread &thread, lldb::addr_t sp, lldb::addr_t func_addr, + lldb::addr_t return_addr, llvm::ArrayRef<lldb::addr_t> args) const { + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (log) { + StreamString s; + s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%d = 0x%" PRIx64, static_cast<int>(i + 1), args[i]); + s.PutCString(")"); + log->PutString(s.GetString()); + } + + const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + + // x0 - x7 contain first 8 simple args + if (args.size() > 8) // TODO handle more than 6 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); + LLDB_LOGF(log, "About to write arg%d (0x%" PRIx64 ") into %s", + static_cast<int>(i + 1), args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // Set "lr" to the return address + if (!reg_ctx->WriteRegisterFromUnsigned( + reg_ctx->GetRegisterInfoAtIndex(ra_reg_num), return_addr)) + return false; + + // Set "sp" to the requested value + if (!reg_ctx->WriteRegisterFromUnsigned( + reg_ctx->GetRegisterInfoAtIndex(sp_reg_num), sp)) + return false; + + // Set "pc" to the address requested + if (!reg_ctx->WriteRegisterFromUnsigned( + reg_ctx->GetRegisterInfoAtIndex(pc_reg_num), func_addr)) + return false; + + return true; +} + +bool ABIMacOSX_arm64::GetArgumentValues(Thread &thread, + ValueList &values) const { + uint32_t num_values = values.GetSize(); + + ExecutionContext exe_ctx(thread.shared_from_this()); + + // Extract the register context so we can read arguments from registers + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + + if (!reg_ctx) + return false; + + addr_t sp = 0; + + for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? + Value *value = values.GetValueAtIndex(value_idx); + + if (!value) + return false; + + CompilerType value_type = value->GetCompilerType(); + llvm::Optional<uint64_t> bit_size = value_type.GetBitSize(&thread); + if (!bit_size) + return false; + + bool is_signed = false; + size_t bit_width = 0; + if (value_type.IsIntegerOrEnumerationType(is_signed)) { + bit_width = *bit_size; + } else if (value_type.IsPointerOrReferenceType()) { + bit_width = *bit_size; + } else { + // We only handle integer, pointer and reference types currently... + return false; + } + + if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) { + if (value_idx < 8) { + // Arguments 1-6 are in x0-x5... + const RegisterInfo *reg_info = nullptr; + // Search by generic ID first, then fall back to by name + uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx); + if (arg_reg_num != LLDB_INVALID_REGNUM) { + reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num); + } else { + switch (value_idx) { + case 0: + reg_info = reg_ctx->GetRegisterInfoByName("x0"); + break; + case 1: + reg_info = reg_ctx->GetRegisterInfoByName("x1"); + break; + case 2: + reg_info = reg_ctx->GetRegisterInfoByName("x2"); + break; + case 3: + reg_info = reg_ctx->GetRegisterInfoByName("x3"); + break; + case 4: + reg_info = reg_ctx->GetRegisterInfoByName("x4"); + break; + case 5: + reg_info = reg_ctx->GetRegisterInfoByName("x5"); + break; + case 6: + reg_info = reg_ctx->GetRegisterInfoByName("x6"); + break; + case 7: + reg_info = reg_ctx->GetRegisterInfoByName("x7"); + break; + } + } + + if (reg_info) { + RegisterValue reg_value; + + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + if (is_signed) + reg_value.SignExtend(bit_width); + if (!reg_value.GetScalarValue(value->GetScalar())) + return false; + continue; + } + } + return false; + } else { + if (sp == 0) { + // Read the stack pointer if we already haven't read it + sp = reg_ctx->GetSP(0); + if (sp == 0) + return false; + } + + // Arguments 5 on up are on the stack + const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8; + Status error; + if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory( + sp, arg_byte_size, is_signed, value->GetScalar(), error)) + return false; + + sp += arg_byte_size; + // Align up to the next 8 byte boundary if needed + if (sp % 8) { + sp >>= 3; + sp += 1; + sp <<= 3; + } + } + } + } + return true; +} + +Status +ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, + lldb::ValueObjectSP &new_value_sp) { + Status error; + if (!new_value_sp) { + error.SetErrorString("Empty value object for return value."); + return error; + } + + CompilerType return_value_type = new_value_sp->GetCompilerType(); + if (!return_value_type) { + error.SetErrorString("Null clang type for return value."); + return error; + } + + Thread *thread = frame_sp->GetThread().get(); + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + if (reg_ctx) { + DataExtractor data; + Status data_error; + const uint64_t byte_size = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) { + error.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", + data_error.AsCString()); + return error; + } + + const uint32_t type_flags = return_value_type.GetTypeInfo(nullptr); + if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { + if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { + // Extract the register context so we can read arguments from registers + lldb::offset_t offset = 0; + if (byte_size <= 16) { + const RegisterInfo *x0_info = reg_ctx->GetRegisterInfoByName("x0", 0); + if (byte_size <= 8) { + uint64_t raw_value = data.GetMaxU64(&offset, byte_size); + + if (!reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) + error.SetErrorString("failed to write register x0"); + } else { + uint64_t raw_value = data.GetMaxU64(&offset, 8); + + if (reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) { + const RegisterInfo *x1_info = + reg_ctx->GetRegisterInfoByName("x1", 0); + raw_value = data.GetMaxU64(&offset, byte_size - offset); + + if (!reg_ctx->WriteRegisterFromUnsigned(x1_info, raw_value)) + error.SetErrorString("failed to write register x1"); + } + } + } else { + error.SetErrorString("We don't support returning longer than 128 bit " + "integer values at present."); + } + } else if (type_flags & eTypeIsFloat) { + if (type_flags & eTypeIsComplex) { + // Don't handle complex yet. + error.SetErrorString( + "returning complex float values are not supported"); + } else { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) { + if (byte_size <= 16) { + if (byte_size <= RegisterValue::GetMaxByteSize()) { + RegisterValue reg_value; + error = reg_value.SetValueFromData(v0_info, data, 0, true); + if (error.Success()) { + if (!reg_ctx->WriteRegister(v0_info, reg_value)) + error.SetErrorString("failed to write register v0"); + } + } else { + error.SetErrorStringWithFormat( + "returning float values with a byte size of %" PRIu64 + " are not supported", + byte_size); + } + } else { + error.SetErrorString("returning float values longer than 128 " + "bits are not supported"); + } + } else { + error.SetErrorString("v0 register is not available on this target"); + } + } + } + } else if (type_flags & eTypeIsVector) { + if (byte_size > 0) { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) { + if (byte_size <= v0_info->byte_size) { + RegisterValue reg_value; + error = reg_value.SetValueFromData(v0_info, data, 0, true); + if (error.Success()) { + if (!reg_ctx->WriteRegister(v0_info, reg_value)) + error.SetErrorString("failed to write register v0"); + } + } + } + } + } + } else { + error.SetErrorString("no registers are available"); + } + + return error; +} + +bool ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + uint32_t lr_reg_num = arm64_dwarf::lr; + uint32_t sp_reg_num = arm64_dwarf::sp; + uint32_t pc_reg_num = arm64_dwarf::pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our previous Call Frame Address is the stack pointer + row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); + + // Our previous PC is in the LR + row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); + + unwind_plan.AppendRow(row); + + // All other registers are the same. + + unwind_plan.SetSourceName("arm64 at-func-entry default"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + + return true; +} + +bool ABIMacOSX_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + uint32_t fp_reg_num = arm64_dwarf::fp; + uint32_t pc_reg_num = arm64_dwarf::pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + const int32_t ptr_size = 8; + + row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); + row->SetOffset(0); + + row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); + + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("arm64-apple-darwin default unwind plan"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); + return true; +} + +// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says +// registers x19 through x28 and sp are callee preserved. v8-v15 are non- +// volatile (and specifically only the lower 8 bytes of these regs), the rest +// of the fp/SIMD registers are volatile. +// +// v. https://github.com/ARM-software/abi-aa/blob/master/aapcs64/ + +// We treat x29 as callee preserved also, else the unwinder won't try to +// retrieve fp saves. + +bool ABIMacOSX_arm64::RegisterIsVolatile(const RegisterInfo *reg_info) { + if (reg_info) { + const char *name = reg_info->name; + + // Sometimes we'll be called with the "alternate" name for these registers; + // recognize them as non-volatile. + + if (name[0] == 'p' && name[1] == 'c') // pc + return false; + if (name[0] == 'f' && name[1] == 'p') // fp + return false; + if (name[0] == 's' && name[1] == 'p') // sp + return false; + if (name[0] == 'l' && name[1] == 'r') // lr + return false; + + if (name[0] == 'x') { + // Volatile registers: x0-x18, x30 (lr) + // Return false for the non-volatile gpr regs, true for everything else + switch (name[1]) { + case '1': + switch (name[2]) { + case '9': + return false; // x19 is non-volatile + default: + return true; + } + break; + case '2': + switch (name[2]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + return false; // x20 - 28 are non-volatile + case '9': + return false; // x29 aka fp treat as non-volatile on Darwin + default: + return true; + } + case '3': // x30 aka lr treat as non-volatile + if (name[2] == '0') + return false; + break; + default: + return true; + } + } else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd') { + // Volatile registers: v0-7, v16-v31 + // Return false for non-volatile fp/SIMD regs, true for everything else + switch (name[1]) { + case '8': + case '9': + return false; // v8-v9 are non-volatile + case '1': + switch (name[2]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + return false; // v10-v15 are non-volatile + default: + return true; + } + default: + return true; + } + } + } + return true; +} + +static bool LoadValueFromConsecutiveGPRRegisters( + ExecutionContext &exe_ctx, RegisterContext *reg_ctx, + const CompilerType &value_type, + bool is_return_value, // false => parameter, true => return value + uint32_t &NGRN, // NGRN (see ABI documentation) + uint32_t &NSRN, // NSRN (see ABI documentation) + DataExtractor &data) { + llvm::Optional<uint64_t> byte_size = value_type.GetByteSize(nullptr); + if (!byte_size || *byte_size == 0) + return false; + + std::unique_ptr<DataBufferHeap> heap_data_up( + new DataBufferHeap(*byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + Status error; + + CompilerType base_type; + const uint32_t homogeneous_count = + value_type.IsHomogeneousAggregate(&base_type); + if (homogeneous_count > 0 && homogeneous_count <= 8) { + // Make sure we have enough registers + if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { + if (!base_type) + return false; + llvm::Optional<uint64_t> base_byte_size = base_type.GetByteSize(nullptr); + if (!base_byte_size) + return false; + uint32_t data_offset = 0; + + for (uint32_t i = 0; i < homogeneous_count; ++i) { + char v_name[8]; + ::snprintf(v_name, sizeof(v_name), "v%u", NSRN); + const RegisterInfo *reg_info = + reg_ctx->GetRegisterInfoByName(v_name, 0); + if (reg_info == nullptr) + return false; + + if (*base_byte_size > reg_info->byte_size) + return false; + + RegisterValue reg_value; + + if (!reg_ctx->ReadRegister(reg_info, reg_value)) + return false; + + // Make sure we have enough room in "heap_data_up" + if ((data_offset + *base_byte_size) <= heap_data_up->GetByteSize()) { + const size_t bytes_copied = reg_value.GetAsMemoryData( + reg_info, heap_data_up->GetBytes() + data_offset, *base_byte_size, + byte_order, error); + if (bytes_copied != *base_byte_size) + return false; + data_offset += bytes_copied; + ++NSRN; + } else + return false; + } + data.SetByteOrder(byte_order); + data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); + data.SetData(DataBufferSP(heap_data_up.release())); + return true; + } + } + + const size_t max_reg_byte_size = 16; + if (*byte_size <= max_reg_byte_size) { + size_t bytes_left = *byte_size; + uint32_t data_offset = 0; + while (data_offset < *byte_size) { + if (NGRN >= 8) + return false; + + uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); + if (reg_num == LLDB_INVALID_REGNUM) + return false; + + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); + if (reg_info == nullptr) + return false; + + RegisterValue reg_value; + + if (!reg_ctx->ReadRegister(reg_info, reg_value)) + return false; + + const size_t curr_byte_size = std::min<size_t>(8, bytes_left); + const size_t bytes_copied = reg_value.GetAsMemoryData( + reg_info, heap_data_up->GetBytes() + data_offset, curr_byte_size, + byte_order, error); + if (bytes_copied == 0) + return false; + if (bytes_copied >= bytes_left) + break; + data_offset += bytes_copied; + bytes_left -= bytes_copied; + ++NGRN; + } + } else { + const RegisterInfo *reg_info = nullptr; + if (is_return_value) { + // We are assuming we are decoding this immediately after returning from + // a function call and that the address of the structure is in x8 + reg_info = reg_ctx->GetRegisterInfoByName("x8", 0); + } else { + // We are assuming we are stopped at the first instruction in a function + // and that the ABI is being respected so all parameters appear where + // they should be (functions with no external linkage can legally violate + // the ABI). + if (NGRN >= 8) + return false; + + uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); + if (reg_num == LLDB_INVALID_REGNUM) + return false; + reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); + if (reg_info == nullptr) + return false; + ++NGRN; + } + + if (reg_info == nullptr) + return false; + + const lldb::addr_t value_addr = + reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS); + + if (value_addr == LLDB_INVALID_ADDRESS) + return false; + + if (exe_ctx.GetProcessRef().ReadMemory( + value_addr, heap_data_up->GetBytes(), heap_data_up->GetByteSize(), + error) != heap_data_up->GetByteSize()) { + return false; + } + } + + data.SetByteOrder(byte_order); + data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); + data.SetData(DataBufferSP(heap_data_up.release())); + return true; +} + +ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( + Thread &thread, CompilerType &return_compiler_type) const { + ValueObjectSP return_valobj_sp; + Value value; + + ExecutionContext exe_ctx(thread.shared_from_this()); + if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr) + return return_valobj_sp; + + // value.SetContext (Value::eContextTypeClangType, return_compiler_type); + value.SetCompilerType(return_compiler_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (!byte_size) + return return_valobj_sp; + + const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); + if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { + value.SetValueType(Value::eValueTypeScalar); + + bool success = false; + if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { + // Extract the register context so we can read arguments from registers + if (*byte_size <= 8) { + const RegisterInfo *x0_reg_info = + reg_ctx->GetRegisterInfoByName("x0", 0); + if (x0_reg_info) { + uint64_t raw_value = + thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, + 0); + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + switch (*byte_size) { + default: + break; + case 16: // uint128_t + // In register x0 and x1 + { + const RegisterInfo *x1_reg_info = + reg_ctx->GetRegisterInfoByName("x1", 0); + + if (x1_reg_info) { + if (*byte_size <= + x0_reg_info->byte_size + x1_reg_info->byte_size) { + std::unique_ptr<DataBufferHeap> heap_data_up( + new DataBufferHeap(*byte_size, 0)); + const ByteOrder byte_order = + exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue x0_reg_value; + RegisterValue x1_reg_value; + if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) && + reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) { + Status error; + if (x0_reg_value.GetAsMemoryData( + x0_reg_info, heap_data_up->GetBytes() + 0, 8, + byte_order, error) && + x1_reg_value.GetAsMemoryData( + x1_reg_info, heap_data_up->GetBytes() + 8, 8, + byte_order, error)) { + DataExtractor data( + DataBufferSP(heap_data_up.release()), byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), data); + return return_valobj_sp; + } + } + } + } + } + break; + case sizeof(uint64_t): + if (is_signed) + value.GetScalar() = (int64_t)(raw_value); + else + value.GetScalar() = (uint64_t)(raw_value); + success = true; + break; + + case sizeof(uint32_t): + if (is_signed) + value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + success = true; + break; + + case sizeof(uint16_t): + if (is_signed) + value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + success = true; + break; + + case sizeof(uint8_t): + if (is_signed) + value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + success = true; + break; + } + } + } + } else if (type_flags & eTypeIsFloat) { + if (type_flags & eTypeIsComplex) { + // Don't handle complex yet. + } else { + if (*byte_size <= sizeof(long double)) { + const RegisterInfo *v0_reg_info = + reg_ctx->GetRegisterInfoByName("v0", 0); + RegisterValue v0_value; + if (reg_ctx->ReadRegister(v0_reg_info, v0_value)) { + DataExtractor data; + if (v0_value.GetData(data)) { + lldb::offset_t offset = 0; + if (*byte_size == sizeof(float)) { + value.GetScalar() = data.GetFloat(&offset); + success = true; + } else if (*byte_size == sizeof(double)) { + value.GetScalar() = data.GetDouble(&offset); + success = true; + } else if (*byte_size == sizeof(long double)) { + value.GetScalar() = data.GetLongDouble(&offset); + success = true; + } + } + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } else if (type_flags & eTypeIsVector) { + if (*byte_size > 0) { + + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) { + if (*byte_size <= v0_info->byte_size) { + std::unique_ptr<DataBufferHeap> heap_data_up( + new DataBufferHeap(*byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(v0_info, reg_value)) { + Status error; + if (reg_value.GetAsMemoryData(v0_info, heap_data_up->GetBytes(), + heap_data_up->GetByteSize(), + byte_order, error)) { + DataExtractor data(DataBufferSP(heap_data_up.release()), + byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), data); + } + } + } + } + } + } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) { + DataExtractor data; + + uint32_t NGRN = 0; // Search ABI docs for NGRN + uint32_t NSRN = 0; // Search ABI docs for NSRN + const bool is_return_value = true; + if (LoadValueFromConsecutiveGPRRegisters( + exe_ctx, reg_ctx, return_compiler_type, is_return_value, NGRN, NSRN, + data)) { + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), data); + } + } + return return_valobj_sp; +} + +void ABIMacOSX_arm64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), pluginDesc, + CreateInstance); +} + +void ABIMacOSX_arm64::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +// PluginInterface protocol + +ConstString ABIMacOSX_arm64::GetPluginNameStatic() { + static ConstString g_plugin_name("ABIMacOSX_arm64"); + return g_plugin_name; +} + +uint32_t ABIMacOSX_arm64::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h index c7a91ba9c468..fc8ccee92e71 100644 --- a/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABIMacOSX_arm64_h_ -#define liblldb_ABIMacOSX_arm64_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_AARCH64_ABIMACOSX_ARM64_H +#define LLDB_SOURCE_PLUGINS_ABI_AARCH64_ABIMACOSX_ARM64_H -#include "lldb/Target/ABI.h" +#include "Plugins/ABI/AArch64/ABIAArch64.h" #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" -class ABIMacOSX_arm64 : public lldb_private::ABI { +class ABIMacOSX_arm64 : public ABIAArch64 { public: ~ABIMacOSX_arm64() override = default; @@ -42,7 +42,7 @@ public: // // To work around this, we relax that alignment to be just word-size // (8-bytes). - // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // Allowing the trap handlers for user space would be easy (_sigtramp) but // in other environments there can be a large number of different functions // involved in async traps. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { @@ -62,9 +62,6 @@ public: return true; } - const lldb_private::RegisterInfo * - GetRegisterInfoArray(uint32_t &count) override; - // Static Functions static void Initialize(); @@ -93,11 +90,7 @@ protected: lldb_private::CompilerType &ast_type) const override; private: - ABIMacOSX_arm64(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using ABIAArch64::ABIAArch64; // Call CreateInstance instead. }; -#endif // liblldb_ABIMacOSX_arm64_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_AARCH64_ABIMACOSX_ARM64_H diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp new file mode 100644 index 000000000000..831c8aa0d760 --- /dev/null +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -0,0 +1,800 @@ +//===-- ABISysV_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 "ABISysV_arm64.h" + +#include <vector> + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" +#include "lldb/Utility/Status.h" + +#include "Utility/ARM64_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +bool ABISysV_arm64::GetPointerReturnRegister(const char *&name) { + name = "x0"; + return true; +} + +size_t ABISysV_arm64::GetRedZoneSize() const { return 128; } + +// Static Functions + +ABISP +ABISysV_arm64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { + const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch(); + const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor(); + + if (vendor_type != llvm::Triple::Apple) { + if (arch_type == llvm::Triple::aarch64 || + arch_type == llvm::Triple::aarch64_32) { + return ABISP( + new ABISysV_arm64(std::move(process_sp), MakeMCRegisterInfo(arch))); + } + } + + return ABISP(); +} + +bool ABISysV_arm64::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t return_addr, + llvm::ArrayRef<addr_t> args) const { + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (log) { + StreamString s; + s.Printf("ABISysV_arm64::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%d = 0x%" PRIx64, static_cast<int>(i + 1), args[i]); + s.PutCString(")"); + log->PutString(s.GetString()); + } + + // x0 - x7 contain first 8 simple args + if (args.size() > 8) + return false; + + for (size_t i = 0; i < args.size(); ++i) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); + LLDB_LOGF(log, "About to write arg%d (0x%" PRIx64 ") into %s", + static_cast<int>(i + 1), args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // Set "lr" to the return address + if (!reg_ctx->WriteRegisterFromUnsigned( + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA), + return_addr)) + return false; + + // Set "sp" to the requested value + if (!reg_ctx->WriteRegisterFromUnsigned( + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_SP), + sp)) + return false; + + // Set "pc" to the address requested + if (!reg_ctx->WriteRegisterFromUnsigned( + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC), + func_addr)) + return false; + + return true; +} + +// TODO: We dont support fp/SIMD arguments in v0-v7 +bool ABISysV_arm64::GetArgumentValues(Thread &thread, ValueList &values) const { + uint32_t num_values = values.GetSize(); + + ExecutionContext exe_ctx(thread.shared_from_this()); + + // Extract the register context so we can read arguments from registers + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + + if (!reg_ctx) + return false; + + addr_t sp = 0; + + for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? + Value *value = values.GetValueAtIndex(value_idx); + + if (!value) + return false; + + CompilerType value_type = value->GetCompilerType(); + if (value_type) { + bool is_signed = false; + size_t bit_width = 0; + llvm::Optional<uint64_t> bit_size = value_type.GetBitSize(&thread); + if (!bit_size) + return false; + if (value_type.IsIntegerOrEnumerationType(is_signed)) { + bit_width = *bit_size; + } else if (value_type.IsPointerOrReferenceType()) { + bit_width = *bit_size; + } else { + // We only handle integer, pointer and reference types currently... + return false; + } + + if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) { + if (value_idx < 8) { + // Arguments 1-8 are in x0-x7... + const RegisterInfo *reg_info = nullptr; + reg_info = reg_ctx->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx); + + if (reg_info) { + RegisterValue reg_value; + + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + if (is_signed) + reg_value.SignExtend(bit_width); + if (!reg_value.GetScalarValue(value->GetScalar())) + return false; + continue; + } + } + return false; + } else { + // TODO: Verify for stack layout for SysV + if (sp == 0) { + // Read the stack pointer if we already haven't read it + sp = reg_ctx->GetSP(0); + if (sp == 0) + return false; + } + + // Arguments 5 on up are on the stack + const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8; + Status error; + if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory( + sp, arg_byte_size, is_signed, value->GetScalar(), error)) + return false; + + sp += arg_byte_size; + // Align up to the next 8 byte boundary if needed + if (sp % 8) { + sp >>= 3; + sp += 1; + sp <<= 3; + } + } + } + } + } + return true; +} + +Status ABISysV_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, + lldb::ValueObjectSP &new_value_sp) { + Status error; + if (!new_value_sp) { + error.SetErrorString("Empty value object for return value."); + return error; + } + + CompilerType return_value_type = new_value_sp->GetCompilerType(); + if (!return_value_type) { + error.SetErrorString("Null clang type for return value."); + return error; + } + + Thread *thread = frame_sp->GetThread().get(); + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + if (reg_ctx) { + DataExtractor data; + Status data_error; + const uint64_t byte_size = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) { + error.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", + data_error.AsCString()); + return error; + } + + const uint32_t type_flags = return_value_type.GetTypeInfo(nullptr); + if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { + if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { + // Extract the register context so we can read arguments from registers + lldb::offset_t offset = 0; + if (byte_size <= 16) { + const RegisterInfo *x0_info = reg_ctx->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + if (byte_size <= 8) { + uint64_t raw_value = data.GetMaxU64(&offset, byte_size); + + if (!reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) + error.SetErrorString("failed to write register x0"); + } else { + uint64_t raw_value = data.GetMaxU64(&offset, 8); + + if (reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) { + const RegisterInfo *x1_info = reg_ctx->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2); + raw_value = data.GetMaxU64(&offset, byte_size - offset); + + if (!reg_ctx->WriteRegisterFromUnsigned(x1_info, raw_value)) + error.SetErrorString("failed to write register x1"); + } + } + } else { + error.SetErrorString("We don't support returning longer than 128 bit " + "integer values at present."); + } + } else if (type_flags & eTypeIsFloat) { + if (type_flags & eTypeIsComplex) { + // Don't handle complex yet. + error.SetErrorString( + "returning complex float values are not supported"); + } else { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) { + if (byte_size <= 16) { + if (byte_size <= RegisterValue::GetMaxByteSize()) { + RegisterValue reg_value; + error = reg_value.SetValueFromData(v0_info, data, 0, true); + if (error.Success()) { + if (!reg_ctx->WriteRegister(v0_info, reg_value)) + error.SetErrorString("failed to write register v0"); + } + } else { + error.SetErrorStringWithFormat( + "returning float values with a byte size of %" PRIu64 + " are not supported", + byte_size); + } + } else { + error.SetErrorString("returning float values longer than 128 " + "bits are not supported"); + } + } else { + error.SetErrorString("v0 register is not available on this target"); + } + } + } + } else if (type_flags & eTypeIsVector) { + if (byte_size > 0) { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) { + if (byte_size <= v0_info->byte_size) { + RegisterValue reg_value; + error = reg_value.SetValueFromData(v0_info, data, 0, true); + if (error.Success()) { + if (!reg_ctx->WriteRegister(v0_info, reg_value)) + error.SetErrorString("failed to write register v0"); + } + } + } + } + } + } else { + error.SetErrorString("no registers are available"); + } + + return error; +} + +bool ABISysV_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + uint32_t lr_reg_num = arm64_dwarf::lr; + uint32_t sp_reg_num = arm64_dwarf::sp; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our previous Call Frame Address is the stack pointer + row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); + + unwind_plan.AppendRow(row); + unwind_plan.SetReturnAddressRegister(lr_reg_num); + + // All other registers are the same. + + unwind_plan.SetSourceName("arm64 at-func-entry default"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); + + return true; +} + +bool ABISysV_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + uint32_t fp_reg_num = arm64_dwarf::fp; + uint32_t pc_reg_num = arm64_dwarf::pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + const int32_t ptr_size = 8; + + row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); + row->SetOffset(0); + + row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); + + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("arm64 default unwind plan"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); + + return true; +} + +// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says +// registers x19 through x28 and sp are callee preserved. v8-v15 are non- +// volatile (and specifically only the lower 8 bytes of these regs), the rest +// of the fp/SIMD registers are volatile. + +// We treat x29 as callee preserved also, else the unwinder won't try to +// retrieve fp saves. + +bool ABISysV_arm64::RegisterIsVolatile(const RegisterInfo *reg_info) { + if (reg_info) { + const char *name = reg_info->name; + + // Sometimes we'll be called with the "alternate" name for these registers; + // recognize them as non-volatile. + + if (name[0] == 'p' && name[1] == 'c') // pc + return false; + if (name[0] == 'f' && name[1] == 'p') // fp + return false; + if (name[0] == 's' && name[1] == 'p') // sp + return false; + if (name[0] == 'l' && name[1] == 'r') // lr + return false; + + if (name[0] == 'x' || name[0] == 'r') { + // Volatile registers: x0-x18 + // Although documentation says only x19-28 + sp are callee saved We ll + // also have to treat x30 as non-volatile. Each dwarf frame has its own + // value of lr. Return false for the non-volatile gpr regs, true for + // everything else + switch (name[1]) { + case '1': + switch (name[2]) { + case '9': + return false; // x19 is non-volatile + default: + return true; + } + break; + case '2': + switch (name[2]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + return false; // x20 - 28 are non-volatile + case '9': + return false; // x29 aka fp treat as non-volatile + default: + return true; + } + case '3': // x30 (lr) and x31 (sp) treat as non-volatile + if (name[2] == '0' || name[2] == '1') + return false; + break; + default: + return true; // all volatile cases not handled above fall here. + } + } else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd') { + // Volatile registers: v0-7, v16-v31 + // Return false for non-volatile fp/SIMD regs, true for everything else + switch (name[1]) { + case '8': + case '9': + return false; // v8-v9 are non-volatile + case '1': + switch (name[2]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + return false; // v10-v15 are non-volatile + default: + return true; + } + default: + return true; + } + } + } + return true; +} + +static bool LoadValueFromConsecutiveGPRRegisters( + ExecutionContext &exe_ctx, RegisterContext *reg_ctx, + const CompilerType &value_type, + bool is_return_value, // false => parameter, true => return value + uint32_t &NGRN, // NGRN (see ABI documentation) + uint32_t &NSRN, // NSRN (see ABI documentation) + DataExtractor &data) { + llvm::Optional<uint64_t> byte_size = value_type.GetByteSize(nullptr); + + if (byte_size || *byte_size == 0) + return false; + + std::unique_ptr<DataBufferHeap> heap_data_up( + new DataBufferHeap(*byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + Status error; + + CompilerType base_type; + const uint32_t homogeneous_count = + value_type.IsHomogeneousAggregate(&base_type); + if (homogeneous_count > 0 && homogeneous_count <= 8) { + // Make sure we have enough registers + if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { + if (!base_type) + return false; + llvm::Optional<uint64_t> base_byte_size = base_type.GetByteSize(nullptr); + if (!base_byte_size) + return false; + uint32_t data_offset = 0; + + for (uint32_t i = 0; i < homogeneous_count; ++i) { + char v_name[8]; + ::snprintf(v_name, sizeof(v_name), "v%u", NSRN); + const RegisterInfo *reg_info = + reg_ctx->GetRegisterInfoByName(v_name, 0); + if (reg_info == nullptr) + return false; + + if (*base_byte_size > reg_info->byte_size) + return false; + + RegisterValue reg_value; + + if (!reg_ctx->ReadRegister(reg_info, reg_value)) + return false; + + // Make sure we have enough room in "heap_data_up" + if ((data_offset + *base_byte_size) <= heap_data_up->GetByteSize()) { + const size_t bytes_copied = reg_value.GetAsMemoryData( + reg_info, heap_data_up->GetBytes() + data_offset, *base_byte_size, + byte_order, error); + if (bytes_copied != *base_byte_size) + return false; + data_offset += bytes_copied; + ++NSRN; + } else + return false; + } + data.SetByteOrder(byte_order); + data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); + data.SetData(DataBufferSP(heap_data_up.release())); + return true; + } + } + + const size_t max_reg_byte_size = 16; + if (*byte_size <= max_reg_byte_size) { + size_t bytes_left = *byte_size; + uint32_t data_offset = 0; + while (data_offset < *byte_size) { + if (NGRN >= 8) + return false; + + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); + if (reg_info == nullptr) + return false; + + RegisterValue reg_value; + + if (!reg_ctx->ReadRegister(reg_info, reg_value)) + return false; + + const size_t curr_byte_size = std::min<size_t>(8, bytes_left); + const size_t bytes_copied = reg_value.GetAsMemoryData( + reg_info, heap_data_up->GetBytes() + data_offset, curr_byte_size, + byte_order, error); + if (bytes_copied == 0) + return false; + if (bytes_copied >= bytes_left) + break; + data_offset += bytes_copied; + bytes_left -= bytes_copied; + ++NGRN; + } + } else { + const RegisterInfo *reg_info = nullptr; + if (is_return_value) { + // We are assuming we are decoding this immediately after returning from + // a function call and that the address of the structure is in x8 + reg_info = reg_ctx->GetRegisterInfoByName("x8", 0); + } else { + // We are assuming we are stopped at the first instruction in a function + // and that the ABI is being respected so all parameters appear where + // they should be (functions with no external linkage can legally violate + // the ABI). + if (NGRN >= 8) + return false; + + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + NGRN); + if (reg_info == nullptr) + return false; + ++NGRN; + } + + if (reg_info == nullptr) + return false; + + const lldb::addr_t value_addr = + reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS); + + if (value_addr == LLDB_INVALID_ADDRESS) + return false; + + if (exe_ctx.GetProcessRef().ReadMemory( + value_addr, heap_data_up->GetBytes(), heap_data_up->GetByteSize(), + error) != heap_data_up->GetByteSize()) { + return false; + } + } + + data.SetByteOrder(byte_order); + data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); + data.SetData(DataBufferSP(heap_data_up.release())); + return true; +} + +ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( + Thread &thread, CompilerType &return_compiler_type) const { + ValueObjectSP return_valobj_sp; + Value value; + + ExecutionContext exe_ctx(thread.shared_from_this()); + if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr) + return return_valobj_sp; + + // value.SetContext (Value::eContextTypeClangType, return_compiler_type); + value.SetCompilerType(return_compiler_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (!byte_size) + return return_valobj_sp; + + const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); + if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { + value.SetValueType(Value::eValueTypeScalar); + + bool success = false; + if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { + // Extract the register context so we can read arguments from registers + if (*byte_size <= 8) { + const RegisterInfo *x0_reg_info = nullptr; + x0_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1); + if (x0_reg_info) { + uint64_t raw_value = + thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, + 0); + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + switch (*byte_size) { + default: + break; + case 16: // uint128_t + // In register x0 and x1 + { + const RegisterInfo *x1_reg_info = nullptr; + x1_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG2); + + if (x1_reg_info) { + if (*byte_size <= + x0_reg_info->byte_size + x1_reg_info->byte_size) { + std::unique_ptr<DataBufferHeap> heap_data_up( + new DataBufferHeap(*byte_size, 0)); + const ByteOrder byte_order = + exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue x0_reg_value; + RegisterValue x1_reg_value; + if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) && + reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) { + Status error; + if (x0_reg_value.GetAsMemoryData( + x0_reg_info, heap_data_up->GetBytes() + 0, 8, + byte_order, error) && + x1_reg_value.GetAsMemoryData( + x1_reg_info, heap_data_up->GetBytes() + 8, 8, + byte_order, error)) { + DataExtractor data( + DataBufferSP(heap_data_up.release()), byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), data); + return return_valobj_sp; + } + } + } + } + } + break; + case sizeof(uint64_t): + if (is_signed) + value.GetScalar() = (int64_t)(raw_value); + else + value.GetScalar() = (uint64_t)(raw_value); + success = true; + break; + + case sizeof(uint32_t): + if (is_signed) + value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + success = true; + break; + + case sizeof(uint16_t): + if (is_signed) + value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + success = true; + break; + + case sizeof(uint8_t): + if (is_signed) + value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + success = true; + break; + } + } + } + } else if (type_flags & eTypeIsFloat) { + if (type_flags & eTypeIsComplex) { + // Don't handle complex yet. + } else { + if (*byte_size <= sizeof(long double)) { + const RegisterInfo *v0_reg_info = + reg_ctx->GetRegisterInfoByName("v0", 0); + RegisterValue v0_value; + if (reg_ctx->ReadRegister(v0_reg_info, v0_value)) { + DataExtractor data; + if (v0_value.GetData(data)) { + lldb::offset_t offset = 0; + if (*byte_size == sizeof(float)) { + value.GetScalar() = data.GetFloat(&offset); + success = true; + } else if (*byte_size == sizeof(double)) { + value.GetScalar() = data.GetDouble(&offset); + success = true; + } else if (*byte_size == sizeof(long double)) { + value.GetScalar() = data.GetLongDouble(&offset); + success = true; + } + } + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } else if (type_flags & eTypeIsVector && *byte_size <= 16) { + if (*byte_size > 0) { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) { + std::unique_ptr<DataBufferHeap> heap_data_up( + new DataBufferHeap(*byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(v0_info, reg_value)) { + Status error; + if (reg_value.GetAsMemoryData(v0_info, heap_data_up->GetBytes(), + heap_data_up->GetByteSize(), byte_order, + error)) { + DataExtractor data(DataBufferSP(heap_data_up.release()), byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), data); + } + } + } + } + } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass || + (type_flags & eTypeIsVector && *byte_size > 16)) { + DataExtractor data; + + uint32_t NGRN = 0; // Search ABI docs for NGRN + uint32_t NSRN = 0; // Search ABI docs for NSRN + const bool is_return_value = true; + if (LoadValueFromConsecutiveGPRRegisters( + exe_ctx, reg_ctx, return_compiler_type, is_return_value, NGRN, NSRN, + data)) { + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), data); + } + } + return return_valobj_sp; +} + +void ABISysV_arm64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "SysV ABI for AArch64 targets", CreateInstance); +} + +void ABISysV_arm64::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +lldb_private::ConstString ABISysV_arm64::GetPluginNameStatic() { + static ConstString g_name("SysV-arm64"); + return g_name; +} + +// PluginInterface protocol + +ConstString ABISysV_arm64::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t ABISysV_arm64::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h index 1bf5773e2db3..aeb74acc38b5 100644 --- a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_arm64_h_ -#define liblldb_ABISysV_arm64_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_AARCH64_ABISYSV_ARM64_H +#define LLDB_SOURCE_PLUGINS_ABI_AARCH64_ABISYSV_ARM64_H -#include "lldb/Target/ABI.h" +#include "Plugins/ABI/AArch64/ABIAArch64.h" #include "lldb/lldb-private.h" -class ABISysV_arm64 : public lldb_private::ABI { +class ABISysV_arm64 : public ABIAArch64 { public: ~ABISysV_arm64() override = default; @@ -45,7 +45,7 @@ public: // // To work around this, we relax that alignment to be just word-size // (8-bytes). - // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // Allowing the trap handlers for user space would be easy (_sigtramp) but // in other environments there can be a large number of different functions // involved in async traps. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { @@ -65,9 +65,6 @@ public: return true; } - const lldb_private::RegisterInfo * - GetRegisterInfoArray(uint32_t &count) override; - bool GetPointerReturnRegister(const char *&name) override; // Static Functions @@ -92,11 +89,7 @@ protected: lldb_private::CompilerType &ast_type) const override; private: - ABISysV_arm64(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using ABIAArch64::ABIAArch64; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_arm64_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_AARCH64_ABISYSV_ARM64_H diff --git a/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.cpp b/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp index 715b5e5d2b95..a212eef2ab8a 100644 --- a/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.cpp +++ b/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_arc.cpp ---------------------------------------*- C++ -*-===// +//===-- ABISysV_arc.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -55,6 +55,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(ABISysV_arc, ABIARC) + namespace { namespace dwarf { enum regnums { @@ -144,7 +146,7 @@ size_t ABISysV_arc::GetRedZoneSize() const { return 0; } bool ABISysV_arc::IsRegisterFileReduced(RegisterContext ®_ctx) const { if (!m_is_reg_file_reduced) { const auto *const rf_build_reg = reg_ctx.GetRegisterInfoByName("rf_build"); - + const auto reg_value = reg_ctx.ReadRegisterAsUnsigned(rf_build_reg, /*fail_value*/ 0); // RF_BUILD "Number of Entries" bit. @@ -239,7 +241,7 @@ bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t pc, // Make sure number of parameters matches prototype. assert(!prototype.isFunctionVarArg()); assert(prototype.getFunctionNumParams() == args.size()); - + const size_t regs_for_args_count = IsRegisterFileReduced(*reg_ctx) ? 4U : 8U; // Number of arguments passed on stack. @@ -520,7 +522,7 @@ ValueObjectSP ABISysV_arc::GetReturnValueObjectImpl(Thread &thread, // Integer return type. else if (retType.isIntegerTy()) { size_t byte_size = retType.getPrimitiveSizeInBits(); - if (1 != byte_size) // For boolian type. + if (1 != byte_size) // For boolean type. byte_size /= CHAR_BIT; auto raw_value = ReadRawValue(reg_ctx, byte_size); diff --git a/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.h b/lldb/source/Plugins/ABI/ARC/ABISysV_arc.h index c4b26a54158c..3fbe64b4b45b 100644 --- a/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.h +++ b/lldb/source/Plugins/ABI/ARC/ABISysV_arc.h @@ -16,7 +16,7 @@ #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABISysV_arc : public lldb_private::ABI { +class ABISysV_arc : public lldb_private::RegInfoBasedABI { public: ~ABISysV_arc() override = default; @@ -97,7 +97,7 @@ private: bool IsRegisterFileReduced(lldb_private::RegisterContext ®_ctx) const; - using lldb_private::ABI::ABI; // Call CreateInstance instead. + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. using RegisterFileFlag = llvm::Optional<bool>; mutable RegisterFileFlag m_is_reg_file_reduced; diff --git a/lldb/source/Plugins/ABI/ARM/ABIARM.cpp b/lldb/source/Plugins/ABI/ARM/ABIARM.cpp new file mode 100644 index 000000000000..882c14d386e3 --- /dev/null +++ b/lldb/source/Plugins/ABI/ARM/ABIARM.cpp @@ -0,0 +1,24 @@ +//===-- ARM.h -------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ABIARM.h" +#include "ABIMacOSX_arm.h" +#include "ABISysV_arm.h" +#include "lldb/Core/PluginManager.h" + +LLDB_PLUGIN_DEFINE(ABIARM) + +void ABIARM::Initialize() { + ABISysV_arm::Initialize(); + ABIMacOSX_arm::Initialize(); +} + +void ABIARM::Terminate() { + ABISysV_arm::Terminate(); + ABIMacOSX_arm::Terminate(); +} diff --git a/lldb/source/Plugins/ABI/ARM/ABIARM.h b/lldb/source/Plugins/ABI/ARM/ABIARM.h new file mode 100644 index 000000000000..7d04f1c9eb0f --- /dev/null +++ b/lldb/source/Plugins/ABI/ARM/ABIARM.h @@ -0,0 +1,17 @@ +//===-- ARM.h -------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_ABI_ARM_ABIARM_H +#define LLDB_SOURCE_PLUGINS_ABI_ARM_ABIARM_H + +class ABIARM { +public: + static void Initialize(); + static void Terminate(); +}; +#endif diff --git a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp index 9dff12bcc748..ef500cb198a8 100644 --- a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ b/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp @@ -1,4 +1,4 @@ -//===-- ABIMacOSX_arm.cpp ---------------------------------------*- C++ -*-===// +//===-- ABIMacOSX_arm.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.h index e512651f86e5..e0fa349eea73 100644 --- a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h +++ b/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABIMacOSX_arm_h_ -#define liblldb_ABIMacOSX_arm_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_ARM_ABIMACOSX_ARM_H +#define LLDB_SOURCE_PLUGINS_ABI_ARM_ABIMACOSX_ARM_H #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABIMacOSX_arm : public lldb_private::ABI { +class ABIMacOSX_arm : public lldb_private::RegInfoBasedABI { public: ~ABIMacOSX_arm() override = default; @@ -85,11 +85,7 @@ protected: lldb_private::CompilerType &ast_type) const override; private: - ABIMacOSX_arm(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. }; -#endif // liblldb_ABIMacOSX_arm_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_ARM_ABIMACOSX_ARM_H diff --git a/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp index b6e8f8806829..1a93bac564f7 100644 --- a/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp +++ b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_arm.cpp -----------------------------------------*- C++ -*-===// +//===-- ABISysV_arm.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -34,6 +34,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ABISysV_arm) + static RegisterInfo g_register_infos[] = { // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME // DWARF GENERIC PROCESS PLUGIN diff --git a/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.h b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.h index 60fb14be5f7b..f28f75ce4fe5 100644 --- a/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.h +++ b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_arm_h_ -#define liblldb_ABISysV_arm_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_ARM_ABISYSV_ARM_H +#define LLDB_SOURCE_PLUGINS_ABI_ARM_ABISYSV_ARM_H #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABISysV_arm : public lldb_private::ABI { +class ABISysV_arm : public lldb_private::RegInfoBasedABI { public: ~ABISysV_arm() override = default; @@ -85,11 +85,7 @@ protected: lldb_private::CompilerType &ast_type) const override; private: - ABISysV_arm(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_arm_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_ARM_ABISYSV_ARM_H diff --git a/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp index 34d9258ccb92..32313d4cd815 100644 --- a/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp +++ b/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_hexagon.cpp -------------------------------------*- C++ -*-===// +//===-- ABISysV_hexagon.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,6 +32,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(ABISysV_hexagon, ABIHexagon) + static RegisterInfo g_register_infos[] = { // hexagon-core.xml {"r00", diff --git a/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h b/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.h index bef64a22d95f..d6dab0c2e378 100644 --- a/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h +++ b/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.h @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_hexagon_h_ -#define liblldb_ABISysV_hexagon_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_HEXAGON_ABISYSV_HEXAGON_H +#define LLDB_SOURCE_PLUGINS_ABI_HEXAGON_ABISYSV_HEXAGON_H #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABISysV_hexagon : public lldb_private::ABI { +class ABISysV_hexagon : public lldb_private::RegInfoBasedABI { public: ~ABISysV_hexagon() override = default; @@ -97,11 +97,7 @@ protected: bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); private: - ABISysV_hexagon(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_hexagon_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_HEXAGON_ABISYSV_HEXAGON_H diff --git a/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp deleted file mode 100644 index ec7588dfb50c..000000000000 --- a/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp +++ /dev/null @@ -1,2451 +0,0 @@ -//===-- ABIMacOSX_arm64.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 "ABIMacOSX_arm64.h" - -#include <vector> - -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Triple.h" - -#include "lldb/Core/Module.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/Value.h" -#include "lldb/Core/ValueObjectConstResult.h" -#include "lldb/Symbol/UnwindPlan.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Scalar.h" -#include "lldb/Utility/Status.h" - -#include "Utility/ARM64_DWARF_Registers.h" - -using namespace lldb; -using namespace lldb_private; - -static const char *pluginDesc = "Mac OS X ABI for arm64 targets"; - -static RegisterInfo g_register_infos[] = { - // NAME ALT SZ OFF ENCODING FORMAT - // EH_FRAME DWARF GENERIC - // PROCESS PLUGIN LLDB NATIVE - // ========== ======= == === ============= =================== - // =================== ====================== =========================== - // ======================= ====================== - {"x0", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x1", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x2", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x3", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x4", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x5", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x6", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x7", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x8", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x8, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x9", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x9, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x10", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x10, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x11", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x11, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x12", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x12, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x13", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x13, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x14", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x14, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x15", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x15, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x16", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x16, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x17", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x17, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x18", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x18, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x19", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x19, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x20", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x20, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x21", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x21, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x22", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x22, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x23", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x23, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x24", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x24, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x25", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x25, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x26", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x26, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x27", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x27, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x28", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x28, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fp", - "x29", - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"lr", - "x30", - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"sp", - "x31", - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"pc", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"cpsr", - "psr", - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - - {"v0", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v1", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v2", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v3", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v4", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v5", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v6", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v7", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v8", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v9", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v10", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v11", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v12", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v13", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v14", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v15", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v16", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v17", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v18", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v19", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v20", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v21", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v22", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v23", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v24", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v25", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v26", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v27", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v28", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v29", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v30", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v31", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - - {"fpsr", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fpcr", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - - {"s0", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s1", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s2", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s3", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s4", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s5", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s6", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s7", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s8", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s9", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s10", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s11", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s12", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s13", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s14", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s15", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s16", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s17", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s18", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s19", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s20", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s21", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s22", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s23", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s24", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s25", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s26", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s27", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s28", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s29", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s30", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s31", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - - {"d0", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d1", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d2", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d3", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d4", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d5", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d6", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d7", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d8", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d9", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d10", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d11", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d12", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d13", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d14", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d15", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d16", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d17", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d18", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d19", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d20", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d21", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d22", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d23", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d24", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d25", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d26", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d27", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d28", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d29", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d30", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d31", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}}; - -static const uint32_t k_num_register_infos = - llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; - -const lldb_private::RegisterInfo * -ABIMacOSX_arm64::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } - count = k_num_register_infos; - return g_register_infos; -} - -size_t ABIMacOSX_arm64::GetRedZoneSize() const { return 128; } - -// Static Functions - -ABISP -ABIMacOSX_arm64::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) { - const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch(); - const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor(); - - if (vendor_type == llvm::Triple::Apple) { - if (arch_type == llvm::Triple::aarch64 || - arch_type == llvm::Triple::aarch64_32) { - return ABISP( - new ABIMacOSX_arm64(std::move(process_sp), MakeMCRegisterInfo(arch))); - } - } - - return ABISP(); -} - -bool ABIMacOSX_arm64::PrepareTrivialCall( - Thread &thread, lldb::addr_t sp, lldb::addr_t func_addr, - lldb::addr_t return_addr, llvm::ArrayRef<lldb::addr_t> args) const { - RegisterContext *reg_ctx = thread.GetRegisterContext().get(); - if (!reg_ctx) - return false; - - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - if (log) { - StreamString s; - s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64 - ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 - ", return_addr = 0x%" PRIx64, - thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, - (uint64_t)return_addr); - - for (size_t i = 0; i < args.size(); ++i) - s.Printf(", arg%d = 0x%" PRIx64, static_cast<int>(i + 1), args[i]); - s.PutCString(")"); - log->PutString(s.GetString()); - } - - const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); - const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); - - // x0 - x7 contain first 8 simple args - if (args.size() > 8) // TODO handle more than 6 arguments - return false; - - for (size_t i = 0; i < args.size(); ++i) { - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); - LLDB_LOGF(log, "About to write arg%d (0x%" PRIx64 ") into %s", - static_cast<int>(i + 1), args[i], reg_info->name); - if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) - return false; - } - - // Set "lr" to the return address - if (!reg_ctx->WriteRegisterFromUnsigned( - reg_ctx->GetRegisterInfoAtIndex(ra_reg_num), return_addr)) - return false; - - // Set "sp" to the requested value - if (!reg_ctx->WriteRegisterFromUnsigned( - reg_ctx->GetRegisterInfoAtIndex(sp_reg_num), sp)) - return false; - - // Set "pc" to the address requested - if (!reg_ctx->WriteRegisterFromUnsigned( - reg_ctx->GetRegisterInfoAtIndex(pc_reg_num), func_addr)) - return false; - - return true; -} - -bool ABIMacOSX_arm64::GetArgumentValues(Thread &thread, - ValueList &values) const { - uint32_t num_values = values.GetSize(); - - ExecutionContext exe_ctx(thread.shared_from_this()); - - // Extract the register context so we can read arguments from registers - - RegisterContext *reg_ctx = thread.GetRegisterContext().get(); - - if (!reg_ctx) - return false; - - addr_t sp = 0; - - for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { - // We currently only support extracting values with Clang QualTypes. Do we - // care about others? - Value *value = values.GetValueAtIndex(value_idx); - - if (!value) - return false; - - CompilerType value_type = value->GetCompilerType(); - llvm::Optional<uint64_t> bit_size = value_type.GetBitSize(&thread); - if (!bit_size) - return false; - - bool is_signed = false; - size_t bit_width = 0; - if (value_type.IsIntegerOrEnumerationType(is_signed)) { - bit_width = *bit_size; - } else if (value_type.IsPointerOrReferenceType()) { - bit_width = *bit_size; - } else { - // We only handle integer, pointer and reference types currently... - return false; - } - - if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) { - if (value_idx < 8) { - // Arguments 1-6 are in x0-x5... - const RegisterInfo *reg_info = nullptr; - // Search by generic ID first, then fall back to by name - uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx); - if (arg_reg_num != LLDB_INVALID_REGNUM) { - reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num); - } else { - switch (value_idx) { - case 0: - reg_info = reg_ctx->GetRegisterInfoByName("x0"); - break; - case 1: - reg_info = reg_ctx->GetRegisterInfoByName("x1"); - break; - case 2: - reg_info = reg_ctx->GetRegisterInfoByName("x2"); - break; - case 3: - reg_info = reg_ctx->GetRegisterInfoByName("x3"); - break; - case 4: - reg_info = reg_ctx->GetRegisterInfoByName("x4"); - break; - case 5: - reg_info = reg_ctx->GetRegisterInfoByName("x5"); - break; - case 6: - reg_info = reg_ctx->GetRegisterInfoByName("x6"); - break; - case 7: - reg_info = reg_ctx->GetRegisterInfoByName("x7"); - break; - } - } - - if (reg_info) { - RegisterValue reg_value; - - if (reg_ctx->ReadRegister(reg_info, reg_value)) { - if (is_signed) - reg_value.SignExtend(bit_width); - if (!reg_value.GetScalarValue(value->GetScalar())) - return false; - continue; - } - } - return false; - } else { - if (sp == 0) { - // Read the stack pointer if we already haven't read it - sp = reg_ctx->GetSP(0); - if (sp == 0) - return false; - } - - // Arguments 5 on up are on the stack - const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8; - Status error; - if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory( - sp, arg_byte_size, is_signed, value->GetScalar(), error)) - return false; - - sp += arg_byte_size; - // Align up to the next 8 byte boundary if needed - if (sp % 8) { - sp >>= 3; - sp += 1; - sp <<= 3; - } - } - } - } - return true; -} - -Status -ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, - lldb::ValueObjectSP &new_value_sp) { - Status error; - if (!new_value_sp) { - error.SetErrorString("Empty value object for return value."); - return error; - } - - CompilerType return_value_type = new_value_sp->GetCompilerType(); - if (!return_value_type) { - error.SetErrorString("Null clang type for return value."); - return error; - } - - Thread *thread = frame_sp->GetThread().get(); - - RegisterContext *reg_ctx = thread->GetRegisterContext().get(); - - if (reg_ctx) { - DataExtractor data; - Status data_error; - const uint64_t byte_size = new_value_sp->GetData(data, data_error); - if (data_error.Fail()) { - error.SetErrorStringWithFormat( - "Couldn't convert return value to raw data: %s", - data_error.AsCString()); - return error; - } - - const uint32_t type_flags = return_value_type.GetTypeInfo(nullptr); - if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { - if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { - // Extract the register context so we can read arguments from registers - lldb::offset_t offset = 0; - if (byte_size <= 16) { - const RegisterInfo *x0_info = reg_ctx->GetRegisterInfoByName("x0", 0); - if (byte_size <= 8) { - uint64_t raw_value = data.GetMaxU64(&offset, byte_size); - - if (!reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) - error.SetErrorString("failed to write register x0"); - } else { - uint64_t raw_value = data.GetMaxU64(&offset, 8); - - if (reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) { - const RegisterInfo *x1_info = - reg_ctx->GetRegisterInfoByName("x1", 0); - raw_value = data.GetMaxU64(&offset, byte_size - offset); - - if (!reg_ctx->WriteRegisterFromUnsigned(x1_info, raw_value)) - error.SetErrorString("failed to write register x1"); - } - } - } else { - error.SetErrorString("We don't support returning longer than 128 bit " - "integer values at present."); - } - } else if (type_flags & eTypeIsFloat) { - if (type_flags & eTypeIsComplex) { - // Don't handle complex yet. - error.SetErrorString( - "returning complex float values are not supported"); - } else { - const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); - - if (v0_info) { - if (byte_size <= 16) { - if (byte_size <= RegisterValue::GetMaxByteSize()) { - RegisterValue reg_value; - error = reg_value.SetValueFromData(v0_info, data, 0, true); - if (error.Success()) { - if (!reg_ctx->WriteRegister(v0_info, reg_value)) - error.SetErrorString("failed to write register v0"); - } - } else { - error.SetErrorStringWithFormat( - "returning float values with a byte size of %" PRIu64 - " are not supported", - byte_size); - } - } else { - error.SetErrorString("returning float values longer than 128 " - "bits are not supported"); - } - } else { - error.SetErrorString("v0 register is not available on this target"); - } - } - } - } else if (type_flags & eTypeIsVector) { - if (byte_size > 0) { - const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); - - if (v0_info) { - if (byte_size <= v0_info->byte_size) { - RegisterValue reg_value; - error = reg_value.SetValueFromData(v0_info, data, 0, true); - if (error.Success()) { - if (!reg_ctx->WriteRegister(v0_info, reg_value)) - error.SetErrorString("failed to write register v0"); - } - } - } - } - } - } else { - error.SetErrorString("no registers are available"); - } - - return error; -} - -bool ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { - unwind_plan.Clear(); - unwind_plan.SetRegisterKind(eRegisterKindDWARF); - - uint32_t lr_reg_num = arm64_dwarf::lr; - uint32_t sp_reg_num = arm64_dwarf::sp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::RowSP row(new UnwindPlan::Row); - - // Our previous Call Frame Address is the stack pointer - row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - - // Our previous PC is in the LR - row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); - - unwind_plan.AppendRow(row); - - // All other registers are the same. - - unwind_plan.SetSourceName("arm64 at-func-entry default"); - unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); - - return true; -} - -bool ABIMacOSX_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { - unwind_plan.Clear(); - unwind_plan.SetRegisterKind(eRegisterKindDWARF); - - uint32_t fp_reg_num = arm64_dwarf::fp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::RowSP row(new UnwindPlan::Row); - const int32_t ptr_size = 8; - - row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); - row->SetOffset(0); - - row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); - row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); - - unwind_plan.AppendRow(row); - unwind_plan.SetSourceName("arm64-apple-darwin default unwind plan"); - unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); - unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); - return true; -} - -// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says -// registers x19 through x28 and sp are callee preserved. v8-v15 are non- -// volatile (and specifically only the lower 8 bytes of these regs), the rest -// of the fp/SIMD registers are volatile. -// -// v. https://github.com/ARM-software/software-standards/blob/master/abi/aapcs64/ - -// We treat x29 as callee preserved also, else the unwinder won't try to -// retrieve fp saves. - -bool ABIMacOSX_arm64::RegisterIsVolatile(const RegisterInfo *reg_info) { - if (reg_info) { - const char *name = reg_info->name; - - // Sometimes we'll be called with the "alternate" name for these registers; - // recognize them as non-volatile. - - if (name[0] == 'p' && name[1] == 'c') // pc - return false; - if (name[0] == 'f' && name[1] == 'p') // fp - return false; - if (name[0] == 's' && name[1] == 'p') // sp - return false; - if (name[0] == 'l' && name[1] == 'r') // lr - return false; - - if (name[0] == 'x') { - // Volatile registers: x0-x18, x30 (lr) - // Return false for the non-volatile gpr regs, true for everything else - switch (name[1]) { - case '1': - switch (name[2]) { - case '9': - return false; // x19 is non-volatile - default: - return true; - } - break; - case '2': - switch (name[2]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - return false; // x20 - 28 are non-volatile - case '9': - return false; // x29 aka fp treat as non-volatile on Darwin - default: - return true; - } - case '3': // x30 aka lr treat as non-volatile - if (name[2] == '0') - return false; - break; - default: - return true; - } - } else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd') { - // Volatile registers: v0-7, v16-v31 - // Return false for non-volatile fp/SIMD regs, true for everything else - switch (name[1]) { - case '8': - case '9': - return false; // v8-v9 are non-volatile - case '1': - switch (name[2]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - return false; // v10-v15 are non-volatile - default: - return true; - } - default: - return true; - } - } - } - return true; -} - -static bool LoadValueFromConsecutiveGPRRegisters( - ExecutionContext &exe_ctx, RegisterContext *reg_ctx, - const CompilerType &value_type, - bool is_return_value, // false => parameter, true => return value - uint32_t &NGRN, // NGRN (see ABI documentation) - uint32_t &NSRN, // NSRN (see ABI documentation) - DataExtractor &data) { - llvm::Optional<uint64_t> byte_size = value_type.GetByteSize(nullptr); - if (!byte_size || *byte_size == 0) - return false; - - std::unique_ptr<DataBufferHeap> heap_data_up( - new DataBufferHeap(*byte_size, 0)); - const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); - Status error; - - CompilerType base_type; - const uint32_t homogeneous_count = - value_type.IsHomogeneousAggregate(&base_type); - if (homogeneous_count > 0 && homogeneous_count <= 8) { - // Make sure we have enough registers - if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { - if (!base_type) - return false; - llvm::Optional<uint64_t> base_byte_size = base_type.GetByteSize(nullptr); - if (!base_byte_size) - return false; - uint32_t data_offset = 0; - - for (uint32_t i = 0; i < homogeneous_count; ++i) { - char v_name[8]; - ::snprintf(v_name, sizeof(v_name), "v%u", NSRN); - const RegisterInfo *reg_info = - reg_ctx->GetRegisterInfoByName(v_name, 0); - if (reg_info == nullptr) - return false; - - if (*base_byte_size > reg_info->byte_size) - return false; - - RegisterValue reg_value; - - if (!reg_ctx->ReadRegister(reg_info, reg_value)) - return false; - - // Make sure we have enough room in "heap_data_up" - if ((data_offset + *base_byte_size) <= heap_data_up->GetByteSize()) { - const size_t bytes_copied = reg_value.GetAsMemoryData( - reg_info, heap_data_up->GetBytes() + data_offset, *base_byte_size, - byte_order, error); - if (bytes_copied != *base_byte_size) - return false; - data_offset += bytes_copied; - ++NSRN; - } else - return false; - } - data.SetByteOrder(byte_order); - data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); - data.SetData(DataBufferSP(heap_data_up.release())); - return true; - } - } - - const size_t max_reg_byte_size = 16; - if (*byte_size <= max_reg_byte_size) { - size_t bytes_left = *byte_size; - uint32_t data_offset = 0; - while (data_offset < *byte_size) { - if (NGRN >= 8) - return false; - - uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); - if (reg_num == LLDB_INVALID_REGNUM) - return false; - - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); - if (reg_info == nullptr) - return false; - - RegisterValue reg_value; - - if (!reg_ctx->ReadRegister(reg_info, reg_value)) - return false; - - const size_t curr_byte_size = std::min<size_t>(8, bytes_left); - const size_t bytes_copied = reg_value.GetAsMemoryData( - reg_info, heap_data_up->GetBytes() + data_offset, curr_byte_size, - byte_order, error); - if (bytes_copied == 0) - return false; - if (bytes_copied >= bytes_left) - break; - data_offset += bytes_copied; - bytes_left -= bytes_copied; - ++NGRN; - } - } else { - const RegisterInfo *reg_info = nullptr; - if (is_return_value) { - // We are assuming we are decoding this immediately after returning from - // a function call and that the address of the structure is in x8 - reg_info = reg_ctx->GetRegisterInfoByName("x8", 0); - } else { - // We are assuming we are stopped at the first instruction in a function - // and that the ABI is being respected so all parameters appear where - // they should be (functions with no external linkage can legally violate - // the ABI). - if (NGRN >= 8) - return false; - - uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); - if (reg_num == LLDB_INVALID_REGNUM) - return false; - reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); - if (reg_info == nullptr) - return false; - ++NGRN; - } - - if (reg_info == nullptr) - return false; - - const lldb::addr_t value_addr = - reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS); - - if (value_addr == LLDB_INVALID_ADDRESS) - return false; - - if (exe_ctx.GetProcessRef().ReadMemory( - value_addr, heap_data_up->GetBytes(), heap_data_up->GetByteSize(), - error) != heap_data_up->GetByteSize()) { - return false; - } - } - - data.SetByteOrder(byte_order); - data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); - data.SetData(DataBufferSP(heap_data_up.release())); - return true; -} - -ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( - Thread &thread, CompilerType &return_compiler_type) const { - ValueObjectSP return_valobj_sp; - Value value; - - ExecutionContext exe_ctx(thread.shared_from_this()); - if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr) - return return_valobj_sp; - - // value.SetContext (Value::eContextTypeClangType, return_compiler_type); - value.SetCompilerType(return_compiler_type); - - RegisterContext *reg_ctx = thread.GetRegisterContext().get(); - if (!reg_ctx) - return return_valobj_sp; - - llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); - if (!byte_size) - return return_valobj_sp; - - const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); - if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { - value.SetValueType(Value::eValueTypeScalar); - - bool success = false; - if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { - // Extract the register context so we can read arguments from registers - if (*byte_size <= 8) { - const RegisterInfo *x0_reg_info = - reg_ctx->GetRegisterInfoByName("x0", 0); - if (x0_reg_info) { - uint64_t raw_value = - thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, - 0); - const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (*byte_size) { - default: - break; - case 16: // uint128_t - // In register x0 and x1 - { - const RegisterInfo *x1_reg_info = - reg_ctx->GetRegisterInfoByName("x1", 0); - - if (x1_reg_info) { - if (*byte_size <= - x0_reg_info->byte_size + x1_reg_info->byte_size) { - std::unique_ptr<DataBufferHeap> heap_data_up( - new DataBufferHeap(*byte_size, 0)); - const ByteOrder byte_order = - exe_ctx.GetProcessRef().GetByteOrder(); - RegisterValue x0_reg_value; - RegisterValue x1_reg_value; - if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) && - reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) { - Status error; - if (x0_reg_value.GetAsMemoryData( - x0_reg_info, heap_data_up->GetBytes() + 0, 8, - byte_order, error) && - x1_reg_value.GetAsMemoryData( - x1_reg_info, heap_data_up->GetBytes() + 8, 8, - byte_order, error)) { - DataExtractor data( - DataBufferSP(heap_data_up.release()), byte_order, - exe_ctx.GetProcessRef().GetAddressByteSize()); - - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); - return return_valobj_sp; - } - } - } - } - } - break; - case sizeof(uint64_t): - if (is_signed) - value.GetScalar() = (int64_t)(raw_value); - else - value.GetScalar() = (uint64_t)(raw_value); - success = true; - break; - - case sizeof(uint32_t): - if (is_signed) - value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); - else - value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); - success = true; - break; - - case sizeof(uint16_t): - if (is_signed) - value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); - else - value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); - success = true; - break; - - case sizeof(uint8_t): - if (is_signed) - value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); - else - value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); - success = true; - break; - } - } - } - } else if (type_flags & eTypeIsFloat) { - if (type_flags & eTypeIsComplex) { - // Don't handle complex yet. - } else { - if (*byte_size <= sizeof(long double)) { - const RegisterInfo *v0_reg_info = - reg_ctx->GetRegisterInfoByName("v0", 0); - RegisterValue v0_value; - if (reg_ctx->ReadRegister(v0_reg_info, v0_value)) { - DataExtractor data; - if (v0_value.GetData(data)) { - lldb::offset_t offset = 0; - if (*byte_size == sizeof(float)) { - value.GetScalar() = data.GetFloat(&offset); - success = true; - } else if (*byte_size == sizeof(double)) { - value.GetScalar() = data.GetDouble(&offset); - success = true; - } else if (*byte_size == sizeof(long double)) { - value.GetScalar() = data.GetLongDouble(&offset); - success = true; - } - } - } - } - } - } - - if (success) - return_valobj_sp = ValueObjectConstResult::Create( - thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); - } else if (type_flags & eTypeIsVector) { - if (*byte_size > 0) { - - const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); - - if (v0_info) { - if (*byte_size <= v0_info->byte_size) { - std::unique_ptr<DataBufferHeap> heap_data_up( - new DataBufferHeap(*byte_size, 0)); - const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); - RegisterValue reg_value; - if (reg_ctx->ReadRegister(v0_info, reg_value)) { - Status error; - if (reg_value.GetAsMemoryData(v0_info, heap_data_up->GetBytes(), - heap_data_up->GetByteSize(), - byte_order, error)) { - DataExtractor data(DataBufferSP(heap_data_up.release()), - byte_order, - exe_ctx.GetProcessRef().GetAddressByteSize()); - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); - } - } - } - } - } - } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) { - DataExtractor data; - - uint32_t NGRN = 0; // Search ABI docs for NGRN - uint32_t NSRN = 0; // Search ABI docs for NSRN - const bool is_return_value = true; - if (LoadValueFromConsecutiveGPRRegisters( - exe_ctx, reg_ctx, return_compiler_type, is_return_value, NGRN, NSRN, - data)) { - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); - } - } - return return_valobj_sp; -} - -void ABIMacOSX_arm64::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), pluginDesc, - CreateInstance); -} - -void ABIMacOSX_arm64::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -// PluginInterface protocol - -ConstString ABIMacOSX_arm64::GetPluginNameStatic() { - static ConstString g_plugin_name("ABIMacOSX_arm64"); - return g_plugin_name; -} - -uint32_t ABIMacOSX_arm64::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/ABI/Mips/ABIMips.cpp b/lldb/source/Plugins/ABI/Mips/ABIMips.cpp new file mode 100644 index 000000000000..16ef1faf9d9d --- /dev/null +++ b/lldb/source/Plugins/ABI/Mips/ABIMips.cpp @@ -0,0 +1,24 @@ +//===-- Mips.h ------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ABIMips.h" +#include "ABISysV_mips.h" +#include "ABISysV_mips64.h" +#include "lldb/Core/PluginManager.h" + +LLDB_PLUGIN_DEFINE(ABIMips) + +void ABIMips::Initialize() { + ABISysV_mips::Initialize(); + ABISysV_mips64::Initialize(); +} + +void ABIMips::Terminate() { + ABISysV_mips::Terminate(); + ABISysV_mips64::Terminate(); +} diff --git a/lldb/source/Plugins/ABI/Mips/ABIMips.h b/lldb/source/Plugins/ABI/Mips/ABIMips.h new file mode 100644 index 000000000000..dc7704de1c96 --- /dev/null +++ b/lldb/source/Plugins/ABI/Mips/ABIMips.h @@ -0,0 +1,17 @@ +//===-- Mips.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_ABI_MIPS_ABIMIPS_H +#define LLDB_SOURCE_PLUGINS_ABI_MIPS_ABIMIPS_H + +class ABIMips { +public: + static void Initialize(); + static void Terminate(); +}; +#endif diff --git a/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp b/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp index 416db9f5ae87..d66e0926ad99 100644 --- a/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp +++ b/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_mips.cpp ----------------------------------------*- C++ -*-===// +//===-- ABISysV_mips.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,6 +32,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ABISysV_mips) + enum dwarf_regnums { dwarf_r0 = 0, dwarf_r1, diff --git a/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.h b/lldb/source/Plugins/ABI/Mips/ABISysV_mips.h index 8143f552fc4d..715405e7ef97 100644 --- a/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.h +++ b/lldb/source/Plugins/ABI/Mips/ABISysV_mips.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_mips_h_ -#define liblldb_ABISysV_mips_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_MIPS_ABISYSV_MIPS_H +#define LLDB_SOURCE_PLUGINS_ABI_MIPS_ABISYSV_MIPS_H #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABISysV_mips : public lldb_private::ABI { +class ABISysV_mips : public lldb_private::RegInfoBasedABI { public: ~ABISysV_mips() override = default; @@ -87,11 +87,7 @@ protected: bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); private: - ABISysV_mips(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_mips_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_MIPS_ABISYSV_MIPS_H diff --git a/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp b/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp index 72ec0715b6cd..bb28a50e5f4a 100644 --- a/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp +++ b/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_mips64.cpp --------------------------------------*- C++ -*-===// +//===-- ABISysV_mips64.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,6 +32,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ABISysV_mips64) + enum dwarf_regnums { dwarf_r0 = 0, dwarf_r1, diff --git a/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h b/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.h index 76c3c5413b92..91428216a73a 100644 --- a/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h +++ b/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_mips64_h_ -#define liblldb_ABISysV_mips64_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_MIPS_ABISYSV_MIPS64_H +#define LLDB_SOURCE_PLUGINS_ABI_MIPS_ABISYSV_MIPS64_H #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABISysV_mips64 : public lldb_private::ABI { +class ABISysV_mips64 : public lldb_private::RegInfoBasedABI { public: ~ABISysV_mips64() override = default; @@ -51,7 +51,7 @@ public: // // To work around this, we relax that alignment to be just word-size // (8-bytes). - // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // Allowing the trap handlers for user space would be easy (_sigtramp) but // in other environments there can be a large number of different functions // involved in async traps. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { @@ -100,11 +100,7 @@ protected: bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); private: - ABISysV_mips64(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_mips64_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_MIPS_ABISYSV_MIPS64_H diff --git a/lldb/source/Plugins/ABI/PowerPC/ABIPowerPC.cpp b/lldb/source/Plugins/ABI/PowerPC/ABIPowerPC.cpp new file mode 100644 index 000000000000..b561e3c93f57 --- /dev/null +++ b/lldb/source/Plugins/ABI/PowerPC/ABIPowerPC.cpp @@ -0,0 +1,24 @@ +//===-- PowerPC.h ---------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ABIPowerPC.h" +#include "ABISysV_ppc.h" +#include "ABISysV_ppc64.h" +#include "lldb/Core/PluginManager.h" + +LLDB_PLUGIN_DEFINE(ABIPowerPC) + +void ABIPowerPC::Initialize() { + ABISysV_ppc::Initialize(); + ABISysV_ppc64::Initialize(); +} + +void ABIPowerPC::Terminate() { + ABISysV_ppc::Terminate(); + ABISysV_ppc64::Terminate(); +} diff --git a/lldb/source/Plugins/ABI/PowerPC/ABIPowerPC.h b/lldb/source/Plugins/ABI/PowerPC/ABIPowerPC.h new file mode 100644 index 000000000000..5e745eae0a42 --- /dev/null +++ b/lldb/source/Plugins/ABI/PowerPC/ABIPowerPC.h @@ -0,0 +1,17 @@ +//===-- PowerPC.h -----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_ABI_POWERPC_ABIPOWERPC_H +#define LLDB_SOURCE_PLUGINS_ABI_POWERPC_ABIPOWERPC_H + +class ABIPowerPC { +public: + static void Initialize(); + static void Terminate(); +}; +#endif diff --git a/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp index 857b7fee10e3..6f5eded7b031 100644 --- a/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_ppc.cpp -----------------------------------------*- C++ -*-===// +//===-- ABISysV_ppc.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,6 +32,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ABISysV_ppc) + enum dwarf_regnums { dwarf_r0 = 0, dwarf_r1, diff --git a/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.h index 59907c4648ba..4a586849e585 100644 --- a/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_ppc_h_ -#define liblldb_ABISysV_ppc_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_POWERPC_ABISYSV_PPC_H +#define LLDB_SOURCE_PLUGINS_ABI_POWERPC_ABISYSV_PPC_H #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABISysV_ppc : public lldb_private::ABI { +class ABISysV_ppc : public lldb_private::RegInfoBasedABI { public: ~ABISysV_ppc() override = default; @@ -49,7 +49,7 @@ public: // // To work around this, we relax that alignment to be just word-size // (8-bytes). - // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // Allowing the trap handlers for user space would be easy (_sigtramp) but // in other environments there can be a large number of different functions // involved in async traps. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { @@ -96,11 +96,7 @@ protected: bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); private: - ABISysV_ppc(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_ppc_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_POWERPC_ABISYSV_PPC_H diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 935353c38ca4..251ac972fd76 100644 --- a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_ppc64.cpp ---------------------------------------*- C++ -*-===// +//===-- ABISysV_ppc64.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -11,6 +11,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "Utility/PPC64LE_DWARF_Registers.h" #include "Utility/PPC64_DWARF_Registers.h" #include "lldb/Core/Module.h" @@ -19,7 +20,6 @@ #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" #include "lldb/Core/ValueObjectRegister.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -47,6 +47,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ABISysV_ppc64) + const lldb_private::RegisterInfo * ABISysV_ppc64::GetRegisterInfoArray(uint32_t &count) { if (GetByteOrder() == lldb::eByteOrderLittle) { @@ -806,10 +808,10 @@ private: // case 3: get from GPRs // first, check if this is a packed struct or not - ClangASTContext *ast = - llvm::dyn_cast<ClangASTContext>(m_type.GetTypeSystem()); + TypeSystemClang *ast = + llvm::dyn_cast<TypeSystemClang>(m_type.GetTypeSystem()); if (ast) { - clang::RecordDecl *record_decl = ClangASTContext::GetAsRecordDecl(m_type); + clang::RecordDecl *record_decl = TypeSystemClang::GetAsRecordDecl(m_type); if (record_decl) { auto attrs = record_decl->attrs(); diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h index 1b58975dd9d9..8dcf3ca48b56 100644 --- a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_ppc64_h_ -#define liblldb_ABISysV_ppc64_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_POWERPC_ABISYSV_PPC64_H +#define LLDB_SOURCE_PLUGINS_ABI_POWERPC_ABISYSV_PPC64_H #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABISysV_ppc64 : public lldb_private::ABI { +class ABISysV_ppc64 : public lldb_private::RegInfoBasedABI { public: ~ABISysV_ppc64() override = default; @@ -49,7 +49,7 @@ public: // // To work around this, we relax that alignment to be just word-size // (8-bytes). - // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // Allowing the trap handlers for user space would be easy (_sigtramp) but // in other environments there can be a large number of different functions // involved in async traps. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { @@ -96,13 +96,9 @@ protected: bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); private: - ABISysV_ppc64(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. lldb::ByteOrder GetByteOrder() const; }; -#endif // liblldb_ABISysV_ppc64_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_POWERPC_ABISYSV_PPC64_H diff --git a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp deleted file mode 100644 index 89a1f2b3cf04..000000000000 --- a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp +++ /dev/null @@ -1,2420 +0,0 @@ -//===-- ABISysV_arm64.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 "ABISysV_arm64.h" - -#include <vector> - -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Triple.h" - -#include "lldb/Core/Module.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/Value.h" -#include "lldb/Core/ValueObjectConstResult.h" -#include "lldb/Symbol/UnwindPlan.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Scalar.h" -#include "lldb/Utility/Status.h" - -#include "Utility/ARM64_DWARF_Registers.h" - -using namespace lldb; -using namespace lldb_private; - -static RegisterInfo g_register_infos[] = { - // NAME ALT SZ OFF ENCODING FORMAT - // EH_FRAME DWARF GENERIC - // PROCESS PLUGIN LLDB NATIVE - // ========== ======= == === ============= =================== - // =================== ====================== =========================== - // ======================= ====================== - {"x0", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x1", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x2", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x3", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x4", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x5", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x6", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x7", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x8", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x8, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x9", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x9, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x10", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x10, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x11", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x11, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x12", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x12, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x13", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x13, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x14", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x14, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x15", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x15, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x16", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x16, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x17", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x17, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x18", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x18, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x19", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x19, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x20", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x20, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x21", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x21, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x22", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x22, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x23", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x23, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x24", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x24, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x25", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x25, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x26", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x26, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x27", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x27, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"x28", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x28, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fp", - "x29", - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"lr", - "x30", - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"sp", - "x31", - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"pc", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"cpsr", - "psr", - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - - {"v0", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v1", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v2", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v3", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v4", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v5", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v6", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v7", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v8", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v9", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v10", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v11", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v12", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v13", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v14", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v15", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v16", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v17", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v18", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v19", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v20", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v21", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v22", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v23", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v24", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v25", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v26", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v27", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v28", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v29", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v30", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"v31", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - - {"fpsr", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fpcr", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - - {"s0", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s1", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s2", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s3", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s4", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s5", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s6", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s7", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s8", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s9", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s10", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s11", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s12", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s13", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s14", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s15", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s16", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s17", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s18", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s19", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s20", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s21", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s22", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s23", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s24", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s25", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s26", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s27", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s28", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s29", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s30", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"s31", - nullptr, - 4, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - - {"d0", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d1", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d2", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d3", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d4", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d5", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d6", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d7", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d8", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d9", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d10", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d11", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d12", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d13", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d14", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d15", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d16", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d17", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d18", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d19", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d20", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d21", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d22", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d23", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d24", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d25", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d26", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d27", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d28", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d29", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d30", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"d31", - nullptr, - 8, - 0, - eEncodingIEEE754, - eFormatFloat, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}}; - -static const uint32_t k_num_register_infos = - llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; - -const lldb_private::RegisterInfo * -ABISysV_arm64::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } - count = k_num_register_infos; - return g_register_infos; -} - -bool ABISysV_arm64::GetPointerReturnRegister(const char *&name) { - name = "x0"; - return true; -} - -size_t ABISysV_arm64::GetRedZoneSize() const { return 128; } - -// Static Functions - -ABISP -ABISysV_arm64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch(); - const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor(); - - if (vendor_type != llvm::Triple::Apple) { - if (arch_type == llvm::Triple::aarch64 || - arch_type == llvm::Triple::aarch64_32) { - return ABISP( - new ABISysV_arm64(std::move(process_sp), MakeMCRegisterInfo(arch))); - } - } - - return ABISP(); -} - -bool ABISysV_arm64::PrepareTrivialCall(Thread &thread, addr_t sp, - addr_t func_addr, addr_t return_addr, - llvm::ArrayRef<addr_t> args) const { - RegisterContext *reg_ctx = thread.GetRegisterContext().get(); - if (!reg_ctx) - return false; - - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - if (log) { - StreamString s; - s.Printf("ABISysV_arm64::PrepareTrivialCall (tid = 0x%" PRIx64 - ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 - ", return_addr = 0x%" PRIx64, - thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, - (uint64_t)return_addr); - - for (size_t i = 0; i < args.size(); ++i) - s.Printf(", arg%d = 0x%" PRIx64, static_cast<int>(i + 1), args[i]); - s.PutCString(")"); - log->PutString(s.GetString()); - } - - // x0 - x7 contain first 8 simple args - if (args.size() > 8) - return false; - - for (size_t i = 0; i < args.size(); ++i) { - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); - LLDB_LOGF(log, "About to write arg%d (0x%" PRIx64 ") into %s", - static_cast<int>(i + 1), args[i], reg_info->name); - if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) - return false; - } - - // Set "lr" to the return address - if (!reg_ctx->WriteRegisterFromUnsigned( - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_RA), - return_addr)) - return false; - - // Set "sp" to the requested value - if (!reg_ctx->WriteRegisterFromUnsigned( - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_SP), - sp)) - return false; - - // Set "pc" to the address requested - if (!reg_ctx->WriteRegisterFromUnsigned( - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC), - func_addr)) - return false; - - return true; -} - -// TODO: We dont support fp/SIMD arguments in v0-v7 -bool ABISysV_arm64::GetArgumentValues(Thread &thread, ValueList &values) const { - uint32_t num_values = values.GetSize(); - - ExecutionContext exe_ctx(thread.shared_from_this()); - - // Extract the register context so we can read arguments from registers - - RegisterContext *reg_ctx = thread.GetRegisterContext().get(); - - if (!reg_ctx) - return false; - - addr_t sp = 0; - - for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { - // We currently only support extracting values with Clang QualTypes. Do we - // care about others? - Value *value = values.GetValueAtIndex(value_idx); - - if (!value) - return false; - - CompilerType value_type = value->GetCompilerType(); - if (value_type) { - bool is_signed = false; - size_t bit_width = 0; - llvm::Optional<uint64_t> bit_size = value_type.GetBitSize(&thread); - if (!bit_size) - return false; - if (value_type.IsIntegerOrEnumerationType(is_signed)) { - bit_width = *bit_size; - } else if (value_type.IsPointerOrReferenceType()) { - bit_width = *bit_size; - } else { - // We only handle integer, pointer and reference types currently... - return false; - } - - if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) { - if (value_idx < 8) { - // Arguments 1-8 are in x0-x7... - const RegisterInfo *reg_info = nullptr; - reg_info = reg_ctx->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx); - - if (reg_info) { - RegisterValue reg_value; - - if (reg_ctx->ReadRegister(reg_info, reg_value)) { - if (is_signed) - reg_value.SignExtend(bit_width); - if (!reg_value.GetScalarValue(value->GetScalar())) - return false; - continue; - } - } - return false; - } else { - // TODO: Verify for stack layout for SysV - if (sp == 0) { - // Read the stack pointer if we already haven't read it - sp = reg_ctx->GetSP(0); - if (sp == 0) - return false; - } - - // Arguments 5 on up are on the stack - const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8; - Status error; - if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory( - sp, arg_byte_size, is_signed, value->GetScalar(), error)) - return false; - - sp += arg_byte_size; - // Align up to the next 8 byte boundary if needed - if (sp % 8) { - sp >>= 3; - sp += 1; - sp <<= 3; - } - } - } - } - } - return true; -} - -Status ABISysV_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, - lldb::ValueObjectSP &new_value_sp) { - Status error; - if (!new_value_sp) { - error.SetErrorString("Empty value object for return value."); - return error; - } - - CompilerType return_value_type = new_value_sp->GetCompilerType(); - if (!return_value_type) { - error.SetErrorString("Null clang type for return value."); - return error; - } - - Thread *thread = frame_sp->GetThread().get(); - - RegisterContext *reg_ctx = thread->GetRegisterContext().get(); - - if (reg_ctx) { - DataExtractor data; - Status data_error; - const uint64_t byte_size = new_value_sp->GetData(data, data_error); - if (data_error.Fail()) { - error.SetErrorStringWithFormat( - "Couldn't convert return value to raw data: %s", - data_error.AsCString()); - return error; - } - - const uint32_t type_flags = return_value_type.GetTypeInfo(nullptr); - if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { - if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { - // Extract the register context so we can read arguments from registers - lldb::offset_t offset = 0; - if (byte_size <= 16) { - const RegisterInfo *x0_info = reg_ctx->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); - if (byte_size <= 8) { - uint64_t raw_value = data.GetMaxU64(&offset, byte_size); - - if (!reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) - error.SetErrorString("failed to write register x0"); - } else { - uint64_t raw_value = data.GetMaxU64(&offset, 8); - - if (reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) { - const RegisterInfo *x1_info = reg_ctx->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2); - raw_value = data.GetMaxU64(&offset, byte_size - offset); - - if (!reg_ctx->WriteRegisterFromUnsigned(x1_info, raw_value)) - error.SetErrorString("failed to write register x1"); - } - } - } else { - error.SetErrorString("We don't support returning longer than 128 bit " - "integer values at present."); - } - } else if (type_flags & eTypeIsFloat) { - if (type_flags & eTypeIsComplex) { - // Don't handle complex yet. - error.SetErrorString( - "returning complex float values are not supported"); - } else { - const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); - - if (v0_info) { - if (byte_size <= 16) { - if (byte_size <= RegisterValue::GetMaxByteSize()) { - RegisterValue reg_value; - error = reg_value.SetValueFromData(v0_info, data, 0, true); - if (error.Success()) { - if (!reg_ctx->WriteRegister(v0_info, reg_value)) - error.SetErrorString("failed to write register v0"); - } - } else { - error.SetErrorStringWithFormat( - "returning float values with a byte size of %" PRIu64 - " are not supported", - byte_size); - } - } else { - error.SetErrorString("returning float values longer than 128 " - "bits are not supported"); - } - } else { - error.SetErrorString("v0 register is not available on this target"); - } - } - } - } else if (type_flags & eTypeIsVector) { - if (byte_size > 0) { - const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); - - if (v0_info) { - if (byte_size <= v0_info->byte_size) { - RegisterValue reg_value; - error = reg_value.SetValueFromData(v0_info, data, 0, true); - if (error.Success()) { - if (!reg_ctx->WriteRegister(v0_info, reg_value)) - error.SetErrorString("failed to write register v0"); - } - } - } - } - } - } else { - error.SetErrorString("no registers are available"); - } - - return error; -} - -bool ABISysV_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { - unwind_plan.Clear(); - unwind_plan.SetRegisterKind(eRegisterKindDWARF); - - uint32_t lr_reg_num = arm64_dwarf::lr; - uint32_t sp_reg_num = arm64_dwarf::sp; - - UnwindPlan::RowSP row(new UnwindPlan::Row); - - // Our previous Call Frame Address is the stack pointer - row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - - unwind_plan.AppendRow(row); - unwind_plan.SetReturnAddressRegister(lr_reg_num); - - // All other registers are the same. - - unwind_plan.SetSourceName("arm64 at-func-entry default"); - unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); - unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); - - return true; -} - -bool ABISysV_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { - unwind_plan.Clear(); - unwind_plan.SetRegisterKind(eRegisterKindDWARF); - - uint32_t fp_reg_num = arm64_dwarf::fp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::RowSP row(new UnwindPlan::Row); - const int32_t ptr_size = 8; - - row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); - row->SetOffset(0); - - row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); - row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); - - unwind_plan.AppendRow(row); - unwind_plan.SetSourceName("arm64 default unwind plan"); - unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); - unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); - - return true; -} - -// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says -// registers x19 through x28 and sp are callee preserved. v8-v15 are non- -// volatile (and specifically only the lower 8 bytes of these regs), the rest -// of the fp/SIMD registers are volatile. - -// We treat x29 as callee preserved also, else the unwinder won't try to -// retrieve fp saves. - -bool ABISysV_arm64::RegisterIsVolatile(const RegisterInfo *reg_info) { - if (reg_info) { - const char *name = reg_info->name; - - // Sometimes we'll be called with the "alternate" name for these registers; - // recognize them as non-volatile. - - if (name[0] == 'p' && name[1] == 'c') // pc - return false; - if (name[0] == 'f' && name[1] == 'p') // fp - return false; - if (name[0] == 's' && name[1] == 'p') // sp - return false; - if (name[0] == 'l' && name[1] == 'r') // lr - return false; - - if (name[0] == 'x' || name[0] == 'r') { - // Volatile registers: x0-x18 - // Although documentation says only x19-28 + sp are callee saved We ll - // also have to treat x30 as non-volatile. Each dwarf frame has its own - // value of lr. Return false for the non-volatile gpr regs, true for - // everything else - switch (name[1]) { - case '1': - switch (name[2]) { - case '9': - return false; // x19 is non-volatile - default: - return true; - } - break; - case '2': - switch (name[2]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - return false; // x20 - 28 are non-volatile - case '9': - return false; // x29 aka fp treat as non-volatile - default: - return true; - } - case '3': // x30 (lr) and x31 (sp) treat as non-volatile - if (name[2] == '0' || name[2] == '1') - return false; - break; - default: - return true; // all volatile cases not handled above fall here. - } - } else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd') { - // Volatile registers: v0-7, v16-v31 - // Return false for non-volatile fp/SIMD regs, true for everything else - switch (name[1]) { - case '8': - case '9': - return false; // v8-v9 are non-volatile - case '1': - switch (name[2]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - return false; // v10-v15 are non-volatile - default: - return true; - } - default: - return true; - } - } - } - return true; -} - -static bool LoadValueFromConsecutiveGPRRegisters( - ExecutionContext &exe_ctx, RegisterContext *reg_ctx, - const CompilerType &value_type, - bool is_return_value, // false => parameter, true => return value - uint32_t &NGRN, // NGRN (see ABI documentation) - uint32_t &NSRN, // NSRN (see ABI documentation) - DataExtractor &data) { - llvm::Optional<uint64_t> byte_size = value_type.GetByteSize(nullptr); - - if (byte_size || *byte_size == 0) - return false; - - std::unique_ptr<DataBufferHeap> heap_data_up( - new DataBufferHeap(*byte_size, 0)); - const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); - Status error; - - CompilerType base_type; - const uint32_t homogeneous_count = - value_type.IsHomogeneousAggregate(&base_type); - if (homogeneous_count > 0 && homogeneous_count <= 8) { - // Make sure we have enough registers - if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { - if (!base_type) - return false; - llvm::Optional<uint64_t> base_byte_size = base_type.GetByteSize(nullptr); - if (!base_byte_size) - return false; - uint32_t data_offset = 0; - - for (uint32_t i = 0; i < homogeneous_count; ++i) { - char v_name[8]; - ::snprintf(v_name, sizeof(v_name), "v%u", NSRN); - const RegisterInfo *reg_info = - reg_ctx->GetRegisterInfoByName(v_name, 0); - if (reg_info == nullptr) - return false; - - if (*base_byte_size > reg_info->byte_size) - return false; - - RegisterValue reg_value; - - if (!reg_ctx->ReadRegister(reg_info, reg_value)) - return false; - - // Make sure we have enough room in "heap_data_up" - if ((data_offset + *base_byte_size) <= heap_data_up->GetByteSize()) { - const size_t bytes_copied = reg_value.GetAsMemoryData( - reg_info, heap_data_up->GetBytes() + data_offset, *base_byte_size, - byte_order, error); - if (bytes_copied != *base_byte_size) - return false; - data_offset += bytes_copied; - ++NSRN; - } else - return false; - } - data.SetByteOrder(byte_order); - data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); - data.SetData(DataBufferSP(heap_data_up.release())); - return true; - } - } - - const size_t max_reg_byte_size = 16; - if (*byte_size <= max_reg_byte_size) { - size_t bytes_left = *byte_size; - uint32_t data_offset = 0; - while (data_offset < *byte_size) { - if (NGRN >= 8) - return false; - - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); - if (reg_info == nullptr) - return false; - - RegisterValue reg_value; - - if (!reg_ctx->ReadRegister(reg_info, reg_value)) - return false; - - const size_t curr_byte_size = std::min<size_t>(8, bytes_left); - const size_t bytes_copied = reg_value.GetAsMemoryData( - reg_info, heap_data_up->GetBytes() + data_offset, curr_byte_size, - byte_order, error); - if (bytes_copied == 0) - return false; - if (bytes_copied >= bytes_left) - break; - data_offset += bytes_copied; - bytes_left -= bytes_copied; - ++NGRN; - } - } else { - const RegisterInfo *reg_info = nullptr; - if (is_return_value) { - // We are assuming we are decoding this immediately after returning from - // a function call and that the address of the structure is in x8 - reg_info = reg_ctx->GetRegisterInfoByName("x8", 0); - } else { - // We are assuming we are stopped at the first instruction in a function - // and that the ABI is being respected so all parameters appear where - // they should be (functions with no external linkage can legally violate - // the ABI). - if (NGRN >= 8) - return false; - - reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_ARG1 + NGRN); - if (reg_info == nullptr) - return false; - ++NGRN; - } - - if (reg_info == nullptr) - return false; - - const lldb::addr_t value_addr = - reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS); - - if (value_addr == LLDB_INVALID_ADDRESS) - return false; - - if (exe_ctx.GetProcessRef().ReadMemory( - value_addr, heap_data_up->GetBytes(), heap_data_up->GetByteSize(), - error) != heap_data_up->GetByteSize()) { - return false; - } - } - - data.SetByteOrder(byte_order); - data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); - data.SetData(DataBufferSP(heap_data_up.release())); - return true; -} - -ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( - Thread &thread, CompilerType &return_compiler_type) const { - ValueObjectSP return_valobj_sp; - Value value; - - ExecutionContext exe_ctx(thread.shared_from_this()); - if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr) - return return_valobj_sp; - - // value.SetContext (Value::eContextTypeClangType, return_compiler_type); - value.SetCompilerType(return_compiler_type); - - RegisterContext *reg_ctx = thread.GetRegisterContext().get(); - if (!reg_ctx) - return return_valobj_sp; - - llvm::Optional<uint64_t> byte_size = - return_compiler_type.GetByteSize(nullptr); - if (!byte_size) - return return_valobj_sp; - - const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); - if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { - value.SetValueType(Value::eValueTypeScalar); - - bool success = false; - if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { - // Extract the register context so we can read arguments from registers - if (*byte_size <= 8) { - const RegisterInfo *x0_reg_info = nullptr; - x0_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_ARG1); - if (x0_reg_info) { - uint64_t raw_value = - thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, - 0); - const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (*byte_size) { - default: - break; - case 16: // uint128_t - // In register x0 and x1 - { - const RegisterInfo *x1_reg_info = nullptr; - x1_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_ARG2); - - if (x1_reg_info) { - if (*byte_size <= - x0_reg_info->byte_size + x1_reg_info->byte_size) { - std::unique_ptr<DataBufferHeap> heap_data_up( - new DataBufferHeap(*byte_size, 0)); - const ByteOrder byte_order = - exe_ctx.GetProcessRef().GetByteOrder(); - RegisterValue x0_reg_value; - RegisterValue x1_reg_value; - if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) && - reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) { - Status error; - if (x0_reg_value.GetAsMemoryData( - x0_reg_info, heap_data_up->GetBytes() + 0, 8, - byte_order, error) && - x1_reg_value.GetAsMemoryData( - x1_reg_info, heap_data_up->GetBytes() + 8, 8, - byte_order, error)) { - DataExtractor data( - DataBufferSP(heap_data_up.release()), byte_order, - exe_ctx.GetProcessRef().GetAddressByteSize()); - - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); - return return_valobj_sp; - } - } - } - } - } - break; - case sizeof(uint64_t): - if (is_signed) - value.GetScalar() = (int64_t)(raw_value); - else - value.GetScalar() = (uint64_t)(raw_value); - success = true; - break; - - case sizeof(uint32_t): - if (is_signed) - value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); - else - value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); - success = true; - break; - - case sizeof(uint16_t): - if (is_signed) - value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); - else - value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); - success = true; - break; - - case sizeof(uint8_t): - if (is_signed) - value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); - else - value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); - success = true; - break; - } - } - } - } else if (type_flags & eTypeIsFloat) { - if (type_flags & eTypeIsComplex) { - // Don't handle complex yet. - } else { - if (*byte_size <= sizeof(long double)) { - const RegisterInfo *v0_reg_info = - reg_ctx->GetRegisterInfoByName("v0", 0); - RegisterValue v0_value; - if (reg_ctx->ReadRegister(v0_reg_info, v0_value)) { - DataExtractor data; - if (v0_value.GetData(data)) { - lldb::offset_t offset = 0; - if (*byte_size == sizeof(float)) { - value.GetScalar() = data.GetFloat(&offset); - success = true; - } else if (*byte_size == sizeof(double)) { - value.GetScalar() = data.GetDouble(&offset); - success = true; - } else if (*byte_size == sizeof(long double)) { - value.GetScalar() = data.GetLongDouble(&offset); - success = true; - } - } - } - } - } - } - - if (success) - return_valobj_sp = ValueObjectConstResult::Create( - thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); - } else if (type_flags & eTypeIsVector && *byte_size <= 16) { - if (*byte_size > 0) { - const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); - - if (v0_info) { - std::unique_ptr<DataBufferHeap> heap_data_up( - new DataBufferHeap(*byte_size, 0)); - const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); - RegisterValue reg_value; - if (reg_ctx->ReadRegister(v0_info, reg_value)) { - Status error; - if (reg_value.GetAsMemoryData(v0_info, heap_data_up->GetBytes(), - heap_data_up->GetByteSize(), byte_order, - error)) { - DataExtractor data(DataBufferSP(heap_data_up.release()), byte_order, - exe_ctx.GetProcessRef().GetAddressByteSize()); - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); - } - } - } - } - } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass || - (type_flags & eTypeIsVector && *byte_size > 16)) { - DataExtractor data; - - uint32_t NGRN = 0; // Search ABI docs for NGRN - uint32_t NSRN = 0; // Search ABI docs for NSRN - const bool is_return_value = true; - if (LoadValueFromConsecutiveGPRRegisters( - exe_ctx, reg_ctx, return_compiler_type, is_return_value, NGRN, NSRN, - data)) { - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); - } - } - return return_valobj_sp; -} - -void ABISysV_arm64::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - "SysV ABI for AArch64 targets", CreateInstance); -} - -void ABISysV_arm64::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -lldb_private::ConstString ABISysV_arm64::GetPluginNameStatic() { - static ConstString g_name("SysV-arm64"); - return g_name; -} - -// PluginInterface protocol - -ConstString ABISysV_arm64::GetPluginName() { return GetPluginNameStatic(); } - -uint32_t ABISysV_arm64::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp b/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp index f4f803a8277d..eced2adc7591 100644 --- a/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp +++ b/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_s390x.cpp ---------------------------------------*- C++ -*-===// +//===-- ABISysV_s390x.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,6 +32,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(ABISysV_s390x, ABISystemZ) + enum dwarf_regnums { // General Purpose Registers dwarf_r0_s390x = 0, diff --git a/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h b/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.h index 671d6a18260e..f8f412465658 100644 --- a/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h +++ b/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_s390x_h_ -#define liblldb_ABISysV_s390x_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_SYSTEMZ_ABISYSV_S390X_H +#define LLDB_SOURCE_PLUGINS_ABI_SYSTEMZ_ABISYSV_S390X_H #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABISysV_s390x : public lldb_private::ABI { +class ABISysV_s390x : public lldb_private::RegInfoBasedABI { public: ~ABISysV_s390x() override = default; @@ -88,11 +88,7 @@ protected: bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); private: - ABISysV_s390x(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_s390x_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_SYSTEMZ_ABISYSV_S390X_H diff --git a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp index 76ebd6476ffd..89112deb2c4a 100644 --- a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp @@ -1,4 +1,4 @@ -//===-- ABIMacOSX_i386.cpp --------------------------------------*- C++ -*-===// +//===-- ABIMacOSX_i386.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -29,20 +29,7 @@ using namespace lldb; using namespace lldb_private; -enum { - ehframe_eax = 0, - ehframe_ecx, - ehframe_edx, - ehframe_ebx, - ehframe_ebp, // Different from DWARF the regnums - eh_frame esp/ebp had their - // regnums switched on i386 darwin - ehframe_esp, // Different from DWARF the regnums - eh_frame esp/ebp had their - // regnums switched on i386 darwin - ehframe_esi, - ehframe_edi, - ehframe_eip, - ehframe_eflags -}; +LLDB_PLUGIN_DEFINE(ABIMacOSX_i386) enum { dwarf_eax = 0, @@ -54,653 +41,8 @@ enum { dwarf_esi, dwarf_edi, dwarf_eip, - dwarf_eflags, - dwarf_stmm0 = 11, - dwarf_stmm1, - dwarf_stmm2, - dwarf_stmm3, - dwarf_stmm4, - dwarf_stmm5, - dwarf_stmm6, - dwarf_stmm7, - dwarf_xmm0 = 21, - dwarf_xmm1, - dwarf_xmm2, - dwarf_xmm3, - dwarf_xmm4, - dwarf_xmm5, - dwarf_xmm6, - dwarf_xmm7, - dwarf_ymm0 = dwarf_xmm0, - dwarf_ymm1 = dwarf_xmm1, - dwarf_ymm2 = dwarf_xmm2, - dwarf_ymm3 = dwarf_xmm3, - dwarf_ymm4 = dwarf_xmm4, - dwarf_ymm5 = dwarf_xmm5, - dwarf_ymm6 = dwarf_xmm6, - dwarf_ymm7 = dwarf_xmm7 }; -static RegisterInfo g_register_infos[] = { - // NAME ALT SZ OFF ENCODING FORMAT - // EH_FRAME DWARF GENERIC - // PROCESS PLUGIN LLDB NATIVE - // ====== ======= == === ============= ============ - // ===================== ===================== ============================ - // ==================== ====================== - {"eax", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_eax, dwarf_eax, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ebx", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ecx", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_ecx, dwarf_ecx, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"edx", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_edx, dwarf_edx, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"esi", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_esi, dwarf_esi, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"edi", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_edi, dwarf_edi, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ebp", - "fp", - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"esp", - "sp", - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"eip", - "pc", - 4, - 0, - eEncodingUint, - eFormatHex, - {ehframe_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"eflags", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"cs", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ss", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ds", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"es", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fs", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"gs", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm0", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_stmm0, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm1", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_stmm1, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm2", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_stmm2, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm3", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_stmm3, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm4", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_stmm4, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm5", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_stmm5, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm6", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_stmm6, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm7", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_stmm7, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fctrl", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fstat", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ftag", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fiseg", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fioff", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"foseg", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fooff", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fop", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm0", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_xmm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm1", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_xmm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm2", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_xmm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm3", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_xmm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm4", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_xmm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm5", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_xmm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm6", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_xmm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm7", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_xmm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"mxcsr", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm0", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_ymm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm1", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_ymm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm2", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_ymm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm3", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_ymm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm4", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_ymm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm5", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_ymm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm6", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_ymm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm7", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, dwarf_ymm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}}; - -static const uint32_t k_num_register_infos = - llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; - -const lldb_private::RegisterInfo * -ABIMacOSX_i386::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } - count = k_num_register_infos; - return g_register_infos; -} - size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; } // Static Functions diff --git a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.h index 50062b84d878..b8b253144165 100644 --- a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h +++ b/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.h @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABIMacOSX_i386_h_ -#define liblldb_ABIMacOSX_i386_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_X86_ABIMACOSX_I386_H +#define LLDB_SOURCE_PLUGINS_ABI_X86_ABIMACOSX_I386_H +#include "Plugins/ABI/X86/ABIX86.h" #include "lldb/Core/Value.h" -#include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" -class ABIMacOSX_i386 : public lldb_private::ABI { +class ABIMacOSX_i386 : public ABIX86 { public: ~ABIMacOSX_i386() override = default; @@ -45,7 +45,7 @@ public: // // To work around this, we relax that alignment to be just word-size // (4-bytes). - // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // Allowing the trap handlers for user space would be easy (_sigtramp) but // in other environments there can be a large number of different functions // involved in async traps. // @@ -65,9 +65,6 @@ public: return pc <= UINT32_MAX; } - const lldb_private::RegisterInfo * - GetRegisterInfoArray(uint32_t &count) override; - // Static Functions static void Initialize(); @@ -91,12 +88,13 @@ protected: bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); -private: - ABIMacOSX_i386(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. + std::string GetMCName(std::string name) override { + MapRegisterName(name, "stmm", "st"); + return name; } + +private: + using ABIX86::ABIX86; // Call CreateInstance instead. }; -#endif // liblldb_ABIMacOSX_i386_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_X86_ABIMACOSX_I386_H diff --git a/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp b/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp index 69e4cff90ebf..2ac87d1512e9 100644 --- a/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp +++ b/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp @@ -1,4 +1,4 @@ -//===----------------------- ABISysV_i386.cpp -------------------*- C++ -*-===// +//===-- ABISysV_i386.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -31,6 +31,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ABISysV_i386) + // This source file uses the following document as a reference: //==================================================================== // System V Application Binary Interface @@ -63,135 +65,8 @@ enum dwarf_regnums { dwarf_esi, dwarf_edi, dwarf_eip, - dwarf_eflags, - - dwarf_st0 = 11, - dwarf_st1, - dwarf_st2, - dwarf_st3, - dwarf_st4, - dwarf_st5, - dwarf_st6, - dwarf_st7, - - dwarf_xmm0 = 21, - dwarf_xmm1, - dwarf_xmm2, - dwarf_xmm3, - dwarf_xmm4, - dwarf_xmm5, - dwarf_xmm6, - dwarf_xmm7, - dwarf_ymm0 = dwarf_xmm0, - dwarf_ymm1 = dwarf_xmm1, - dwarf_ymm2 = dwarf_xmm2, - dwarf_ymm3 = dwarf_xmm3, - dwarf_ymm4 = dwarf_xmm4, - dwarf_ymm5 = dwarf_xmm5, - dwarf_ymm6 = dwarf_xmm6, - dwarf_ymm7 = dwarf_xmm7, - - dwarf_mm0 = 29, - dwarf_mm1, - dwarf_mm2, - dwarf_mm3, - dwarf_mm4, - dwarf_mm5, - dwarf_mm6, - dwarf_mm7, - - dwarf_bnd0 = 101, - dwarf_bnd1, - dwarf_bnd2, - dwarf_bnd3 -}; - -static RegisterInfo g_register_infos[] = { - // clang-format off - //NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB NATIVE VALUE INVAL DYN EXPR SZ - //========== ======= == === ============= ==================== =================== =================== ========================= =================== =================== ======= ======= ======== == - {"eax", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_eax, dwarf_eax, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ebx", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ecx", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_ecx, dwarf_ecx, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"edx", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_edx, dwarf_edx, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"esi", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_esi, dwarf_esi, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"edi", nullptr, 4, 0, eEncodingUint, eFormatHex, {dwarf_edi, dwarf_edi, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ebp", "fp", 4, 0, eEncodingUint, eFormatHex, {dwarf_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"esp", "sp", 4, 0, eEncodingUint, eFormatHex, {dwarf_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"eip", "pc", 4, 0, eEncodingUint, eFormatHex, {dwarf_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"eflags", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"cs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ss", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ds", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"es", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"gs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"st0", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"st1", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"st2", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"st3", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"st4", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"st5", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"st6", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"st7", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_st7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fctrl", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fstat", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ftag", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fiseg", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fioff", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"foseg", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fooff", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fop", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm0", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm1", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm2", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm3", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm4", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm5", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm6", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm7", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_xmm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"mxcsr", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm0", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm1", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm2", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm3", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm4", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm5", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm6", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm7", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, dwarf_ymm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bnd0", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{dwarf_bnd0, dwarf_bnd0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bnd1", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{dwarf_bnd1, dwarf_bnd1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bnd2", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{dwarf_bnd2, dwarf_bnd2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bnd3", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{dwarf_bnd3, dwarf_bnd3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bndcfgu", nullptr, 8, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bndstatus",nullptr, 8, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0} - // clang-format on }; -static const uint32_t k_num_register_infos = - llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; - -const lldb_private::RegisterInfo * -ABISysV_i386::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } - count = k_num_register_infos; - return g_register_infos; -} - // Static Functions ABISP diff --git a/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.h b/lldb/source/Plugins/ABI/X86/ABISysV_i386.h index 2362e9adda98..1ebb107d36df 100644 --- a/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.h +++ b/lldb/source/Plugins/ABI/X86/ABISysV_i386.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_i386_h_ -#define liblldb_ABISysV_i386_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_X86_ABISYSV_I386_H +#define LLDB_SOURCE_PLUGINS_ABI_X86_ABISYSV_I386_H -#include "lldb/Target/ABI.h" +#include "Plugins/ABI/X86/ABIX86.h" #include "lldb/lldb-private.h" -class ABISysV_i386 : public lldb_private::ABI { +class ABISysV_i386 : public ABIX86 { public: ~ABISysV_i386() override = default; @@ -53,7 +53,7 @@ public: // // To work around this, we relax that alignment to be just word-size // (4-bytes). - // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // Allowing the trap handlers for user space would be easy (_sigtramp) but // in other environments there can be a large number of different functions // involved in async traps. @@ -73,9 +73,6 @@ public: return (pc <= UINT32_MAX); } - const lldb_private::RegisterInfo * - GetRegisterInfoArray(uint32_t &count) override; - // Static Functions static void Initialize(); @@ -100,11 +97,7 @@ protected: bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); private: - ABISysV_i386(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using ABIX86::ABIX86; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_i386_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_X86_ABISYSV_I386_H diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp index bf1c48f778e1..7729e58f8580 100644 --- a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- ABISysV_x86_64.cpp --------------------------------------*- C++ -*-===// +//===-- ABISysV_x86_64.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -35,6 +35,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ABISysV_x86_64) + enum dwarf_regnums { dwarf_rax = 0, dwarf_rdx, @@ -53,162 +55,8 @@ enum dwarf_regnums { dwarf_r14, dwarf_r15, dwarf_rip, - dwarf_xmm0, - dwarf_xmm1, - dwarf_xmm2, - dwarf_xmm3, - dwarf_xmm4, - dwarf_xmm5, - dwarf_xmm6, - dwarf_xmm7, - dwarf_xmm8, - dwarf_xmm9, - dwarf_xmm10, - dwarf_xmm11, - dwarf_xmm12, - dwarf_xmm13, - dwarf_xmm14, - dwarf_xmm15, - dwarf_stmm0, - dwarf_stmm1, - dwarf_stmm2, - dwarf_stmm3, - dwarf_stmm4, - dwarf_stmm5, - dwarf_stmm6, - dwarf_stmm7, - dwarf_ymm0, - dwarf_ymm1, - dwarf_ymm2, - dwarf_ymm3, - dwarf_ymm4, - dwarf_ymm5, - dwarf_ymm6, - dwarf_ymm7, - dwarf_ymm8, - dwarf_ymm9, - dwarf_ymm10, - dwarf_ymm11, - dwarf_ymm12, - dwarf_ymm13, - dwarf_ymm14, - dwarf_ymm15, - dwarf_bnd0 = 126, - dwarf_bnd1, - dwarf_bnd2, - dwarf_bnd3 -}; - -static RegisterInfo g_register_infos[] = { - // clang-format off - // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC LLDB NATIVE - // ======== ======= == === ============= =================== ======================= ===================== =========================== ===================== ====================== - {"rax", nullptr, 8, 0, eEncodingUint, eFormatHex, {dwarf_rax, dwarf_rax, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rbx", nullptr, 8, 0, eEncodingUint, eFormatHex, {dwarf_rbx, dwarf_rbx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rcx", "arg4", 8, 0, eEncodingUint, eFormatHex, {dwarf_rcx, dwarf_rcx, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rdx", "arg3", 8, 0, eEncodingUint, eFormatHex, {dwarf_rdx, dwarf_rdx, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rsi", "arg2", 8, 0, eEncodingUint, eFormatHex, {dwarf_rsi, dwarf_rsi, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rdi", "arg1", 8, 0, eEncodingUint, eFormatHex, {dwarf_rdi, dwarf_rdi, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rbp", "fp", 8, 0, eEncodingUint, eFormatHex, {dwarf_rbp, dwarf_rbp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rsp", "sp", 8, 0, eEncodingUint, eFormatHex, {dwarf_rsp, dwarf_rsp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"r8", "arg5", 8, 0, eEncodingUint, eFormatHex, {dwarf_r8, dwarf_r8, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"r9", "arg6", 8, 0, eEncodingUint, eFormatHex, {dwarf_r9, dwarf_r9, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"r10", nullptr, 8, 0, eEncodingUint, eFormatHex, {dwarf_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"r11", nullptr, 8, 0, eEncodingUint, eFormatHex, {dwarf_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"r12", nullptr, 8, 0, eEncodingUint, eFormatHex, {dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"r13", nullptr, 8, 0, eEncodingUint, eFormatHex, {dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"r14", nullptr, 8, 0, eEncodingUint, eFormatHex, {dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"r15", nullptr, 8, 0, eEncodingUint, eFormatHex, {dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rip", "pc", 8, 0, eEncodingUint, eFormatHex, {dwarf_rip, dwarf_rip, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"rflags", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"cs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ss", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ds", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"es", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"gs", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"stmm0", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_stmm0, dwarf_stmm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"stmm1", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_stmm1, dwarf_stmm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"stmm2", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_stmm2, dwarf_stmm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"stmm3", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_stmm3, dwarf_stmm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"stmm4", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_stmm4, dwarf_stmm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"stmm5", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_stmm5, dwarf_stmm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"stmm6", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_stmm6, dwarf_stmm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"stmm7", nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_stmm7, dwarf_stmm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fctrl", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fstat", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ftag", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fiseg", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fioff", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"foseg", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fooff", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"fop", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm0", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm0, dwarf_xmm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm1", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm1, dwarf_xmm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm2", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm2, dwarf_xmm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm3", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm3, dwarf_xmm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm4", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm4, dwarf_xmm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm5", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm5, dwarf_xmm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm6", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm6, dwarf_xmm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm7", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm7, dwarf_xmm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm8", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm8, dwarf_xmm8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm9", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm9, dwarf_xmm9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm10", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm10, dwarf_xmm10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm11", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm11, dwarf_xmm11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm12", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm12, dwarf_xmm12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm13", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm13, dwarf_xmm13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm14", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm14, dwarf_xmm14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"xmm15", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_xmm15, dwarf_xmm15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"mxcsr", nullptr, 4, 0, eEncodingUint, eFormatHex, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm0", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm0, dwarf_ymm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm1", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm1, dwarf_ymm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm2", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm2, dwarf_ymm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm3", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm3, dwarf_ymm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm4", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm4, dwarf_ymm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm5", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm5, dwarf_ymm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm6", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm6, dwarf_ymm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm7", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm7, dwarf_ymm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm8", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm8, dwarf_ymm8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm9", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm9, dwarf_ymm9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm10", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm10, dwarf_ymm10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm11", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm11, dwarf_ymm11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm12", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm12, dwarf_ymm12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm13", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm13, dwarf_ymm13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm14", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm14, dwarf_ymm14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"ymm15", nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, {dwarf_ymm15, dwarf_ymm15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bnd0", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64, {dwarf_bnd0, dwarf_bnd0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bnd1", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64, {dwarf_bnd1, dwarf_bnd1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bnd2", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64, {dwarf_bnd2, dwarf_bnd2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bnd3", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64, {dwarf_bnd3, dwarf_bnd3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bndcfgu", nullptr, 8, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - {"bndstatus",nullptr, 8, 0, eEncodingVector, eFormatVectorOfUInt8, {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, nullptr, nullptr, nullptr, 0}, - // clang-format on }; -static const uint32_t k_num_register_infos = - llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; - -const lldb_private::RegisterInfo * -ABISysV_x86_64::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } - count = k_num_register_infos; - return g_register_infos; -} - bool ABISysV_x86_64::GetPointerReturnRegister(const char *&name) { name = "rax"; return true; @@ -1078,6 +926,21 @@ bool ABISysV_x86_64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { return IsCalleeSaved; } +uint32_t ABISysV_x86_64::GetGenericNum(llvm::StringRef name) { + return llvm::StringSwitch<uint32_t>(name) + .Case("rip", LLDB_REGNUM_GENERIC_PC) + .Case("rsp", LLDB_REGNUM_GENERIC_SP) + .Case("rbp", LLDB_REGNUM_GENERIC_FP) + .Case("rflags", LLDB_REGNUM_GENERIC_FLAGS) + .Case("rdi", LLDB_REGNUM_GENERIC_ARG1) + .Case("rsi", LLDB_REGNUM_GENERIC_ARG2) + .Case("rdx", LLDB_REGNUM_GENERIC_ARG3) + .Case("rcx", LLDB_REGNUM_GENERIC_ARG4) + .Case("r8", LLDB_REGNUM_GENERIC_ARG5) + .Case("r9", LLDB_REGNUM_GENERIC_ARG6) + .Default(LLDB_INVALID_REGNUM); +} + void ABISysV_x86_64::Initialize() { PluginManager::RegisterPlugin( GetPluginNameStatic(), "System V ABI for x86_64 targets", CreateInstance); diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.h index d445d8f4142a..6dce4ce0f012 100644 --- a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h +++ b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.h @@ -6,13 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABISysV_x86_64_h_ -#define liblldb_ABISysV_x86_64_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_X86_ABISYSV_X86_64_H +#define LLDB_SOURCE_PLUGINS_ABI_X86_ABISYSV_X86_64_H -#include "lldb/Target/ABI.h" -#include "lldb/lldb-private.h" +#include "Plugins/ABI/X86/ABIX86_64.h" -class ABISysV_x86_64 : public lldb_private::ABI { +class ABISysV_x86_64 : public ABIX86_64 { public: ~ABISysV_x86_64() override = default; @@ -49,7 +48,7 @@ public: // // To work around this, we relax that alignment to be just word-size // (8-bytes). - // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // Allowing the trap handlers for user space would be easy (_sigtramp) but // in other environments there can be a large number of different functions // involved in async traps. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { @@ -67,9 +66,6 @@ public: return true; } - const lldb_private::RegisterInfo * - GetRegisterInfoArray(uint32_t &count) override; - bool GetPointerReturnRegister(const char *&name) override; // Static Functions @@ -96,13 +92,10 @@ protected: lldb_private::CompilerType &ast_type) const; bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); + uint32_t GetGenericNum(llvm::StringRef reg) override; private: - ABISysV_x86_64(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using ABIX86_64::ABIX86_64; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_x86_64_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_X86_ABISYSV_X86_64_H diff --git a/lldb/source/Plugins/ABI/Windows-x86_64/ABIWindows_x86_64.cpp b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp index ac24426914e1..63b670b07277 100644 --- a/lldb/source/Plugins/ABI/Windows-x86_64/ABIWindows_x86_64.cpp +++ b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- ABIWindows_x86_64.cpp --------------------------------------*- C++ -*-===// +//===-- ABIWindows_x86_64.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -33,6 +33,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ABIWindows_x86_64) + enum dwarf_regnums { dwarf_rax = 0, dwarf_rdx, @@ -97,986 +99,6 @@ enum dwarf_regnums { dwarf_bnd3 }; -static RegisterInfo g_register_infos[] = { - // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME - // DWARF GENERIC PROCESS PLUGIN - // LLDB NATIVE - // ======== ======= == === ============= =================== - // ======================= ===================== - // =========================== ===================== ====================== - {"rax", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rax, dwarf_rax, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rbx", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rbx, dwarf_rbx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rcx", - "arg1", - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rcx, dwarf_rcx, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rdx", - "arg2", - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rdx, dwarf_rdx, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rsi", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rsi, dwarf_rsi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rdi", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rdi, dwarf_rdi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rbp", - "fp", - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rbp, dwarf_rbp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rsp", - "sp", - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rsp, dwarf_rsp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"r8", - "arg3", - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_r8, dwarf_r8, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"r9", - "arg4", - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_r9, dwarf_r9, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"r10", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"r11", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"r12", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"r13", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"r14", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"r15", - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rip", - "pc", - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_rip, dwarf_rip, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"rflags", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"cs", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ss", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ds", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"es", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fs", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"gs", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm0", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_stmm0, dwarf_stmm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm1", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_stmm1, dwarf_stmm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm2", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_stmm2, dwarf_stmm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm3", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_stmm3, dwarf_stmm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm4", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_stmm4, dwarf_stmm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm5", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_stmm5, dwarf_stmm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm6", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_stmm6, dwarf_stmm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"stmm7", - nullptr, - 10, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_stmm7, dwarf_stmm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fctrl", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fstat", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ftag", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fiseg", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fioff", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"foseg", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fooff", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"fop", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm0", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm0, dwarf_xmm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm1", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm1, dwarf_xmm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm2", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm2, dwarf_xmm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm3", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm3, dwarf_xmm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm4", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm4, dwarf_xmm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm5", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm5, dwarf_xmm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm6", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm6, dwarf_xmm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm7", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm7, dwarf_xmm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm8", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm8, dwarf_xmm8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm9", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm9, dwarf_xmm9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm10", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm10, dwarf_xmm10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm11", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm11, dwarf_xmm11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm12", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm12, dwarf_xmm12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm13", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm13, dwarf_xmm13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm14", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm14, dwarf_xmm14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"xmm15", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_xmm15, dwarf_xmm15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"mxcsr", - nullptr, - 4, - 0, - eEncodingUint, - eFormatHex, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm0", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm0, dwarf_ymm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm1", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm1, dwarf_ymm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm2", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm2, dwarf_ymm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm3", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm3, dwarf_ymm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm4", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm4, dwarf_ymm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm5", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm5, dwarf_ymm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm6", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm6, dwarf_ymm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm7", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm7, dwarf_ymm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm8", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm8, dwarf_ymm8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm9", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm9, dwarf_ymm9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm10", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm10, dwarf_ymm10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm11", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm11, dwarf_ymm11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm12", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm12, dwarf_ymm12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm13", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm13, dwarf_ymm13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm14", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm14, dwarf_ymm14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"ymm15", - nullptr, - 32, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {dwarf_ymm15, dwarf_ymm15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"bnd0", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt64, - {dwarf_bnd0, dwarf_bnd0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"bnd1", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt64, - {dwarf_bnd1, dwarf_bnd1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"bnd2", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt64, - {dwarf_bnd2, dwarf_bnd2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"bnd3", - nullptr, - 16, - 0, - eEncodingVector, - eFormatVectorOfUInt64, - {dwarf_bnd3, dwarf_bnd3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"bndcfgu", - nullptr, - 8, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}, - {"bndstatus", - nullptr, - 8, - 0, - eEncodingVector, - eFormatVectorOfUInt8, - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}}; - -static const uint32_t k_num_register_infos = - llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; - -const lldb_private::RegisterInfo * -ABIWindows_x86_64::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } - count = k_num_register_infos; - return g_register_infos; -} - bool ABIWindows_x86_64::GetPointerReturnRegister(const char *&name) { name = "rax"; return true; @@ -1777,6 +799,19 @@ bool ABIWindows_x86_64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { return IsCalleeSaved; } +uint32_t ABIWindows_x86_64::GetGenericNum(llvm::StringRef reg) { + return llvm::StringSwitch<uint32_t>(reg) + .Case("rip", LLDB_REGNUM_GENERIC_PC) + .Case("rsp", LLDB_REGNUM_GENERIC_SP) + .Case("rbp", LLDB_REGNUM_GENERIC_FP) + .Case("rflags", LLDB_REGNUM_GENERIC_FLAGS) + .Case("rcx", LLDB_REGNUM_GENERIC_ARG1) + .Case("rdx", LLDB_REGNUM_GENERIC_ARG2) + .Case("r8", LLDB_REGNUM_GENERIC_ARG3) + .Case("r9", LLDB_REGNUM_GENERIC_ARG4) + .Default(LLDB_INVALID_REGNUM); +} + void ABIWindows_x86_64::Initialize() { PluginManager::RegisterPlugin( GetPluginNameStatic(), "Windows ABI for x86_64 targets", CreateInstance); diff --git a/lldb/source/Plugins/ABI/Windows-x86_64/ABIWindows_x86_64.h b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h index 2366566d7809..89fc6e6ca21f 100644 --- a/lldb/source/Plugins/ABI/Windows-x86_64/ABIWindows_x86_64.h +++ b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h @@ -6,13 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ABIWindows_x86_64_h_ -#define liblldb_ABIWindows_x86_64_h_ +#ifndef LLDB_SOURCE_PLUGINS_ABI_X86_ABIWINDOWS_X86_64_H +#define LLDB_SOURCE_PLUGINS_ABI_X86_ABIWINDOWS_X86_64_H -#include "lldb/Target/ABI.h" -#include "lldb/lldb-private.h" +#include "Plugins/ABI/X86/ABIX86_64.h" -class ABIWindows_x86_64 : public lldb_private::ABI { +class ABIWindows_x86_64 : public ABIX86_64 { public: ~ABIWindows_x86_64() override = default; @@ -56,9 +55,6 @@ public: return true; } - const lldb_private::RegisterInfo * - GetRegisterInfoArray(uint32_t &count) override; - bool GetPointerReturnRegister(const char *&name) override; //------------------------------------------------------------------ @@ -89,13 +85,10 @@ protected: lldb_private::CompilerType &ast_type) const; bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); + uint32_t GetGenericNum(llvm::StringRef reg) override; private: - ABIWindows_x86_64(lldb::ProcessSP process_sp, - std::unique_ptr<llvm::MCRegisterInfo> info_up) - : lldb_private::ABI(std::move(process_sp), std::move(info_up)) { - // Call CreateInstance instead. - } + using ABIX86_64::ABIX86_64; // Call CreateInstance instead. }; -#endif // liblldb_ABISysV_x86_64_h_ +#endif // LLDB_SOURCE_PLUGINS_ABI_X86_ABIWINDOWS_X86_64_H diff --git a/lldb/source/Plugins/ABI/X86/ABIX86.cpp b/lldb/source/Plugins/ABI/X86/ABIX86.cpp new file mode 100644 index 000000000000..bf5ab669417e --- /dev/null +++ b/lldb/source/Plugins/ABI/X86/ABIX86.cpp @@ -0,0 +1,43 @@ +//===-- X86.h -------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ABIX86.h" +#include "ABIMacOSX_i386.h" +#include "ABISysV_i386.h" +#include "ABISysV_x86_64.h" +#include "ABIWindows_x86_64.h" +#include "lldb/Core/PluginManager.h" + +LLDB_PLUGIN_DEFINE(ABIX86) + +void ABIX86::Initialize() { + ABIMacOSX_i386::Initialize(); + ABISysV_i386::Initialize(); + ABISysV_x86_64::Initialize(); + ABIWindows_x86_64::Initialize(); +} + +void ABIX86::Terminate() { + ABIMacOSX_i386::Terminate(); + ABISysV_i386::Terminate(); + ABISysV_x86_64::Terminate(); + ABIWindows_x86_64::Terminate(); +} + +uint32_t ABIX86::GetGenericNum(llvm::StringRef name) { + return llvm::StringSwitch<uint32_t>(name) + .Case("eip", LLDB_REGNUM_GENERIC_PC) + .Case("esp", LLDB_REGNUM_GENERIC_SP) + .Case("ebp", LLDB_REGNUM_GENERIC_FP) + .Case("eflags", LLDB_REGNUM_GENERIC_FLAGS) + .Case("edi", LLDB_REGNUM_GENERIC_ARG1) + .Case("esi", LLDB_REGNUM_GENERIC_ARG2) + .Case("edx", LLDB_REGNUM_GENERIC_ARG3) + .Case("ecx", LLDB_REGNUM_GENERIC_ARG4) + .Default(LLDB_INVALID_REGNUM); +} diff --git a/lldb/source/Plugins/ABI/X86/ABIX86.h b/lldb/source/Plugins/ABI/X86/ABIX86.h new file mode 100644 index 000000000000..22521cacf180 --- /dev/null +++ b/lldb/source/Plugins/ABI/X86/ABIX86.h @@ -0,0 +1,24 @@ +//===-- X86.h ---------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_ABI_X86_ABIX86_H +#define LLDB_SOURCE_PLUGINS_ABI_X86_ABIX86_H + +#include "lldb/Target/ABI.h" + +class ABIX86 : public lldb_private::MCBasedABI { +public: + static void Initialize(); + static void Terminate(); + + uint32_t GetGenericNum(llvm::StringRef name) override; + +private: + using lldb_private::MCBasedABI::MCBasedABI; +}; +#endif diff --git a/lldb/source/Plugins/ABI/X86/ABIX86_64.h b/lldb/source/Plugins/ABI/X86/ABIX86_64.h new file mode 100644 index 000000000000..e65c2d97d897 --- /dev/null +++ b/lldb/source/Plugins/ABI/X86/ABIX86_64.h @@ -0,0 +1,26 @@ +//===-- ABIX86_64.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_ABI_X86_ABIX86_64_H +#define LLDB_SOURCE_PLUGINS_ABI_X86_ABIX86_64_H + +#include "lldb/Target/ABI.h" +#include "lldb/lldb-private.h" + +class ABIX86_64 : public lldb_private::MCBasedABI { +protected: + std::string GetMCName(std::string name) override { + MapRegisterName(name, "stmm", "st"); + return name; + } + +private: + using lldb_private::MCBasedABI::MCBasedABI; +}; + +#endif // LLDB_SOURCE_PLUGINS_ABI_X86_ABIX86_64_H diff --git a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp index 5b86df6c5273..58c7cbb4530a 100644 --- a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp +++ b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp @@ -1,4 +1,4 @@ -//===-- ArchitectureArm.cpp -------------------------------------*- C++ -*-===// +//===-- ArchitectureArm.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -17,6 +17,8 @@ using namespace lldb_private; using namespace lldb; +LLDB_PLUGIN_DEFINE(ArchitectureArm) + ConstString ArchitectureArm::GetPluginNameStatic() { return ConstString("arm"); } diff --git a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h index 03e79ce524a7..36b79c7c01a1 100644 --- a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h +++ b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGIN_ARCHITECTURE_ARM_H -#define LLDB_PLUGIN_ARCHITECTURE_ARM_H +#ifndef LLDB_SOURCE_PLUGINS_ARCHITECTURE_ARM_ARCHITECTUREARM_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_ARM_ARCHITECTUREARM_H #include "lldb/Core/Architecture.h" @@ -37,4 +37,4 @@ private: } // namespace lldb_private -#endif // LLDB_PLUGIN_ARCHITECTURE_ARM_H +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_ARM_ARCHITECTUREARM_H diff --git a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp index 5f2f6eeb8261..22508969ceed 100644 --- a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp +++ b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp @@ -1,4 +1,4 @@ -//===-- ArchitectureMips.cpp -------------------------------------*- C++ -*-===// +//===-- ArchitectureMips.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -21,6 +21,8 @@ using namespace lldb_private; using namespace lldb; +LLDB_PLUGIN_DEFINE(ArchitectureMips) + ConstString ArchitectureMips::GetPluginNameStatic() { return ConstString("mips"); } @@ -118,9 +120,7 @@ lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr, if (current_offset == 0) return addr; - ExecutionContext ctx; - target.CalculateExecutionContext(ctx); - auto insn = GetInstructionAtAddress(ctx, current_offset, addr); + auto insn = GetInstructionAtAddress(target, current_offset, addr); if (nullptr == insn || !insn->HasDelaySlot()) return addr; @@ -136,8 +136,7 @@ lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr, } Instruction *ArchitectureMips::GetInstructionAtAddress( - const ExecutionContext &exe_ctx, const Address &resolved_addr, - addr_t symbol_offset) const { + Target &target, const Address &resolved_addr, addr_t symbol_offset) const { auto loop_count = symbol_offset / 2; @@ -169,10 +168,11 @@ Instruction *ArchitectureMips::GetInstructionAtAddress( for (uint32_t i = 1; i <= loop_count; i++) { // Adjust the address to read from. addr.Slide(-2); - AddressRange range(addr, i * 2); uint32_t insn_size = 0; - disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); + disasm_sp->ParseInstructions(target, addr, + {Disassembler::Limit::Bytes, i * 2}, nullptr, + prefer_file_cache); uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); if (num_insns) { diff --git a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h index a15991ff9ebf..71ee60184b69 100644 --- a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h +++ b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGIN_ARCHITECTURE_MIPS_H -#define LLDB_PLUGIN_ARCHITECTURE_MIPS_H +#ifndef LLDB_SOURCE_PLUGINS_ARCHITECTURE_MIPS_ARCHITECTUREMIPS_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_MIPS_ARCHITECTUREMIPS_H #include "lldb/Core/Architecture.h" #include "lldb/Utility/ArchSpec.h" @@ -35,11 +35,10 @@ public: AddressClass addr_class) const override; private: - Instruction *GetInstructionAtAddress(const ExecutionContext &exe_ctx, + Instruction *GetInstructionAtAddress(Target &target, const Address &resolved_addr, lldb::addr_t symbol_offset) const; - static std::unique_ptr<Architecture> Create(const ArchSpec &arch); ArchitectureMips(const ArchSpec &arch) : m_arch(arch) {} @@ -48,4 +47,4 @@ private: } // namespace lldb_private -#endif // LLDB_PLUGIN_ARCHITECTURE_MIPS_H +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_MIPS_ARCHITECTUREMIPS_H diff --git a/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp b/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp index 76eaa44546eb..94301ecf052c 100644 --- a/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp +++ b/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp @@ -1,4 +1,4 @@ -//===-- ArchitecturePPC64.cpp -----------------------------------*- C++ -*-===// +//===-- ArchitecturePPC64.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -20,6 +20,8 @@ using namespace lldb_private; using namespace lldb; +LLDB_PLUGIN_DEFINE(ArchitecturePPC64) + ConstString ArchitecturePPC64::GetPluginNameStatic() { return ConstString("ppc64"); } diff --git a/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h b/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h index dc663b849c4a..25210d37e53a 100644 --- a/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h +++ b/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGIN_ARCHITECTURE_PPC64_H -#define LLDB_PLUGIN_ARCHITECTURE_PPC64_H +#ifndef LLDB_SOURCE_PLUGINS_ARCHITECTURE_PPC64_ARCHITECTUREPPC64_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_PPC64_ARCHITECTUREPPC64_H #include "lldb/Core/Architecture.h" @@ -38,4 +38,4 @@ private: } // namespace lldb_private -#endif // LLDB_PLUGIN_ARCHITECTURE_PPC64_H +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_PPC64_ARCHITECTUREPPC64_H diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp index dbdb3520087e..6427d8d176c8 100644 --- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -1,4 +1,4 @@ -//===-- DisassemblerLLVMC.cpp -----------------------------------*- C++ -*-===// +//===-- DisassemblerLLVMC.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -43,6 +43,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(DisassemblerLLVMC) + class DisassemblerLLVMC::MCDisasmInstance { public: static std::unique_ptr<MCDisasmInstance> @@ -86,76 +88,18 @@ public: : Instruction(address, addr_class), m_disasm_wp(std::static_pointer_cast<DisassemblerLLVMC>( disasm.shared_from_this())), - m_does_branch(eLazyBoolCalculate), m_has_delay_slot(eLazyBoolCalculate), - m_is_call(eLazyBoolCalculate), m_is_valid(false), m_using_file_addr(false) {} ~InstructionLLVMC() override = default; bool DoesBranch() override { - if (m_does_branch == eLazyBoolCalculate) { - DisassemblerScope disasm(*this); - if (disasm) { - DataExtractor data; - if (m_opcode.GetData(data)) { - bool is_alternate_isa; - lldb::addr_t pc = m_address.GetFileAddress(); - - DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = - GetDisasmToUse(is_alternate_isa, disasm); - const uint8_t *opcode_data = data.GetDataStart(); - const size_t opcode_data_len = data.GetByteSize(); - llvm::MCInst inst; - const size_t inst_size = - mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len, pc, inst); - // Be conservative, if we didn't understand the instruction, say it - // might branch... - if (inst_size == 0) - m_does_branch = eLazyBoolYes; - else { - const bool can_branch = mc_disasm_ptr->CanBranch(inst); - if (can_branch) - m_does_branch = eLazyBoolYes; - else - m_does_branch = eLazyBoolNo; - } - } - } - } - return m_does_branch == eLazyBoolYes; + VisitInstruction(); + return m_does_branch; } bool HasDelaySlot() override { - if (m_has_delay_slot == eLazyBoolCalculate) { - DisassemblerScope disasm(*this); - if (disasm) { - DataExtractor data; - if (m_opcode.GetData(data)) { - bool is_alternate_isa; - lldb::addr_t pc = m_address.GetFileAddress(); - - DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = - GetDisasmToUse(is_alternate_isa, disasm); - const uint8_t *opcode_data = data.GetDataStart(); - const size_t opcode_data_len = data.GetByteSize(); - llvm::MCInst inst; - const size_t inst_size = - mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len, pc, inst); - // if we didn't understand the instruction, say it doesn't have a - // delay slot... - if (inst_size == 0) - m_has_delay_slot = eLazyBoolNo; - else { - const bool has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst); - if (has_delay_slot) - m_has_delay_slot = eLazyBoolYes; - else - m_has_delay_slot = eLazyBoolNo; - } - } - } - } - return m_has_delay_slot == eLazyBoolYes; + VisitInstruction(); + return m_has_delay_slot; } DisassemblerLLVMC::MCDisasmInstance *GetDisasmToUse(bool &is_alternate_isa) { @@ -367,16 +311,8 @@ public: } break; } - m_mnemonics = mnemonic_strm.GetString(); + m_mnemonics = std::string(mnemonic_strm.GetString()); return; - } else { - if (m_does_branch == eLazyBoolCalculate) { - const bool can_branch = mc_disasm_ptr->CanBranch(inst); - if (can_branch) - m_does_branch = eLazyBoolYes; - else - m_does_branch = eLazyBoolNo; - } } static RegularExpression s_regex( @@ -774,7 +710,7 @@ public: s.PutCString(")"); break; case Operand::Type::Register: - s.PutCString(op.m_register.AsCString()); + s.PutCString(op.m_register.GetStringRef()); break; case Operand::Type::Sum: s.PutCString("("); @@ -866,42 +802,54 @@ public: } bool IsCall() override { - if (m_is_call == eLazyBoolCalculate) { - DisassemblerScope disasm(*this); - if (disasm) { - DataExtractor data; - if (m_opcode.GetData(data)) { - bool is_alternate_isa; - lldb::addr_t pc = m_address.GetFileAddress(); - - DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = - GetDisasmToUse(is_alternate_isa, disasm); - const uint8_t *opcode_data = data.GetDataStart(); - const size_t opcode_data_len = data.GetByteSize(); - llvm::MCInst inst; - const size_t inst_size = - mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len, pc, inst); - if (inst_size == 0) { - m_is_call = eLazyBoolNo; - } else { - if (mc_disasm_ptr->IsCall(inst)) - m_is_call = eLazyBoolYes; - else - m_is_call = eLazyBoolNo; - } - } - } - } - return m_is_call == eLazyBoolYes; + VisitInstruction(); + return m_is_call; } protected: std::weak_ptr<DisassemblerLLVMC> m_disasm_wp; - LazyBool m_does_branch; - LazyBool m_has_delay_slot; - LazyBool m_is_call; - bool m_is_valid; + + bool m_is_valid = false; bool m_using_file_addr; + bool m_has_visited_instruction = false; + + // Be conservative. If we didn't understand the instruction, say it: + // - Might branch + // - Does not have a delay slot + // - Is not a call + bool m_does_branch = true; + bool m_has_delay_slot = false; + bool m_is_call = false; + + void VisitInstruction() { + if (m_has_visited_instruction) + return; + + DisassemblerScope disasm(*this); + if (!disasm) + return; + + DataExtractor data; + if (!m_opcode.GetData(data)) + return; + + bool is_alternate_isa; + lldb::addr_t pc = m_address.GetFileAddress(); + DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = + GetDisasmToUse(is_alternate_isa, disasm); + const uint8_t *opcode_data = data.GetDataStart(); + const size_t opcode_data_len = data.GetByteSize(); + llvm::MCInst inst; + const size_t inst_size = + mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len, pc, inst); + if (inst_size == 0) + return; + + m_has_visited_instruction = true; + m_does_branch = mc_disasm_ptr->CanBranch(inst); + m_has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst); + m_is_call = mc_disasm_ptr->IsCall(inst); + } private: DisassemblerLLVMC::MCDisasmInstance * @@ -1414,7 +1362,7 @@ const char *DisassemblerLLVMC::SymbolLookup(uint64_t value, uint64_t *type_ptr, // If Address::Dump returned a multi-line description, most commonly // seen when we have multiple levels of inlined functions at an // address, only show the first line. - std::string str = ss.GetString(); + std::string str = std::string(ss.GetString()); size_t first_eol_char = str.find_first_of("\r\n"); if (first_eol_char != std::string::npos) { str.erase(first_eol_char); diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h index fd5775056d33..9b3741bdd18f 100644 --- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h +++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_DisassemblerLLVMC_h_ -#define liblldb_DisassemblerLLVMC_h_ +#ifndef LLDB_SOURCE_PLUGINS_DISASSEMBLER_LLVMC_DISASSEMBLERLLVMC_H +#define LLDB_SOURCE_PLUGINS_DISASSEMBLER_LLVMC_DISASSEMBLERLLVMC_H #include <memory> #include <mutex> @@ -82,4 +82,4 @@ protected: std::unique_ptr<MCDisasmInstance> m_alternate_disasm_up; }; -#endif // liblldb_DisassemblerLLVM_h_ +#endif // LLDB_SOURCE_PLUGINS_DISASSEMBLER_LLVMC_DISASSEMBLERLLVMC_H diff --git a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp index 5b19647a27ba..fe86b2929073 100644 --- a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp @@ -1,4 +1,4 @@ -//===-- DynamicLoaderHexagonDYLD.cpp ----------------------------*- C++ -*-===// +//===-- DynamicLoaderHexagonDYLD.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -25,6 +25,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(DynamicLoaderHexagonDYLD) + // Aidan 21/05/2014 // // Notes about hexagon dynamic loading: @@ -418,8 +420,8 @@ DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, if (sym == nullptr || !sym->IsTrampoline()) return thread_plan_sp; - const ConstString sym_name = sym->GetMangled().GetName( - lldb::eLanguageTypeUnknown, Mangled::ePreferMangled); + const ConstString sym_name = + sym->GetMangled().GetName(Mangled::ePreferMangled); if (!sym_name) return thread_plan_sp; diff --git a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h index c171513c5499..2d39ce06a8d9 100644 --- a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_DynamicLoaderHexagonDYLD_h_ -#define liblldb_DynamicLoaderHexagonDYLD_h_ +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_DYNAMICLOADERHEXAGONDYLD_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_DYNAMICLOADERHEXAGONDYLD_H #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Target/DynamicLoader.h" @@ -132,7 +132,9 @@ private: const lldb_private::SectionList * GetSectionListFromModule(const lldb::ModuleSP module) const; - DISALLOW_COPY_AND_ASSIGN(DynamicLoaderHexagonDYLD); + DynamicLoaderHexagonDYLD(const DynamicLoaderHexagonDYLD &) = delete; + const DynamicLoaderHexagonDYLD & + operator=(const DynamicLoaderHexagonDYLD &) = delete; }; -#endif // liblldb_DynamicLoaderHexagonDYLD_h_ +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_DYNAMICLOADERHEXAGONDYLD_H diff --git a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp index f4788816d4ea..af76056af684 100644 --- a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp +++ b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp @@ -1,4 +1,4 @@ -//===-- HexagonDYLDRendezvous.cpp -------------------------------*- C++ -*-===// +//===-- HexagonDYLDRendezvous.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h index 70fc12b7fab7..5707f8858f6c 100644 --- a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h +++ b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_HexagonDYLDRendezvous_H_ -#define liblldb_HexagonDYLDRendezvous_H_ +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H #include <limits.h> #include <list> @@ -243,4 +243,4 @@ protected: bool FindMetadata(const char *name, PThreadField field, uint32_t &value); }; -#endif // liblldb_HexagonDYLDRendezvous_H_ +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index 737599303a60..15b3805003a5 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -1,4 +1,4 @@ -//===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===// +//===-- DYLDRendezvous.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h index 536eeeaaf334..b028120eb0d4 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_Rendezvous_H_ -#define liblldb_Rendezvous_H_ +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYLDRENDEZVOUS_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYLDRENDEZVOUS_H #include <list> #include <string> diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 9d61c8feb923..ac60af5336ed 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -1,4 +1,4 @@ -//===-- DynamicLoaderPOSIXDYLD.cpp ------------------------------*- C++ -*-===// +//===-- DynamicLoaderPOSIXDYLD.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -29,6 +29,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(DynamicLoaderPOSIXDYLD, DynamicLoaderPosixDYLD) + void DynamicLoaderPOSIXDYLD::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 0630d1eb11d1..a7fcdfbadeaf 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_DynamicLoaderPOSIXDYLD_h_ -#define liblldb_DynamicLoaderPOSIXDYLD_h_ +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYNAMICLOADERPOSIXDYLD_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYNAMICLOADERPOSIXDYLD_H #include <map> #include <memory> @@ -136,7 +136,7 @@ protected: void LoadVDSO(); - // Loading an interpreter module (if present) assumming m_interpreter_base + // Loading an interpreter module (if present) assuming m_interpreter_base // already points to its base address. lldb::ModuleSP LoadInterpreterModule(); @@ -159,7 +159,9 @@ protected: bool AlwaysRelyOnEHUnwindInfo(lldb_private::SymbolContext &sym_ctx) override; private: - DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD); + DynamicLoaderPOSIXDYLD(const DynamicLoaderPOSIXDYLD &) = delete; + const DynamicLoaderPOSIXDYLD & + operator=(const DynamicLoaderPOSIXDYLD &) = delete; }; -#endif // liblldb_DynamicLoaderPOSIXDYLD_h_ +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYNAMICLOADERPOSIXDYLD_H diff --git a/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp index 6bc951c4d35b..48762fe6e0c3 100644 --- a/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp +++ b/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp @@ -1,4 +1,4 @@ -//===-- DynamicLoaderStatic.cpp ---------------------------------*- C++ -*-===// +//===-- DynamicLoaderStatic.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -17,6 +17,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(DynamicLoaderStatic) + // Create an instance of this class. This function is filled into the plugin // info class that gets handed out by the plugin factory and allows the lldb to // instantiate an instance of this class. @@ -27,8 +29,19 @@ DynamicLoader *DynamicLoaderStatic::CreateInstance(Process *process, const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); const llvm::Triple::OSType os_type = triple_ref.getOS(); - if ((os_type == llvm::Triple::UnknownOS)) - create = true; + const llvm::Triple::ArchType arch_type = triple_ref.getArch(); + if (os_type == llvm::Triple::UnknownOS) { + // The WASM and Hexagon plugin check the ArchType rather than the OSType, + // so explicitly reject those here. + switch(arch_type) { + case llvm::Triple::hexagon: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + break; + default: + create = true; + } + } } if (!create) { diff --git a/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h index fa9aded7286c..ce78804f9a92 100644 --- a/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h +++ b/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_DynamicLoaderStatic_h_ -#define liblldb_DynamicLoaderStatic_h_ +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_STATIC_DYNAMICLOADERSTATIC_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_STATIC_DYNAMICLOADERSTATIC_H #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" @@ -53,7 +53,8 @@ public: private: void LoadAllImagesAtFileAddresses(); - DISALLOW_COPY_AND_ASSIGN(DynamicLoaderStatic); + DynamicLoaderStatic(const DynamicLoaderStatic &) = delete; + const DynamicLoaderStatic &operator=(const DynamicLoaderStatic &) = delete; }; -#endif // liblldb_DynamicLoaderStatic_h_ +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_STATIC_DYNAMICLOADERSTATIC_H diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp index 25ab30e9db9c..7f9504b9b3a9 100644 --- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp @@ -1,5 +1,4 @@ -//===-- DynamicLoaderWindowsDYLD.cpp --------------------------------*- C++ -//-*-===// +//===-- DynamicLoaderWindowsDYLD.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -24,6 +23,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(DynamicLoaderWindowsDYLD) + DynamicLoaderWindowsDYLD::DynamicLoaderWindowsDYLD(Process *process) : DynamicLoader(process) {} @@ -191,9 +192,8 @@ DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread, // Max size of an instruction in x86 is 15 bytes. AddressRange range(pc, 2 * 15); - ExecutionContext exe_ctx(m_process->GetTarget()); DisassemblerSP disassembler_sp = Disassembler::DisassembleRange( - arch, nullptr, nullptr, exe_ctx, range, true); + arch, nullptr, nullptr, m_process->GetTarget(), range, true); if (!disassembler_sp) { return ThreadPlanSP(); } @@ -212,6 +212,7 @@ DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread, auto first_insn = insn_list->GetInstructionAtIndex(0); auto second_insn = insn_list->GetInstructionAtIndex(1); + ExecutionContext exe_ctx(m_process->GetTarget()); if (first_insn == nullptr || second_insn == nullptr || strcmp(first_insn->GetMnemonic(&exe_ctx), "jmpl") != 0 || strcmp(second_insn->GetMnemonic(&exe_ctx), "nop") != 0) { diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h index 100689a63128..502a4c160ddd 100644 --- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_h_ -#define liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_h_ +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_WINDOWS_DYLD_DYNAMICLOADERWINDOWSDYLD_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_WINDOWS_DYLD_DYNAMICLOADERWINDOWSDYLD_H #include "lldb/Target/DynamicLoader.h" #include "lldb/lldb-forward.h" @@ -51,4 +51,4 @@ private: } // namespace lldb_private -#endif // liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_h_ +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_WINDOWS_DYLD_DYNAMICLOADERWINDOWSDYLD_H diff --git a/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp b/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp new file mode 100644 index 000000000000..ae7e011eaa52 --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp @@ -0,0 +1,70 @@ +//===-- DynamicLoaderWasmDYLD.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 "DynamicLoaderWasmDYLD.h" + +#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::wasm; + +LLDB_PLUGIN_DEFINE(DynamicLoaderWasmDYLD) + +DynamicLoaderWasmDYLD::DynamicLoaderWasmDYLD(Process *process) + : DynamicLoader(process) {} + +void DynamicLoaderWasmDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +ConstString DynamicLoaderWasmDYLD::GetPluginNameStatic() { + static ConstString g_plugin_name("wasm-dyld"); + return g_plugin_name; +} + +const char *DynamicLoaderWasmDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in WebAssembly engines."; +} + +DynamicLoader *DynamicLoaderWasmDYLD::CreateInstance(Process *process, + bool force) { + bool should_create = force; + if (!should_create) { + should_create = + (process->GetTarget().GetArchitecture().GetTriple().getArch() == + llvm::Triple::wasm32); + } + + if (should_create) + return new DynamicLoaderWasmDYLD(process); + + return nullptr; +} + +void DynamicLoaderWasmDYLD::DidAttach() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + LLDB_LOGF(log, "DynamicLoaderWasmDYLD::%s()", __FUNCTION__); + + // Ask the process for the list of loaded WebAssembly modules. + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "Couldn't load modules: {0}"); +} + +ThreadPlanSP DynamicLoaderWasmDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + return ThreadPlanSP(); +} diff --git a/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h b/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h new file mode 100644 index 000000000000..4a18972bb848 --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h @@ -0,0 +1,48 @@ +//===-- DynamicLoaderWasmDYLD.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_Plugins_DynamicLoaderWasmDYLD_h_ +#define liblldb_Plugins_DynamicLoaderWasmDYLD_h_ + +#include "lldb/Target/DynamicLoader.h" + +namespace lldb_private { +namespace wasm { + +class DynamicLoaderWasmDYLD : public DynamicLoader { +public: + DynamicLoaderWasmDYLD(Process *process); + + static void Initialize(); + static void Terminate() {} + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic(); + + static DynamicLoader *CreateInstance(Process *process, bool force); + + /// DynamicLoader + /// \{ + void DidAttach() override; + void DidLaunch() override {} + Status CanLoadImage() override { return Status(); } + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop) override; + /// \} + + /// PluginInterface protocol. + /// \{ + ConstString GetPluginName() override { return GetPluginNameStatic(); } + uint32_t GetPluginVersion() override { return 1; } + /// \} +}; + +} // namespace wasm +} // namespace lldb_private + +#endif // liblldb_Plugins_DynamicLoaderWasmDYLD_h_ diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 77bb9544ea40..39ba5f4e9e4f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -1,4 +1,4 @@ -//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===// +//===-- ASTResultSynthesizer.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,10 +8,10 @@ #include "ASTResultSynthesizer.h" +#include "ClangASTImporter.h" #include "ClangPersistentVariables.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" @@ -248,48 +248,37 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, // For Lvalues // // - In AST result synthesis (here!) the expression E is transformed into an - // initialization - // T *$__lldb_expr_result_ptr = &E. + // initialization T *$__lldb_expr_result_ptr = &E. // // - In structure allocation, a pointer-sized slot is allocated in the - // struct that is to be - // passed into the expression. + // struct that is to be passed into the expression. // // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are - // redirected at - // an entry in the struct ($__lldb_arg) passed into the expression. - // (Other persistent - // variables are treated similarly, having been materialized as - // references, but in those - // cases the value of the reference itself is never modified.) + // redirected at an entry in the struct ($__lldb_arg) passed into the + // expression. (Other persistent variables are treated similarly, having + // been materialized as references, but in those cases the value of the + // reference itself is never modified.) // // - During materialization, $0 (the result persistent variable) is ignored. // // - During dematerialization, $0 is marked up as a load address with value - // equal to the - // contents of the structure entry. + // equal to the contents of the structure entry. // // For Rvalues // // - In AST result synthesis the expression E is transformed into an - // initialization - // static T $__lldb_expr_result = E. + // initialization static T $__lldb_expr_result = E. // // - In structure allocation, a pointer-sized slot is allocated in the - // struct that is to be - // passed into the expression. + // struct that is to be passed into the expression. // // - In IR transformations, an instruction is inserted at the beginning of - // the function to - // dereference the pointer resident in the slot. Reads and writes to - // $__lldb_expr_result - // are redirected at that dereferenced version. Guard variables for the - // static variable - // are excised. + // the function to dereference the pointer resident in the slot. Reads and + // writes to $__lldb_expr_result are redirected at that dereferenced + // version. Guard variables for the static variable are excised. // // - During materialization, $0 (the result persistent variable) is - // populated with the location - // of a newly-allocated area of memory. + // populated with the location of a newly-allocated area of memory. // // - During dematerialization, $0 is ignored. @@ -325,7 +314,8 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, else result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr"); - m_sema->RequireCompleteType(SourceLocation(), expr_qual_type, + m_sema->RequireCompleteType(last_expr->getSourceRange().getBegin(), + expr_qual_type, clang::diag::err_incomplete_type); QualType ptr_qual_type; @@ -453,13 +443,13 @@ void ASTResultSynthesizer::CommitPersistentDecls() { return; auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); - ClangASTContext *scratch_ctx = ClangASTContext::GetScratch(m_target); + TypeSystemClang *scratch_ctx = TypeSystemClang::GetScratch(m_target); for (clang::NamedDecl *decl : m_decls) { StringRef name = decl->getName(); ConstString name_cs(name.str().c_str()); - Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl( + Decl *D_scratch = persistent_vars->GetClangASTImporter()->DeportDecl( &scratch_ctx->getASTContext(), decl); if (!D_scratch) { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h index 0b0f3b97705d..9de823bc75a7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h @@ -6,13 +6,20 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ASTResultSynthesizer_h_ -#define liblldb_ASTResultSynthesizer_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H -#include "lldb/Core/ClangForward.h" #include "lldb/Target/Target.h" #include "clang/Sema/SemaConsumer.h" +namespace clang { +class CompoundStmt; +class DeclContext; +class NamedDecl; +class ObjCMethodDecl; +class TypeDecl; +} // namespace clang + namespace lldb_private { /// \class ASTResultSynthesizer ASTResultSynthesizer.h @@ -163,4 +170,4 @@ private: } // namespace lldb_private -#endif // liblldb_ASTResultSynthesizer_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp index a164d48ae3e0..40f0de40da52 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp @@ -1,4 +1,4 @@ -//===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===// +//===-- ASTStructExtractor.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h index 078cf095975f..c285f6408895 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h @@ -6,13 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ASTStructExtractor_h_ -#define liblldb_ASTStructExtractor_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H #include "ClangExpressionVariable.h" #include "ClangFunctionCaller.h" -#include "lldb/Core/ClangForward.h" #include "clang/Sema/SemaConsumer.h" namespace lldb_private { @@ -129,4 +128,4 @@ private: } // namespace lldb_private -#endif // liblldb_ASTStructExtractor_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp index bbdf4e31c5a4..1e438ed9d73e 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp @@ -1,4 +1,4 @@ -//===-- ASTUtils.cpp --------------------------------------------*- C++ -*-===// +//===-- ASTUtils.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h index d429e8c3855f..3787c572d45b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h @@ -6,9 +6,10 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ASTUtils_h_ -#define liblldb_ASTUtils_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H +#include "clang/Basic/Module.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/Sema.h" @@ -71,7 +72,7 @@ public: return m_Source->getModule(ID); } - llvm::Optional<ASTSourceDescriptor> + llvm::Optional<clang::ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override { return m_Source->getSourceDescriptor(ID); } @@ -576,4 +577,4 @@ public: }; } // namespace lldb_private -#endif // liblldb_ASTUtils_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp new file mode 100644 index 000000000000..ac16738933ac --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -0,0 +1,1212 @@ +//===-- ClangASTImporter.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/Core/Module.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Log.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" +#include "llvm/Support/raw_ostream.h" + +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangASTSource.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +#include <memory> + +using namespace lldb_private; +using namespace clang; + +CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast, + const CompilerType &src_type) { + clang::ASTContext &dst_clang_ast = dst_ast.getASTContext(); + + TypeSystemClang *src_ast = + llvm::dyn_cast_or_null<TypeSystemClang>(src_type.GetTypeSystem()); + if (!src_ast) + return CompilerType(); + + clang::ASTContext &src_clang_ast = src_ast->getASTContext(); + + clang::QualType src_qual_type = ClangUtil::GetQualType(src_type); + + ImporterDelegateSP delegate_sp(GetDelegate(&dst_clang_ast, &src_clang_ast)); + if (!delegate_sp) + return CompilerType(); + + ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &dst_clang_ast); + + llvm::Expected<QualType> ret_or_error = delegate_sp->Import(src_qual_type); + if (!ret_or_error) { + Log *log = + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG_ERROR(log, ret_or_error.takeError(), + "Couldn't import type: {0}"); + return CompilerType(); + } + + lldb::opaque_compiler_type_t dst_clang_type = ret_or_error->getAsOpaquePtr(); + + if (dst_clang_type) + return CompilerType(&dst_ast, dst_clang_type); + return CompilerType(); +} + +clang::Decl *ClangASTImporter::CopyDecl(clang::ASTContext *dst_ast, + clang::Decl *decl) { + ImporterDelegateSP delegate_sp; + + clang::ASTContext *src_ast = &decl->getASTContext(); + delegate_sp = GetDelegate(dst_ast, src_ast); + + ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, dst_ast); + + if (!delegate_sp) + return nullptr; + + llvm::Expected<clang::Decl *> result = delegate_sp->Import(decl); + if (!result) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + LLDB_LOG_ERROR(log, result.takeError(), "Couldn't import decl: {0}"); + if (log) { + lldb::user_id_t user_id = LLDB_INVALID_UID; + ClangASTMetadata *metadata = GetDeclMetadata(decl); + if (metadata) + user_id = metadata->GetUserID(); + + if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl)) + LLDB_LOG(log, + " [ClangASTImporter] WARNING: Failed to import a {0} " + "'{1}', metadata {2}", + decl->getDeclKindName(), named_decl->getNameAsString(), + user_id); + else + LLDB_LOG(log, + " [ClangASTImporter] WARNING: Failed to import a {0}, " + "metadata {1}", + decl->getDeclKindName(), user_id); + } + return nullptr; + } + + return *result; +} + +class DeclContextOverride { +private: + struct Backup { + clang::DeclContext *decl_context; + clang::DeclContext *lexical_decl_context; + }; + + llvm::DenseMap<clang::Decl *, Backup> m_backups; + + void OverrideOne(clang::Decl *decl) { + if (m_backups.find(decl) != m_backups.end()) { + return; + } + + m_backups[decl] = {decl->getDeclContext(), decl->getLexicalDeclContext()}; + + decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl()); + decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl()); + } + + bool ChainPassesThrough( + clang::Decl *decl, clang::DeclContext *base, + clang::DeclContext *(clang::Decl::*contextFromDecl)(), + clang::DeclContext *(clang::DeclContext::*contextFromContext)()) { + for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); decl_ctx; + decl_ctx = (decl_ctx->*contextFromContext)()) { + if (decl_ctx == base) { + return true; + } + } + + return false; + } + + clang::Decl *GetEscapedChild(clang::Decl *decl, + clang::DeclContext *base = nullptr) { + if (base) { + // decl's DeclContext chains must pass through base. + + if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext, + &clang::DeclContext::getParent) || + !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext, + &clang::DeclContext::getLexicalParent)) { + return decl; + } + } else { + base = clang::dyn_cast<clang::DeclContext>(decl); + + if (!base) { + return nullptr; + } + } + + if (clang::DeclContext *context = + clang::dyn_cast<clang::DeclContext>(decl)) { + for (clang::Decl *decl : context->decls()) { + if (clang::Decl *escaped_child = GetEscapedChild(decl)) { + return escaped_child; + } + } + } + + return nullptr; + } + + void Override(clang::Decl *decl) { + if (clang::Decl *escaped_child = GetEscapedChild(decl)) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + LLDB_LOG(log, + " [ClangASTImporter] DeclContextOverride couldn't " + "override ({0}Decl*){1} - its child ({2}Decl*){3} escapes", + decl->getDeclKindName(), decl, escaped_child->getDeclKindName(), + escaped_child); + lldbassert(0 && "Couldn't override!"); + } + + OverrideOne(decl); + } + +public: + DeclContextOverride() {} + + void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) { + for (DeclContext *decl_context = decl->getLexicalDeclContext(); + decl_context; decl_context = decl_context->getLexicalParent()) { + DeclContext *redecl_context = decl_context->getRedeclContext(); + + if (llvm::isa<FunctionDecl>(redecl_context) && + llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) { + for (clang::Decl *child_decl : decl_context->decls()) { + Override(child_decl); + } + } + } + } + + ~DeclContextOverride() { + for (const std::pair<clang::Decl *, Backup> &backup : m_backups) { + backup.first->setDeclContext(backup.second.decl_context); + backup.first->setLexicalDeclContext(backup.second.lexical_decl_context); + } + } +}; + +namespace { +/// Completes all imported TagDecls at the end of the scope. +/// +/// While in a CompleteTagDeclsScope, every decl that could be completed will +/// be completed at the end of the scope (including all Decls that are +/// imported while completing the original Decls). +class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { + ClangASTImporter::ImporterDelegateSP m_delegate; + llvm::SmallVector<NamedDecl *, 32> m_decls_to_complete; + llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed; + clang::ASTContext *m_dst_ctx; + clang::ASTContext *m_src_ctx; + ClangASTImporter &importer; + +public: + /// Constructs a CompleteTagDeclsScope. + /// \param importer The ClangASTImporter that we should observe. + /// \param dst_ctx The ASTContext to which Decls are imported. + /// \param src_ctx The ASTContext from which Decls are imported. + explicit CompleteTagDeclsScope(ClangASTImporter &importer, + clang::ASTContext *dst_ctx, + clang::ASTContext *src_ctx) + : m_delegate(importer.GetDelegate(dst_ctx, src_ctx)), m_dst_ctx(dst_ctx), + m_src_ctx(src_ctx), importer(importer) { + m_delegate->SetImportListener(this); + } + + virtual ~CompleteTagDeclsScope() { + ClangASTImporter::ASTContextMetadataSP to_context_md = + importer.GetContextMetadata(m_dst_ctx); + + // Complete all decls we collected until now. + while (!m_decls_to_complete.empty()) { + NamedDecl *decl = m_decls_to_complete.pop_back_val(); + m_decls_already_completed.insert(decl); + + // We should only complete decls coming from the source context. + assert(to_context_md->m_origins[decl].ctx == m_src_ctx); + + Decl *original_decl = to_context_md->m_origins[decl].decl; + + // Complete the decl now. + TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl); + if (auto *tag_decl = dyn_cast<TagDecl>(decl)) { + if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) { + if (original_tag_decl->isCompleteDefinition()) { + m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl); + tag_decl->setCompleteDefinition(true); + } + } + + tag_decl->setHasExternalLexicalStorage(false); + tag_decl->setHasExternalVisibleStorage(false); + } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) { + container_decl->setHasExternalLexicalStorage(false); + container_decl->setHasExternalVisibleStorage(false); + } + + to_context_md->m_origins.erase(decl); + } + + // Stop listening to imported decls. We do this after clearing the + // Decls we needed to import to catch all Decls they might have pulled in. + m_delegate->RemoveImportListener(); + } + + void NewDeclImported(clang::Decl *from, clang::Decl *to) override { + // Filter out decls that we can't complete later. + if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to)) + return; + RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from); + // We don't need to complete injected class name decls. + if (from_record_decl && from_record_decl->isInjectedClassName()) + return; + + NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to); + // Check if we already completed this type. + if (m_decls_already_completed.count(to_named_decl) != 0) + return; + m_decls_to_complete.push_back(to_named_decl); + } +}; +} // namespace + +CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst, + const CompilerType &src_type) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + TypeSystemClang *src_ctxt = + llvm::cast<TypeSystemClang>(src_type.GetTypeSystem()); + + LLDB_LOG(log, + " [ClangASTImporter] DeportType called on ({0}Type*){1} " + "from (ASTContext*){2} to (ASTContext*){3}", + src_type.GetTypeName(), src_type.GetOpaqueQualType(), + &src_ctxt->getASTContext(), &dst.getASTContext()); + + DeclContextOverride decl_context_override; + + if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>()) + decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl()); + + CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(), + &src_ctxt->getASTContext()); + return CopyType(dst, src_type); +} + +clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx, + clang::Decl *decl) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + clang::ASTContext *src_ctx = &decl->getASTContext(); + LLDB_LOG(log, + " [ClangASTImporter] DeportDecl called on ({0}Decl*){1} from " + "(ASTContext*){2} to (ASTContext*){3}", + decl->getDeclKindName(), decl, src_ctx, dst_ctx); + + DeclContextOverride decl_context_override; + + decl_context_override.OverrideAllDeclsFromContainingFunction(decl); + + clang::Decl *result; + { + CompleteTagDeclsScope complete_scope(*this, dst_ctx, src_ctx); + result = CopyDecl(dst_ctx, decl); + } + + if (!result) + return nullptr; + + LLDB_LOG(log, + " [ClangASTImporter] DeportDecl deported ({0}Decl*){1} to " + "({2}Decl*){3}", + decl->getDeclKindName(), decl, result->getDeclKindName(), result); + + return result; +} + +bool ClangASTImporter::CanImport(const CompilerType &type) { + if (!ClangUtil::IsClangType(type)) + return false; + + // TODO: remove external completion BOOL + // CompleteAndFetchChildren should get the Decl out and check for the + + clang::QualType qual_type( + ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + if (GetDeclOrigin(cxx_record_decl).Valid()) + return true; + } + } break; + + case clang::Type::Enum: { + clang::EnumDecl *enum_decl = + llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) { + if (GetDeclOrigin(enum_decl).Valid()) + return true; + } + } break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added + // ASTContext because it only supports TagDecl objects right now... + if (class_interface_decl) { + if (GetDeclOrigin(class_interface_decl).Valid()) + return true; + } + } + } break; + + case clang::Type::Typedef: + return CanImport(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::TypedefType>(qual_type) + ->getDecl() + ->getUnderlyingType() + .getAsOpaquePtr())); + + case clang::Type::Auto: + return CanImport(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::AutoType>(qual_type) + ->getDeducedType() + .getAsOpaquePtr())); + + case clang::Type::Elaborated: + return CanImport(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::ElaboratedType>(qual_type) + ->getNamedType() + .getAsOpaquePtr())); + + case clang::Type::Paren: + return CanImport(CompilerType( + type.GetTypeSystem(), + llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); + + default: + break; + } + + return false; +} + +bool ClangASTImporter::Import(const CompilerType &type) { + if (!ClangUtil::IsClangType(type)) + return false; + // TODO: remove external completion BOOL + // CompleteAndFetchChildren should get the Decl out and check for the + + clang::QualType qual_type( + ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + if (GetDeclOrigin(cxx_record_decl).Valid()) + return CompleteAndFetchChildren(qual_type); + } + } break; + + case clang::Type::Enum: { + clang::EnumDecl *enum_decl = + llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) { + if (GetDeclOrigin(enum_decl).Valid()) + return CompleteAndFetchChildren(qual_type); + } + } break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added + // ASTContext because it only supports TagDecl objects right now... + if (class_interface_decl) { + if (GetDeclOrigin(class_interface_decl).Valid()) + return CompleteAndFetchChildren(qual_type); + } + } + } break; + + case clang::Type::Typedef: + return Import(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::TypedefType>(qual_type) + ->getDecl() + ->getUnderlyingType() + .getAsOpaquePtr())); + + case clang::Type::Auto: + return Import(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::AutoType>(qual_type) + ->getDeducedType() + .getAsOpaquePtr())); + + case clang::Type::Elaborated: + return Import(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::ElaboratedType>(qual_type) + ->getNamedType() + .getAsOpaquePtr())); + + case clang::Type::Paren: + return Import(CompilerType( + type.GetTypeSystem(), + llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); + + default: + break; + } + return false; +} + +bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { + if (!CanImport(compiler_type)) + return false; + + if (Import(compiler_type)) { + TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type); + return true; + } + + TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), + false); + return false; +} + +bool ClangASTImporter::LayoutRecordType( + const clang::RecordDecl *record_decl, uint64_t &bit_size, + uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets) { + RecordDeclToLayoutMap::iterator pos = + m_record_decl_to_layout_map.find(record_decl); + bool success = false; + base_offsets.clear(); + vbase_offsets.clear(); + if (pos != m_record_decl_to_layout_map.end()) { + bit_size = pos->second.bit_size; + alignment = pos->second.alignment; + field_offsets.swap(pos->second.field_offsets); + base_offsets.swap(pos->second.base_offsets); + vbase_offsets.swap(pos->second.vbase_offsets); + m_record_decl_to_layout_map.erase(pos); + success = true; + } else { + bit_size = 0; + alignment = 0; + field_offsets.clear(); + } + return success; +} + +void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl, + const LayoutInfo &layout) { + m_record_decl_to_layout_map.insert(std::make_pair(decl, layout)); +} + +bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) { + DeclOrigin decl_origin = GetDeclOrigin(decl); + + if (!decl_origin.Valid()) + return false; + + if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl)) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&decl->getASTContext(), decl_origin.ctx)); + + ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, + &decl->getASTContext()); + if (delegate_sp) + delegate_sp->ImportDefinitionTo(decl, decl_origin.decl); + + return true; +} + +bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, + clang::TagDecl *origin_decl) { + clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext(); + + if (!TypeSystemClang::GetCompleteDecl(origin_ast_ctx, origin_decl)) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&decl->getASTContext(), origin_ast_ctx)); + + if (delegate_sp) + delegate_sp->ImportDefinitionTo(decl, origin_decl); + + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + OriginMap &origins = context_md->m_origins; + + origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl); + + return true; +} + +bool ClangASTImporter::CompleteObjCInterfaceDecl( + clang::ObjCInterfaceDecl *interface_decl) { + DeclOrigin decl_origin = GetDeclOrigin(interface_decl); + + if (!decl_origin.Valid()) + return false; + + if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl)) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx)); + + if (delegate_sp) + delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl); + + if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass()) + RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0)); + + return true; +} + +bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) { + if (!RequireCompleteType(type)) + return false; + + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + if (const TagType *tag_type = type->getAs<TagType>()) { + TagDecl *tag_decl = tag_type->getDecl(); + + DeclOrigin decl_origin = GetDeclOrigin(tag_decl); + + if (!decl_origin.Valid()) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx)); + + ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, + &tag_decl->getASTContext()); + + TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl); + + for (Decl *origin_child_decl : origin_tag_decl->decls()) { + llvm::Expected<Decl *> imported_or_err = + delegate_sp->Import(origin_child_decl); + if (!imported_or_err) { + LLDB_LOG_ERROR(log, imported_or_err.takeError(), + "Couldn't import decl: {0}"); + return false; + } + } + + if (RecordDecl *record_decl = dyn_cast<RecordDecl>(origin_tag_decl)) + record_decl->setHasLoadedFieldsFromExternalStorage(true); + + return true; + } + + if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) { + if (ObjCInterfaceDecl *objc_interface_decl = + objc_object_type->getInterface()) { + DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl); + + if (!decl_origin.Valid()) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx)); + + ObjCInterfaceDecl *origin_interface_decl = + llvm::dyn_cast<ObjCInterfaceDecl>(decl_origin.decl); + + for (Decl *origin_child_decl : origin_interface_decl->decls()) { + llvm::Expected<Decl *> imported_or_err = + delegate_sp->Import(origin_child_decl); + if (!imported_or_err) { + LLDB_LOG_ERROR(log, imported_or_err.takeError(), + "Couldn't import decl: {0}"); + return false; + } + } + + return true; + } + return false; + } + + return true; +} + +bool ClangASTImporter::RequireCompleteType(clang::QualType type) { + if (type.isNull()) + return false; + + if (const TagType *tag_type = type->getAs<TagType>()) { + TagDecl *tag_decl = tag_type->getDecl(); + + if (tag_decl->getDefinition() || tag_decl->isBeingDefined()) + return true; + + return CompleteTagDecl(tag_decl); + } + if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) { + if (ObjCInterfaceDecl *objc_interface_decl = + objc_object_type->getInterface()) + return CompleteObjCInterfaceDecl(objc_interface_decl); + return false; + } + if (const ArrayType *array_type = type->getAsArrayTypeUnsafe()) + return RequireCompleteType(array_type->getElementType()); + if (const AtomicType *atomic_type = type->getAs<AtomicType>()) + return RequireCompleteType(atomic_type->getPointeeType()); + + return true; +} + +ClangASTMetadata *ClangASTImporter::GetDeclMetadata(const clang::Decl *decl) { + DeclOrigin decl_origin = GetDeclOrigin(decl); + + if (decl_origin.Valid()) { + TypeSystemClang *ast = TypeSystemClang::GetASTContext(decl_origin.ctx); + return ast->GetMetadata(decl_origin.decl); + } + TypeSystemClang *ast = TypeSystemClang::GetASTContext(&decl->getASTContext()); + return ast->GetMetadata(decl); +} + +ClangASTImporter::DeclOrigin +ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) { + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + OriginMap &origins = context_md->m_origins; + + OriginMap::iterator iter = origins.find(decl); + + if (iter != origins.end()) + return iter->second; + return DeclOrigin(); +} + +void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl, + clang::Decl *original_decl) { + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + OriginMap &origins = context_md->m_origins; + + OriginMap::iterator iter = origins.find(decl); + + if (iter != origins.end()) { + iter->second.decl = original_decl; + iter->second.ctx = &original_decl->getASTContext(); + return; + } + origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl); +} + +void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl, + NamespaceMapSP &namespace_map) { + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + context_md->m_namespace_maps[decl] = namespace_map; +} + +ClangASTImporter::NamespaceMapSP +ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl) { + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps; + + NamespaceMetaMap::iterator iter = namespace_maps.find(decl); + + if (iter != namespace_maps.end()) + return iter->second; + return NamespaceMapSP(); +} + +void ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl) { + assert(decl); + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + const DeclContext *parent_context = decl->getDeclContext(); + const NamespaceDecl *parent_namespace = + dyn_cast<NamespaceDecl>(parent_context); + NamespaceMapSP parent_map; + + if (parent_namespace) + parent_map = GetNamespaceMap(parent_namespace); + + NamespaceMapSP new_map; + + new_map = std::make_shared<NamespaceMap>(); + + if (context_md->m_map_completer) { + std::string namespace_string = decl->getDeclName().getAsString(); + + context_md->m_map_completer->CompleteNamespaceMap( + new_map, ConstString(namespace_string.c_str()), parent_map); + } + + context_md->m_namespace_maps[decl] = new_map; +} + +void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + LLDB_LOG(log, + " [ClangASTImporter] Forgetting destination (ASTContext*){0}", + dst_ast); + + m_metadata_map.erase(dst_ast); +} + +void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast, + clang::ASTContext *src_ast) { + ASTContextMetadataSP md = MaybeGetContextMetadata(dst_ast); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + LLDB_LOG(log, + " [ClangASTImporter] Forgetting source->dest " + "(ASTContext*){0}->(ASTContext*){1}", + src_ast, dst_ast); + + if (!md) + return; + + md->m_delegates.erase(src_ast); + + for (OriginMap::iterator iter = md->m_origins.begin(); + iter != md->m_origins.end();) { + if (iter->second.ctx == src_ast) + md->m_origins.erase(iter++); + else + ++iter; + } +} + +ClangASTImporter::MapCompleter::~MapCompleter() { return; } + +llvm::Expected<Decl *> +ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { + if (m_std_handler) { + llvm::Optional<Decl *> D = m_std_handler->Import(From); + if (D) { + // Make sure we don't use this decl later to map it back to it's original + // decl. The decl the CxxModuleHandler created has nothing to do with + // the one from debug info, and linking those two would just cause the + // ASTImporter to try 'updating' the module decl with the minimal one from + // the debug info. + m_decls_to_ignore.insert(*D); + return *D; + } + } + + // Check which ASTContext this declaration originally came from. + DeclOrigin origin = m_master.GetDeclOrigin(From); + // If it originally came from the target ASTContext then we can just + // pretend that the original is the one we imported. This can happen for + // example when inspecting a persistent declaration from the scratch + // ASTContext (which will provide the declaration when parsing the + // expression and then we later try to copy the declaration back to the + // scratch ASTContext to store the result). + // Without this check we would ask the ASTImporter to import a declaration + // into the same ASTContext where it came from (which doesn't make a lot of + // sense). + if (origin.Valid() && origin.ctx == &getToContext()) { + RegisterImportedDecl(From, origin.decl); + return origin.decl; + } + + // This declaration came originally from another ASTContext. Instead of + // copying our potentially incomplete 'From' Decl we instead go to the + // original ASTContext and copy the original to the target. This is not + // only faster than first completing our current decl and then copying it + // to the target, but it also prevents that indirectly copying the same + // declaration to the same target requires the ASTImporter to merge all + // the different decls that appear to come from different ASTContexts (even + // though all these different source ASTContexts just got a copy from + // one source AST). + if (origin.Valid()) { + auto R = m_master.CopyDecl(&getToContext(), origin.decl); + if (R) { + RegisterImportedDecl(From, R); + return R; + } + } + + // If we have a forcefully completed type, try to find an actual definition + // for it in other modules. + const ClangASTMetadata *md = m_master.GetDeclMetadata(From); + auto *td = dyn_cast<TagDecl>(From); + if (td && md && md->IsForcefullyCompleted()) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG(log, + "[ClangASTImporter] Searching for a complete definition of {0} in " + "other modules", + td->getName()); + Expected<DeclContext *> dc_or_err = ImportContext(td->getDeclContext()); + if (!dc_or_err) + return dc_or_err.takeError(); + Expected<DeclarationName> dn_or_err = Import(td->getDeclName()); + if (!dn_or_err) + return dn_or_err.takeError(); + DeclContext *dc = *dc_or_err; + DeclContext::lookup_result lr = dc->lookup(*dn_or_err); + if (lr.size()) { + clang::Decl *lookup_found = lr.front(); + RegisterImportedDecl(From, lookup_found); + m_decls_to_ignore.insert(lookup_found); + return lookup_found; + } else + LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); + } + + return ASTImporter::ImportImpl(From); +} + +void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( + clang::Decl *to, clang::Decl *from) { + // We might have a forward declaration from a shared library that we + // gave external lexical storage so that Clang asks us about the full + // definition when it needs it. In this case the ASTImporter isn't aware + // that the forward decl from the shared library is the actual import + // target but would create a second declaration that would then be defined. + // 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); + + /* + if (to_objc_interface) + to_objc_interface->startDefinition(); + + CXXRecordDecl *to_cxx_record = dyn_cast<CXXRecordDecl>(to); + + if (to_cxx_record) + to_cxx_record->startDefinition(); + */ + + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + if (llvm::Error err = ImportDefinition(from)) { + LLDB_LOG_ERROR(log, std::move(err), + "[ClangASTImporter] Error during importing definition: {0}"); + return; + } + + if (clang::TagDecl *to_tag = dyn_cast<clang::TagDecl>(to)) { + if (clang::TagDecl *from_tag = dyn_cast<clang::TagDecl>(from)) { + to_tag->setCompleteDefinition(from_tag->isCompleteDefinition()); + + if (Log *log_ast = + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST)) { + std::string name_string; + if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) { + llvm::raw_string_ostream name_stream(name_string); + from_named_decl->printName(name_stream); + name_stream.flush(); + } + LLDB_LOG(log_ast, "==== [ClangASTImporter][TUDecl: {0}] Imported " + "({1}Decl*){2}, named {3} (from " + "(Decl*){4})", + static_cast<void *>(to->getTranslationUnitDecl()), + from->getDeclKindName(), static_cast<void *>(to), name_string, + static_cast<void *>(from)); + + // Log the AST of the TU. + std::string ast_string; + llvm::raw_string_ostream ast_stream(ast_string); + to->getTranslationUnitDecl()->dump(ast_stream); + LLDB_LOG(log_ast, "{0}", ast_string); + } + } + } + + // If we're dealing with an Objective-C class, ensure that the inheritance + // has been set up correctly. The ASTImporter may not do this correctly if + // the class was originally sourced from symbols. + + if (ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to)) { + do { + ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass(); + + if (to_superclass) + break; // we're not going to override it if it's set + + ObjCInterfaceDecl *from_objc_interface = + dyn_cast<ObjCInterfaceDecl>(from); + + if (!from_objc_interface) + break; + + ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass(); + + if (!from_superclass) + break; + + llvm::Expected<Decl *> imported_from_superclass_decl = + Import(from_superclass); + + if (!imported_from_superclass_decl) { + LLDB_LOG_ERROR(log, imported_from_superclass_decl.takeError(), + "Couldn't import decl: {0}"); + break; + } + + ObjCInterfaceDecl *imported_from_superclass = + dyn_cast<ObjCInterfaceDecl>(*imported_from_superclass_decl); + + if (!imported_from_superclass) + break; + + if (!to_objc_interface->hasDefinition()) + to_objc_interface->startDefinition(); + + to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo( + m_source_ctx->getObjCInterfaceType(imported_from_superclass))); + } while (false); + } +} + +/// Takes a CXXMethodDecl and completes the return type if necessary. This +/// is currently only necessary for virtual functions with covariant return +/// types where Clang's CodeGen expects that the underlying records are already +/// completed. +static void MaybeCompleteReturnType(ClangASTImporter &importer, + CXXMethodDecl *to_method) { + if (!to_method->isVirtual()) + return; + QualType return_type = to_method->getReturnType(); + if (!return_type->isPointerType() && !return_type->isReferenceType()) + return; + + clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl(); + if (!rd) + return; + if (rd->getDefinition()) + return; + + importer.CompleteTagDecl(rd); +} + +/// Recreate a module with its parents in \p to_source and return its id. +static OptionalClangModuleID +RemapModule(OptionalClangModuleID from_id, + ClangExternalASTSourceCallbacks &from_source, + ClangExternalASTSourceCallbacks &to_source) { + if (!from_id.HasValue()) + return {}; + clang::Module *module = from_source.getModule(from_id.GetValue()); + OptionalClangModuleID parent = RemapModule( + from_source.GetIDForModule(module->Parent), from_source, to_source); + TypeSystemClang &to_ts = to_source.GetTypeSystem(); + return to_ts.GetOrCreateClangModule(module->Name, parent, module->IsFramework, + module->IsExplicit); +} + +void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, + clang::Decl *to) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + // 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); + + // Transfer module ownership information. + auto *from_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>( + getFromContext().getExternalSource()); + // Can also be a ClangASTSourceProxy. + auto *to_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>( + getToContext().getExternalSource()); + if (from_source && to_source) { + OptionalClangModuleID from_id(from->getOwningModuleID()); + OptionalClangModuleID to_id = + RemapModule(from_id, *from_source, *to_source); + TypeSystemClang &to_ts = to_source->GetTypeSystem(); + to_ts.SetOwningModule(to, to_id); + } + + lldb::user_id_t user_id = LLDB_INVALID_UID; + ClangASTMetadata *metadata = m_master.GetDeclMetadata(from); + if (metadata) + user_id = metadata->GetUserID(); + + if (log) { + if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) { + std::string name_string; + llvm::raw_string_ostream name_stream(name_string); + from_named_decl->printName(name_stream); + name_stream.flush(); + + LLDB_LOG(log, + " [ClangASTImporter] Imported ({0}Decl*){1}, named {2} (from " + "(Decl*){3}), metadata {4}", + from->getDeclKindName(), to, name_string, from, user_id); + } else { + LLDB_LOG(log, + " [ClangASTImporter] Imported ({0}Decl*){1} (from " + "(Decl*){2}), metadata {3}", + from->getDeclKindName(), to, from, user_id); + } + } + + ASTContextMetadataSP to_context_md = + m_master.GetContextMetadata(&to->getASTContext()); + ASTContextMetadataSP from_context_md = + m_master.MaybeGetContextMetadata(m_source_ctx); + + if (from_context_md) { + OriginMap &origins = from_context_md->m_origins; + + OriginMap::iterator origin_iter = origins.find(from); + + if (origin_iter != origins.end()) { + if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || + user_id != LLDB_INVALID_UID) { + if (origin_iter->second.ctx != &to->getASTContext()) + to_context_md->m_origins[to] = origin_iter->second; + } + + ImporterDelegateSP direct_completer = + m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx); + + if (direct_completer.get() != this) + direct_completer->ASTImporter::Imported(origin_iter->second.decl, to); + + LLDB_LOG(log, + " [ClangASTImporter] Propagated origin " + "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to " + "(ASTContext*){3}", + origin_iter->second.decl, origin_iter->second.ctx, + &from->getASTContext(), &to->getASTContext()); + } else { + if (m_new_decl_listener) + m_new_decl_listener->NewDeclImported(from, to); + + if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || + user_id != LLDB_INVALID_UID) { + to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); + } + + LLDB_LOG(log, + " [ClangASTImporter] Decl has no origin information in " + "(ASTContext*){0}", + &from->getASTContext()); + } + + if (auto *to_namespace = dyn_cast<clang::NamespaceDecl>(to)) { + auto *from_namespace = cast<clang::NamespaceDecl>(from); + + NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps; + + NamespaceMetaMap::iterator namespace_map_iter = + namespace_maps.find(from_namespace); + + if (namespace_map_iter != namespace_maps.end()) + to_context_md->m_namespace_maps[to_namespace] = + namespace_map_iter->second; + } + } else { + to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); + + LLDB_LOG(log, + " [ClangASTImporter] Sourced origin " + "(Decl*){0}/(ASTContext*){1} into (ASTContext*){2}", + from, m_source_ctx, &to->getASTContext()); + } + + if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) { + to_tag_decl->setHasExternalLexicalStorage(); + to_tag_decl->getPrimaryContext()->setMustBuildLookupTable(); + auto from_tag_decl = cast<TagDecl>(from); + + LLDB_LOG( + log, + " [ClangASTImporter] To is a TagDecl - attributes {0}{1} [{2}->{3}]", + (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""), + (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""), + (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"), + (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete")); + } + + if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) { + m_master.BuildNamespaceMap(to_namespace_decl); + to_namespace_decl->setHasExternalVisibleStorage(); + } + + if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) { + to_container_decl->setHasExternalLexicalStorage(); + to_container_decl->setHasExternalVisibleStorage(); + + if (log) { + if (ObjCInterfaceDecl *to_interface_decl = + llvm::dyn_cast<ObjCInterfaceDecl>(to_container_decl)) { + LLDB_LOG( + log, + " [ClangASTImporter] To is an ObjCInterfaceDecl - attributes " + "{0}{1}{2}", + (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""), + (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""), + (to_interface_decl->hasDefinition() ? " HasDefinition" : "")); + } else { + LLDB_LOG( + log, " [ClangASTImporter] To is an {0}Decl - attributes {1}{2}", + ((Decl *)to_container_decl)->getDeclKindName(), + (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""), + (to_container_decl->hasExternalVisibleStorage() ? " Visible" : "")); + } + } + } + + if (clang::CXXMethodDecl *to_method = dyn_cast<CXXMethodDecl>(to)) + MaybeCompleteReturnType(m_master, to_method); +} + +clang::Decl * +ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) { + return m_master.GetDeclOrigin(To).decl; +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h new file mode 100644 index 000000000000..6ceec774914b --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -0,0 +1,328 @@ +//===-- ClangASTImporter.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_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H + +#include <map> +#include <memory> +#include <set> +#include <vector> + +#include "clang/AST/ASTImporter.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/CompilerDeclContext.h" +#include "lldb/lldb-types.h" + +#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" + +#include "llvm/ADT/DenseMap.h" + +namespace lldb_private { + +class ClangASTMetadata; +class TypeSystemClang; + +class ClangASTImporter { +public: + struct LayoutInfo { + LayoutInfo() = default; + typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + OffsetMap; + + uint64_t bit_size = 0; + uint64_t alignment = 0; + llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets; + OffsetMap base_offsets; + OffsetMap vbase_offsets; + }; + + ClangASTImporter() + : m_file_manager(clang::FileSystemOptions(), + FileSystem::Instance().GetVirtualFileSystem()) {} + + CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type); + + clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); + + CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type); + + clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); + + /// Sets the layout for the given RecordDecl. The layout will later be + /// used by Clang's during code generation. Not calling this function for + /// a RecordDecl will cause that Clang's codegen tries to layout the + /// record by itself. + /// + /// \param decl The RecordDecl to set the layout for. + /// \param layout The layout for the record. + void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout); + + bool LayoutRecordType( + const clang::RecordDecl *record_decl, uint64_t &bit_size, + uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets); + + bool CanImport(const CompilerType &type); + + bool Import(const CompilerType &type); + + bool CompleteType(const CompilerType &compiler_type); + + bool CompleteTagDecl(clang::TagDecl *decl); + + bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin); + + bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl); + + bool CompleteAndFetchChildren(clang::QualType type); + + bool RequireCompleteType(clang::QualType type); + + void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl); + + ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl); + + // + // Namespace maps + // + + typedef std::pair<lldb::ModuleSP, CompilerDeclContext> NamespaceMapItem; + typedef std::vector<NamespaceMapItem> NamespaceMap; + typedef std::shared_ptr<NamespaceMap> NamespaceMapSP; + + void RegisterNamespaceMap(const clang::NamespaceDecl *decl, + NamespaceMapSP &namespace_map); + + NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl); + + void BuildNamespaceMap(const clang::NamespaceDecl *decl); + + // + // Completers for maps + // + + class MapCompleter { + public: + virtual ~MapCompleter(); + + virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map, + ConstString name, + NamespaceMapSP &parent_map) const = 0; + }; + + void InstallMapCompleter(clang::ASTContext *dst_ctx, + MapCompleter &completer) { + ASTContextMetadataSP context_md; + ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); + + if (context_md_iter == m_metadata_map.end()) { + context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); + m_metadata_map[dst_ctx] = context_md; + } else { + context_md = context_md_iter->second; + } + + context_md->m_map_completer = &completer; + } + + void ForgetDestination(clang::ASTContext *dst_ctx); + void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx); + + struct DeclOrigin { + DeclOrigin() : ctx(nullptr), decl(nullptr) {} + + DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl) + : ctx(_ctx), decl(_decl) {} + + DeclOrigin(const DeclOrigin &rhs) { + ctx = rhs.ctx; + decl = rhs.decl; + } + + void operator=(const DeclOrigin &rhs) { + ctx = rhs.ctx; + decl = rhs.decl; + } + + bool Valid() { return (ctx != nullptr || decl != nullptr); } + + clang::ASTContext *ctx; + clang::Decl *decl; + }; + + typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap; + + /// Listener interface used by the ASTImporterDelegate to inform other code + /// about decls that have been imported the first time. + struct NewDeclListener { + virtual ~NewDeclListener() = default; + /// A decl has been imported for the first time. + virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0; + }; + + /// ASTImporter that intercepts and records the import process of the + /// underlying ASTImporter. + /// + /// This class updates the map from declarations to their original + /// declarations and can record declarations that have been imported in a + /// certain interval. + /// + /// When intercepting a declaration import, the ASTImporterDelegate uses the + /// CxxModuleHandler to replace any missing or malformed declarations with + /// their counterpart from a C++ module. + struct ASTImporterDelegate : public clang::ASTImporter { + ASTImporterDelegate(ClangASTImporter &master, clang::ASTContext *target_ctx, + clang::ASTContext *source_ctx) + : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx, + master.m_file_manager, true /*minimal*/), + m_master(master), m_source_ctx(source_ctx) { + setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal); + } + + /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate + /// and deattaches it at the end of the scope. Supports being used multiple + /// times on the same ASTImporterDelegate instance in nested scopes. + class CxxModuleScope { + /// The handler we attach to the ASTImporterDelegate. + CxxModuleHandler m_handler; + /// The ASTImporterDelegate we are supposed to attach the handler to. + ASTImporterDelegate &m_delegate; + /// True iff we attached the handler to the ASTImporterDelegate. + bool m_valid = false; + + public: + CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx) + : m_delegate(delegate) { + // If the delegate doesn't have a CxxModuleHandler yet, create one + // and attach it. + if (!delegate.m_std_handler) { + m_handler = CxxModuleHandler(delegate, dst_ctx); + m_valid = true; + delegate.m_std_handler = &m_handler; + } + } + ~CxxModuleScope() { + if (m_valid) { + // Make sure no one messed with the handler we placed. + assert(m_delegate.m_std_handler == &m_handler); + m_delegate.m_std_handler = nullptr; + } + } + }; + + void ImportDefinitionTo(clang::Decl *to, clang::Decl *from); + + void Imported(clang::Decl *from, clang::Decl *to) override; + + clang::Decl *GetOriginalDecl(clang::Decl *To) override; + + void SetImportListener(NewDeclListener *listener) { + assert(m_new_decl_listener == nullptr && "Already attached a listener?"); + m_new_decl_listener = listener; + } + void RemoveImportListener() { m_new_decl_listener = nullptr; } + + protected: + llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override; + + private: + /// Decls we should ignore when mapping decls back to their original + /// ASTContext. Used by the CxxModuleHandler to mark declarations that + /// were created from the 'std' C++ module to prevent that the Importer + /// tries to sync them with the broken equivalent in the debug info AST. + llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore; + ClangASTImporter &m_master; + clang::ASTContext *m_source_ctx; + CxxModuleHandler *m_std_handler = nullptr; + /// The currently attached listener. + NewDeclListener *m_new_decl_listener = nullptr; + }; + + typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP; + typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap; + typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP> + NamespaceMetaMap; + + struct ASTContextMetadata { + ASTContextMetadata(clang::ASTContext *dst_ctx) + : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(), + m_map_completer(nullptr) {} + + clang::ASTContext *m_dst_ctx; + DelegateMap m_delegates; + OriginMap m_origins; + + NamespaceMetaMap m_namespace_maps; + MapCompleter *m_map_completer; + }; + + typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP; + typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP> + ContextMetadataMap; + + ContextMetadataMap m_metadata_map; + + ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) { + ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); + + if (context_md_iter == m_metadata_map.end()) { + ASTContextMetadataSP context_md = + ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); + m_metadata_map[dst_ctx] = context_md; + return context_md; + } + return context_md_iter->second; + } + + ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) { + ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); + + if (context_md_iter != m_metadata_map.end()) + return context_md_iter->second; + return ASTContextMetadataSP(); + } + + ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx, + clang::ASTContext *src_ctx) { + ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx); + + DelegateMap &delegates = context_md->m_delegates; + DelegateMap::iterator delegate_iter = delegates.find(src_ctx); + + if (delegate_iter == delegates.end()) { + ImporterDelegateSP delegate = + ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx)); + delegates[src_ctx] = delegate; + return delegate; + } + return delegate_iter->second; + } + + DeclOrigin GetDeclOrigin(const clang::Decl *decl); + + clang::FileManager m_file_manager; + typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> + RecordDeclToLayoutMap; + + RecordDeclToLayoutMap m_record_decl_to_layout_map; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp new file mode 100644 index 000000000000..42933c78b027 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp @@ -0,0 +1,35 @@ +//===-- ClangASTMetadata.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 "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb_private; + +void ClangASTMetadata::Dump(Stream *s) { + lldb::user_id_t uid = GetUserID(); + + if (uid != LLDB_INVALID_UID) { + s->Printf("uid=0x%" PRIx64, uid); + } + + uint64_t isa_ptr = GetISAPtr(); + if (isa_ptr != 0) { + s->Printf("isa_ptr=0x%" PRIx64, isa_ptr); + } + + const char *obj_ptr_name = GetObjectPtrName(); + if (obj_ptr_name) { + s->Printf("obj_ptr_name=\"%s\" ", obj_ptr_name); + } + + if (m_is_dynamic_cxx) { + s->Printf("is_dynamic_cxx=%i ", m_is_dynamic_cxx); + } + s->EOL(); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h new file mode 100644 index 000000000000..d3bcde2ced79 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h @@ -0,0 +1,110 @@ +//===-- ClangASTMetadata.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_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H + +#include "lldb/Core/dwarf.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" + +namespace lldb_private { + +class ClangASTMetadata { +public: + ClangASTMetadata() + : m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false), + m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true), + m_is_forcefully_completed(false) {} + + bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; } + + void SetIsDynamicCXXType(bool b) { m_is_dynamic_cxx = b; } + + void SetUserID(lldb::user_id_t user_id) { + m_user_id = user_id; + m_union_is_user_id = true; + m_union_is_isa_ptr = false; + } + + lldb::user_id_t GetUserID() const { + if (m_union_is_user_id) + return m_user_id; + else + return LLDB_INVALID_UID; + } + + void SetISAPtr(uint64_t isa_ptr) { + m_isa_ptr = isa_ptr; + m_union_is_user_id = false; + m_union_is_isa_ptr = true; + } + + uint64_t GetISAPtr() const { + if (m_union_is_isa_ptr) + return m_isa_ptr; + else + return 0; + } + + void SetObjectPtrName(const char *name) { + m_has_object_ptr = true; + if (strcmp(name, "self") == 0) + m_is_self = true; + else if (strcmp(name, "this") == 0) + m_is_self = false; + else + m_has_object_ptr = false; + } + + lldb::LanguageType GetObjectPtrLanguage() const { + if (m_has_object_ptr) { + if (m_is_self) + return lldb::eLanguageTypeObjC; + else + return lldb::eLanguageTypeC_plus_plus; + } + return lldb::eLanguageTypeUnknown; + } + + const char *GetObjectPtrName() const { + if (m_has_object_ptr) { + if (m_is_self) + return "self"; + else + return "this"; + } else + return nullptr; + } + + bool HasObjectPtr() const { return m_has_object_ptr; } + + /// A type is "forcefully completed" if it was declared complete to satisfy an + /// AST invariant (e.g. base classes must be complete types), but in fact we + /// were not able to find a actual definition for it. + bool IsForcefullyCompleted() const { return m_is_forcefully_completed; } + + void SetIsForcefullyCompleted(bool value = true) { + m_is_forcefully_completed = true; + } + + void Dump(Stream *s); + +private: + union { + lldb::user_id_t m_user_id; + uint64_t m_isa_ptr; + }; + + bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1, + m_is_self : 1, m_is_dynamic_cxx : 1, m_is_forcefully_completed : 1; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 42927ab6cc8a..6fe85a1298fc 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -1,4 +1,4 @@ -//===-- ClangASTSource.cpp ---------------------------------------*- C++-*-===// +//===-- ClangASTSource.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,8 +13,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolFile.h" @@ -23,8 +21,11 @@ #include "lldb/Utility/Log.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" +#include "clang/Basic/SourceManager.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include <memory> #include <vector> @@ -49,14 +50,16 @@ private: }; } -ClangASTSource::ClangASTSource(const lldb::TargetSP &target, - const lldb::ClangASTImporterSP &importer) - : m_import_in_progress(false), m_lookups_enabled(false), m_target(target), - m_ast_context(nullptr), m_active_lexical_decls(), m_active_lookups() { - m_ast_importer_sp = importer; +ClangASTSource::ClangASTSource( + const lldb::TargetSP &target, + const std::shared_ptr<ClangASTImporter> &importer) + : m_lookups_enabled(false), m_target(target), m_ast_context(nullptr), + m_ast_importer_sp(importer), m_active_lexical_decls(), + m_active_lookups() { + assert(m_ast_importer_sp && "No ClangASTImporter passed to ClangASTSource?"); } -void ClangASTSource::InstallASTContext(ClangASTContext &clang_ast_context) { +void ClangASTSource::InstallASTContext(TypeSystemClang &clang_ast_context) { m_ast_context = &clang_ast_context.getASTContext(); m_clang_ast_context = &clang_ast_context; m_file_manager = &m_ast_context->getSourceManager().getFileManager(); @@ -64,18 +67,15 @@ void ClangASTSource::InstallASTContext(ClangASTContext &clang_ast_context) { } ClangASTSource::~ClangASTSource() { - if (!m_ast_importer_sp) - return; - m_ast_importer_sp->ForgetDestination(m_ast_context); if (!m_target) return; // We are in the process of destruction, don't create clang ast context on // demand by passing false to - // Target::GetScratchClangASTContext(create_on_demand). - ClangASTContext *scratch_clang_ast_context = - ClangASTContext::GetScratch(*m_target, false); + // Target::GetScratchTypeSystemClang(create_on_demand). + TypeSystemClang *scratch_clang_ast_context = + TypeSystemClang::GetScratch(*m_target, false); if (!scratch_clang_ast_context) return; @@ -103,16 +103,8 @@ bool ClangASTSource::FindExternalVisibleDeclsByName( return false; } - if (GetImportInProgress()) { - SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); - return false; - } - std::string decl_name(clang_decl_name.getAsString()); - // if (m_decl_map.DoingASTImport ()) - // return DeclContext::lookup_result(); - // switch (clang_decl_name.getNameKind()) { // Normal identifiers. case DeclarationName::Identifier: { @@ -141,7 +133,7 @@ bool ClangASTSource::FindExternalVisibleDeclsByName( case DeclarationName::ObjCMultiArgSelector: { llvm::SmallVector<NamedDecl *, 1> method_decls; - NameSearchContext method_search_context(*this, method_decls, + NameSearchContext method_search_context(*m_clang_ast_context, method_decls, clang_decl_name, decl_ctx); FindObjCMethodDecls(method_search_context); @@ -179,154 +171,134 @@ bool ClangASTSource::FindExternalVisibleDeclsByName( return false; } m_active_lookups.insert(uniqued_const_decl_name); - // static uint32_t g_depth = 0; - // ++g_depth; - // printf("[%5u] FindExternalVisibleDeclsByName() \"%s\"\n", g_depth, - // uniqued_const_decl_name); llvm::SmallVector<NamedDecl *, 4> name_decls; - NameSearchContext name_search_context(*this, name_decls, clang_decl_name, - decl_ctx); + NameSearchContext name_search_context(*m_clang_ast_context, name_decls, + clang_decl_name, decl_ctx); FindExternalVisibleDecls(name_search_context); SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, name_decls); - // --g_depth; m_active_lookups.erase(uniqued_const_decl_name); return (name_decls.size() != 0); } -void ClangASTSource::CompleteType(TagDecl *tag_decl) { +TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - - if (log) { - LLDB_LOGF(log, - " CompleteTagDecl[%u] on (ASTContext*)%p Completing " - "(TagDecl*)%p named %s", - current_id, static_cast<void *>(m_ast_context), - static_cast<void *>(tag_decl), tag_decl->getName().str().c_str()); - - LLDB_LOG(log, " CTD[%u] Before:\n{0}", current_id, - ClangUtil::DumpDecl(tag_decl)); - } - - auto iter = m_active_lexical_decls.find(tag_decl); - if (iter != m_active_lexical_decls.end()) - return; - m_active_lexical_decls.insert(tag_decl); - ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl); + if (const NamespaceDecl *namespace_context = + dyn_cast<NamespaceDecl>(decl->getDeclContext())) { + ClangASTImporter::NamespaceMapSP namespace_map = + m_ast_importer_sp->GetNamespaceMap(namespace_context); - if (!m_ast_importer_sp) { - return; - } + LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)", + namespace_map.get(), namespace_map->size()); - if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) { - // We couldn't complete the type. Maybe there's a definition somewhere - // else that can be completed. - - LLDB_LOGF(log, - " CTD[%u] Type could not be completed in the module in " - "which it was first found.", - current_id); + if (!namespace_map) + return nullptr; - bool found = false; + for (const ClangASTImporter::NamespaceMapItem &item : *namespace_map) { + LLDB_LOG(log, " CTD Searching namespace {0} in module {1}", + item.second.GetName(), item.first->GetFileSpec().GetFilename()); - DeclContext *decl_ctx = tag_decl->getDeclContext(); + TypeList types; - if (const NamespaceDecl *namespace_context = - dyn_cast<NamespaceDecl>(decl_ctx)) { - ClangASTImporter::NamespaceMapSP namespace_map = - m_ast_importer_sp->GetNamespaceMap(namespace_context); + ConstString name(decl->getName()); - if (log && log->GetVerbose()) - LLDB_LOGF(log, " CTD[%u] Inspecting namespace map %p (%d entries)", - current_id, static_cast<void *>(namespace_map.get()), - static_cast<int>(namespace_map->size())); + item.first->FindTypesInNamespace(name, item.second, UINT32_MAX, types); - if (!namespace_map) - return; + for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) { + lldb::TypeSP type = types.GetTypeAtIndex(ti); - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), - e = namespace_map->end(); - i != e && !found; ++i) { - LLDB_LOGF(log, " CTD[%u] Searching namespace %s in module %s", - current_id, i->second.GetName().AsCString(), - i->first->GetFileSpec().GetFilename().GetCString()); + if (!type) + continue; - TypeList types; + CompilerType clang_type(type->GetFullCompilerType()); - ConstString name(tag_decl->getName().str().c_str()); + if (!ClangUtil::IsClangType(clang_type)) + continue; - i->first->FindTypesInNamespace(name, &i->second, UINT32_MAX, types); + const TagType *tag_type = + ClangUtil::GetQualType(clang_type)->getAs<TagType>(); - for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { - lldb::TypeSP type = types.GetTypeAtIndex(ti); + if (!tag_type) + continue; - if (!type) - continue; + TagDecl *candidate_tag_decl = + const_cast<TagDecl *>(tag_type->getDecl()); - CompilerType clang_type(type->GetFullCompilerType()); + if (TypeSystemClang::GetCompleteDecl( + &candidate_tag_decl->getASTContext(), candidate_tag_decl)) + return candidate_tag_decl; + } + } + } else { + TypeList types; - if (!ClangUtil::IsClangType(clang_type)) - continue; + ConstString name(decl->getName()); - const TagType *tag_type = - ClangUtil::GetQualType(clang_type)->getAs<TagType>(); + const ModuleList &module_list = m_target->GetImages(); - if (!tag_type) - continue; + bool exact_match = false; + llvm::DenseSet<SymbolFile *> searched_symbol_files; + module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, + searched_symbol_files, types); - TagDecl *candidate_tag_decl = - const_cast<TagDecl *>(tag_type->getDecl()); + for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) { + lldb::TypeSP type = types.GetTypeAtIndex(ti); - if (m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, - candidate_tag_decl)) - found = true; - } - } - } else { - TypeList types; + if (!type) + continue; - ConstString name(tag_decl->getName().str().c_str()); + CompilerType clang_type(type->GetFullCompilerType()); - const ModuleList &module_list = m_target->GetImages(); + if (!ClangUtil::IsClangType(clang_type)) + continue; - bool exact_match = false; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, - searched_symbol_files, types); + const TagType *tag_type = + ClangUtil::GetQualType(clang_type)->getAs<TagType>(); - for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { - lldb::TypeSP type = types.GetTypeAtIndex(ti); + if (!tag_type) + continue; - if (!type) - continue; + TagDecl *candidate_tag_decl = const_cast<TagDecl *>(tag_type->getDecl()); - CompilerType clang_type(type->GetFullCompilerType()); + // 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 (!ClangUtil::IsClangType(clang_type)) - continue; + if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(), + candidate_tag_decl)) + return candidate_tag_decl; + } + } + return nullptr; +} - const TagType *tag_type = - ClangUtil::GetQualType(clang_type)->getAs<TagType>(); +void ClangASTSource::CompleteType(TagDecl *tag_decl) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (!tag_type) - continue; + if (log) { + LLDB_LOG(log, + " CompleteTagDecl on (ASTContext*){0} Completing " + "(TagDecl*){1} named {2}", + m_clang_ast_context->getDisplayName(), tag_decl, + tag_decl->getName()); - TagDecl *candidate_tag_decl = - const_cast<TagDecl *>(tag_type->getDecl()); + LLDB_LOG(log, " CTD Before:\n{0}", ClangUtil::DumpDecl(tag_decl)); + } - // 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 (!ClangASTContext::DeclsAreEquivalent(tag_decl, candidate_tag_decl)) - continue; + auto iter = m_active_lexical_decls.find(tag_decl); + if (iter != m_active_lexical_decls.end()) + return; + m_active_lexical_decls.insert(tag_decl); + ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl); - if (m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, - candidate_tag_decl)) - found = true; - } - } + if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) { + // We couldn't complete the type. Maybe there's a definition somewhere + // else that can be completed. + if (TagDecl *alternate = FindCompleteType(tag_decl)) + m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, alternate); } LLDB_LOG(log, " [CTD] After:\n{0}", ClangUtil::DumpDecl(tag_decl)); @@ -335,19 +307,14 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - LLDB_LOGF(log, - " [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing " - "an ObjCInterfaceDecl named %s", - static_cast<void *>(m_ast_context), - interface_decl->getName().str().c_str()); + LLDB_LOG(log, + " [CompleteObjCInterfaceDecl] on (ASTContext*){0} '{1}' " + "Completing an ObjCInterfaceDecl named {1}", + m_ast_context, m_clang_ast_context->getDisplayName(), + interface_decl->getName()); LLDB_LOG(log, " [COID] Before:\n{0}", ClangUtil::DumpDecl(interface_decl)); - if (!m_ast_importer_sp) { - lldbassert(0 && "No mechanism for completing a type!"); - return; - } - ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(interface_decl); if (original.Valid()) { @@ -368,10 +335,8 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { interface_decl->getSuperClass() != interface_decl) CompleteType(interface_decl->getSuperClass()); - if (log) { - LLDB_LOGF(log, " [COID] After:"); - LLDB_LOG(log, " [COID] {0}", ClangUtil::DumpDecl(interface_decl)); - } + LLDB_LOG(log, " [COID] After:"); + LLDB_LOG(log, " [COID] {0}", ClangUtil::DumpDecl(interface_decl)); } clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface( @@ -420,9 +385,6 @@ void ClangASTSource::FindExternalLexicalDecls( llvm::function_ref<bool(Decl::Kind)> predicate, llvm::SmallVectorImpl<Decl *> &decls) { - if (!m_ast_importer_sp) - return; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); const Decl *context_decl = dyn_cast<Decl>(decl_context); @@ -436,29 +398,27 @@ void ClangASTSource::FindExternalLexicalDecls( m_active_lexical_decls.insert(context_decl); ScopedLexicalDeclEraser eraser(m_active_lexical_decls, context_decl); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - if (log) { if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl)) - LLDB_LOGF( - log, - "FindExternalLexicalDecls[%u] on (ASTContext*)%p in '%s' (%sDecl*)%p", - current_id, static_cast<void *>(m_ast_context), - context_named_decl->getNameAsString().c_str(), - context_decl->getDeclKindName(), - static_cast<const void *>(context_decl)); + LLDB_LOG(log, + "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in " + "'{2}' (%sDecl*){3}", + m_ast_context, m_clang_ast_context->getDisplayName(), + context_named_decl->getNameAsString().c_str(), + context_decl->getDeclKindName(), + static_cast<const void *>(context_decl)); else if (context_decl) - LLDB_LOGF( - log, "FindExternalLexicalDecls[%u] on (ASTContext*)%p in (%sDecl*)%p", - current_id, static_cast<void *>(m_ast_context), - context_decl->getDeclKindName(), - static_cast<const void *>(context_decl)); + LLDB_LOG(log, + "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in " + "({2}Decl*){3}", + m_ast_context, m_clang_ast_context->getDisplayName(), + context_decl->getDeclKindName(), + static_cast<const void *>(context_decl)); else - LLDB_LOGF( - log, - "FindExternalLexicalDecls[%u] on (ASTContext*)%p in a NULL context", - current_id, static_cast<const void *>(m_ast_context)); + LLDB_LOG(log, + "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in a " + "NULL context", + m_ast_context, m_clang_ast_context->getDisplayName()); } ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(context_decl); @@ -466,10 +426,10 @@ void ClangASTSource::FindExternalLexicalDecls( if (!original.Valid()) return; - LLDB_LOG( - log, " FELD[{0}] Original decl (ASTContext*){1:x} (Decl*){2:x}:\n{3}", - current_id, static_cast<void *>(original.ctx), - static_cast<void *>(original.decl), ClangUtil::DumpDecl(original.decl)); + LLDB_LOG(log, " FELD Original decl {0} (Decl*){1:x}:\n{2}", + static_cast<void *>(original.ctx), + static_cast<void *>(original.decl), + ClangUtil::DumpDecl(original.decl)); if (ObjCInterfaceDecl *original_iface_decl = dyn_cast<ObjCInterfaceDecl>(original.decl)) { @@ -499,10 +459,7 @@ void ClangASTSource::FindExternalLexicalDecls( // Indicates whether we skipped any Decls of the original DeclContext. bool SkippedDecls = false; - for (TagDecl::decl_iterator iter = original_decl_context->decls_begin(); - iter != original_decl_context->decls_end(); ++iter) { - Decl *decl = *iter; - + for (Decl *decl : original_decl_context->decls()) { // The predicate function returns true if the passed declaration kind is // the one we are looking for. // See clang::ExternalASTSource::FindExternalLexicalDecls() @@ -511,13 +468,13 @@ void ClangASTSource::FindExternalLexicalDecls( std::string ast_dump = ClangUtil::DumpDecl(decl); if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl)) - LLDB_LOGF(log, " FELD[%d] Adding [to %sDecl %s] lexical %sDecl %s", - current_id, context_named_decl->getDeclKindName(), - context_named_decl->getNameAsString().c_str(), - decl->getDeclKindName(), ast_dump.c_str()); + LLDB_LOG(log, " FELD Adding [to {0}Decl {1}] lexical {2}Decl {3}", + context_named_decl->getDeclKindName(), + context_named_decl->getName(), decl->getDeclKindName(), + ast_dump); else - LLDB_LOGF(log, " FELD[%d] Adding lexical %sDecl %s", current_id, - decl->getDeclKindName(), ast_dump.c_str()); + LLDB_LOG(log, " FELD Adding lexical {0}Decl {1}", + decl->getDeclKindName(), ast_dump); } Decl *copied_decl = CopyDecl(decl); @@ -556,56 +513,29 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - if (log) { if (!context.m_decl_context) - LLDB_LOGF(log, - "ClangASTSource::FindExternalVisibleDecls[%u] on " - "(ASTContext*)%p for '%s' in a NULL DeclContext", - current_id, static_cast<void *>(m_ast_context), - name.GetCString()); + LLDB_LOG(log, + "ClangASTSource::FindExternalVisibleDecls on " + "(ASTContext*){0} '{1}' for '{2}' in a NULL DeclContext", + m_ast_context, m_clang_ast_context->getDisplayName(), name); else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context)) - LLDB_LOGF(log, - "ClangASTSource::FindExternalVisibleDecls[%u] on " - "(ASTContext*)%p for '%s' in '%s'", - current_id, static_cast<void *>(m_ast_context), - name.GetCString(), - context_named_decl->getNameAsString().c_str()); + LLDB_LOG(log, + "ClangASTSource::FindExternalVisibleDecls on " + "(ASTContext*){0} '{1}' for '{2}' in '{3}'", + m_ast_context, m_clang_ast_context->getDisplayName(), name, + context_named_decl->getName()); else - LLDB_LOGF(log, - "ClangASTSource::FindExternalVisibleDecls[%u] on " - "(ASTContext*)%p for '%s' in a '%s'", - current_id, static_cast<void *>(m_ast_context), - name.GetCString(), context.m_decl_context->getDeclKindName()); + LLDB_LOG(log, + "ClangASTSource::FindExternalVisibleDecls on " + "(ASTContext*){0} '{1}' for '{2}' in a '{3}'", + m_ast_context, m_clang_ast_context->getDisplayName(), name, + context.m_decl_context->getDeclKindName()); } - context.m_namespace_map = std::make_shared<ClangASTImporter::NamespaceMap>(); - - if (const NamespaceDecl *namespace_context = - dyn_cast<NamespaceDecl>(context.m_decl_context)) { - ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp ? - m_ast_importer_sp->GetNamespaceMap(namespace_context) : nullptr; - - if (log && log->GetVerbose()) - LLDB_LOGF(log, " CAS::FEVD[%u] Inspecting namespace map %p (%d entries)", - current_id, static_cast<void *>(namespace_map.get()), - static_cast<int>(namespace_map->size())); - - if (!namespace_map) - return; - - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), - e = namespace_map->end(); - i != e; ++i) { - LLDB_LOGF(log, " CAS::FEVD[%u] Searching namespace %s in module %s", - current_id, i->second.GetName().AsCString(), - i->first->GetFileSpec().GetFilename().GetCString()); - - FindExternalVisibleDecls(context, i->first, i->second, current_id); - } + if (isa<NamespaceDecl>(context.m_decl_context)) { + LookupInNamespace(context); } else if (isa<ObjCInterfaceDecl>(context.m_decl_context)) { FindObjCPropertyAndIvarDecls(context); } else if (!isa<TranslationUnitDecl>(context.m_decl_context)) { @@ -614,18 +544,15 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { } else { CompilerDeclContext namespace_decl; - LLDB_LOGF(log, " CAS::FEVD[%u] Searching the root namespace", current_id); + LLDB_LOG(log, " CAS::FEVD Searching the root namespace"); - FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl, - current_id); + FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl); } if (!context.m_namespace_map->empty()) { if (log && log->GetVerbose()) - LLDB_LOGF(log, - " CAS::FEVD[%u] Registering namespace map %p (%d entries)", - current_id, static_cast<void *>(context.m_namespace_map.get()), - static_cast<int>(context.m_namespace_map->size())); + LLDB_LOG(log, " CAS::FEVD Registering namespace map {0} ({1} entries)", + context.m_namespace_map.get(), context.m_namespace_map->size()); NamespaceDecl *clang_namespace_decl = AddNamespace(context, context.m_namespace_map); @@ -658,7 +585,7 @@ bool ClangASTSource::IgnoreName(const ConstString name, void ClangASTSource::FindExternalVisibleDecls( NameSearchContext &context, lldb::ModuleSP module_sp, - CompilerDeclContext &namespace_decl, unsigned int current_id) { + CompilerDeclContext &namespace_decl) { assert(m_ast_context); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -672,196 +599,113 @@ void ClangASTSource::FindExternalVisibleDecls( if (!m_target) return; - if (module_sp && namespace_decl) { - CompilerDeclContext found_namespace_decl; - - if (SymbolFile *symbol_file = module_sp->GetSymbolFile()) { - found_namespace_decl = symbol_file->FindNamespace(name, &namespace_decl); + FillNamespaceMap(context, module_sp, namespace_decl); - if (found_namespace_decl) { - context.m_namespace_map->push_back( - std::pair<lldb::ModuleSP, CompilerDeclContext>( - module_sp, found_namespace_decl)); - - LLDB_LOGF(log, " CAS::FEVD[%u] Found namespace %s in module %s", - current_id, name.GetCString(), - module_sp->GetFileSpec().GetFilename().GetCString()); - } - } - } else { - const ModuleList &target_images = m_target->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); + if (context.m_found_type) + return; - for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { - lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); + 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); + } - if (!image) - continue; + if (size_t num_types = types.GetSize()) { + for (size_t ti = 0; ti < num_types; ++ti) { + lldb::TypeSP type_sp = types.GetTypeAtIndex(ti); - CompilerDeclContext found_namespace_decl; + if (log) { + const char *name_string = type_sp->GetName().GetCString(); - SymbolFile *symbol_file = image->GetSymbolFile(); + LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name, + (name_string ? name_string : "<anonymous>")); + } - if (!symbol_file) - continue; + CompilerType full_type = type_sp->GetFullCompilerType(); - found_namespace_decl = symbol_file->FindNamespace(name, &namespace_decl); + CompilerType copied_clang_type(GuardedCopyType(full_type)); - if (found_namespace_decl) { - context.m_namespace_map->push_back( - std::pair<lldb::ModuleSP, CompilerDeclContext>( - image, found_namespace_decl)); + if (!copied_clang_type) { + LLDB_LOG(log, " CAS::FEVD - Couldn't export a type"); - LLDB_LOGF(log, " CAS::FEVD[%u] Found namespace %s in module %s", - current_id, name.GetCString(), - image->GetFileSpec().GetFilename().GetCString()); + continue; } - } - } - do { - if (context.m_found.type) - break; + context.AddTypeDecl(copied_clang_type); - 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); + context.m_found_type = true; + break; } + } - 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(); + if (!context.m_found_type) { + // Try the modules next. + FindDeclInModules(context, name); + } - LLDB_LOGF(log, " CAS::FEVD[%u] Matching type found for \"%s\": %s", - current_id, name.GetCString(), - (name_string ? name_string : "<anonymous>")); - } + if (!context.m_found_type) { + FindDeclInObjCRuntime(context, name); + } +} - CompilerType full_type = type_sp->GetFullCompilerType(); +void ClangASTSource::FillNamespaceMap( + NameSearchContext &context, lldb::ModuleSP module_sp, + const CompilerDeclContext &namespace_decl) { + const ConstString name(context.m_decl_name.getAsString().c_str()); + if (IgnoreName(name, true)) + return; - CompilerType copied_clang_type(GuardedCopyType(full_type)); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (!copied_clang_type) { - LLDB_LOGF(log, " CAS::FEVD[%u] - Couldn't export a type", - current_id); + if (module_sp && namespace_decl) { + CompilerDeclContext found_namespace_decl; - continue; - } + if (SymbolFile *symbol_file = module_sp->GetSymbolFile()) { + found_namespace_decl = symbol_file->FindNamespace(name, namespace_decl); - context.AddTypeDecl(copied_clang_type); + if (found_namespace_decl) { + context.m_namespace_map->push_back( + std::pair<lldb::ModuleSP, CompilerDeclContext>( + module_sp, found_namespace_decl)); - context.m_found.type = true; - break; + LLDB_LOG(log, " CAS::FEVD Found namespace {0} in module {1}", name, + module_sp->GetFileSpec().GetFilename()); } } + return; + } - if (!context.m_found.type) { - // Try the modules next. - - do { - if (ClangModulesDeclVendor *modules_decl_vendor = - m_target->GetClangModulesDeclVendor()) { - bool append = false; - uint32_t max_matches = 1; - std::vector<clang::NamedDecl *> decls; - - if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls)) - break; - - if (log) { - LLDB_LOGF(log, - " CAS::FEVD[%u] Matching entity found for \"%s\" in " - "the modules", - current_id, name.GetCString()); - } - - clang::NamedDecl *const decl_from_modules = decls[0]; - - if (llvm::isa<clang::TypeDecl>(decl_from_modules) || - llvm::isa<clang::ObjCContainerDecl>(decl_from_modules) || - llvm::isa<clang::EnumConstantDecl>(decl_from_modules)) { - clang::Decl *copied_decl = CopyDecl(decl_from_modules); - clang::NamedDecl *copied_named_decl = - copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; - - if (!copied_named_decl) { - LLDB_LOGF( - log, - " CAS::FEVD[%u] - Couldn't export a type from the modules", - current_id); - - break; - } - - context.AddNamedDecl(copied_named_decl); - - context.m_found.type = true; - } - } - } while (false); - } - - if (!context.m_found.type) { - do { - // Couldn't find any types elsewhere. Try the Objective-C runtime if - // one exists. - - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - break; - - ObjCLanguageRuntime *language_runtime( - ObjCLanguageRuntime::Get(*process)); - - if (!language_runtime) - break; - - DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); + const ModuleList &target_images = m_target->GetImages(); + std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); - if (!decl_vendor) - break; + for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { + lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); - bool append = false; - uint32_t max_matches = 1; - std::vector<clang::NamedDecl *> decls; + if (!image) + continue; - auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor); - if (!clang_decl_vendor->FindDecls(name, append, max_matches, decls)) - break; + CompilerDeclContext found_namespace_decl; - if (log) { - LLDB_LOGF( - log, - " CAS::FEVD[%u] Matching type found for \"%s\" in the runtime", - current_id, name.GetCString()); - } + SymbolFile *symbol_file = image->GetSymbolFile(); - clang::Decl *copied_decl = CopyDecl(decls[0]); - clang::NamedDecl *copied_named_decl = - copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; + if (!symbol_file) + continue; - if (!copied_named_decl) { - LLDB_LOGF(log, - " CAS::FEVD[%u] - Couldn't export a type from the runtime", - current_id); + found_namespace_decl = symbol_file->FindNamespace(name, namespace_decl); - break; - } + if (found_namespace_decl) { + context.m_namespace_map->push_back( + std::pair<lldb::ModuleSP, CompilerDeclContext>(image, + found_namespace_decl)); - context.AddNamedDecl(copied_named_decl); - } while (false); + LLDB_LOG(log, " CAS::FEVD Found namespace {0} in module {1}", name, + image->GetFileSpec().GetFilename()); } - - } while (false); + } } template <class D> class TaggedASTDecl { @@ -915,8 +759,8 @@ DeclFromParser<D> DeclFromUser<D>::Import(ClangASTSource &source) { } bool ClangASTSource::FindObjCMethodDeclsWithOrigin( - unsigned int current_id, NameSearchContext &context, - ObjCInterfaceDecl *original_interface_decl, const char *log_info) { + NameSearchContext &context, ObjCInterfaceDecl *original_interface_decl, + const char *log_info) { const DeclarationName &decl_name(context.m_decl_name); clang::ASTContext *original_ctx = &original_interface_decl->getASTContext(); @@ -951,7 +795,7 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( llvm::SmallVector<NamedDecl *, 1> methods; - ClangASTContext::GetCompleteDecl(original_ctx, original_interface_decl); + TypeSystemClang::GetCompleteDecl(original_ctx, original_interface_decl); if (ObjCMethodDecl *instance_method_decl = original_interface_decl->lookupInstanceMethod(original_selector)) { @@ -987,7 +831,7 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - LLDB_LOG(log, " CAS::FOMD[{0}] found ({1}) {2}", current_id, log_info, + LLDB_LOG(log, " CAS::FOMD found ({0}) {1}", log_info, ClangUtil::DumpDecl(copied_method_decl)); context.AddNamedDecl(copied_method_decl); @@ -996,11 +840,91 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( return true; } -void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { +void ClangASTSource::FindDeclInModules(NameSearchContext &context, + ConstString name) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; + ClangModulesDeclVendor *modules_decl_vendor = + m_target->GetClangModulesDeclVendor(); + if (!modules_decl_vendor) + return; + + bool append = false; + uint32_t max_matches = 1; + std::vector<clang::NamedDecl *> decls; + + if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls)) + return; + + LLDB_LOG(log, " CAS::FEVD Matching entity found for \"{0}\" in the modules", + name); + + clang::NamedDecl *const decl_from_modules = decls[0]; + + if (llvm::isa<clang::TypeDecl>(decl_from_modules) || + llvm::isa<clang::ObjCContainerDecl>(decl_from_modules) || + llvm::isa<clang::EnumConstantDecl>(decl_from_modules)) { + clang::Decl *copied_decl = CopyDecl(decl_from_modules); + clang::NamedDecl *copied_named_decl = + copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; + + if (!copied_named_decl) { + LLDB_LOG(log, " CAS::FEVD - Couldn't export a type from the modules"); + + return; + } + + context.AddNamedDecl(copied_named_decl); + + context.m_found_type = true; + } +} + +void ClangASTSource::FindDeclInObjCRuntime(NameSearchContext &context, + ConstString name) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + lldb::ProcessSP process(m_target->GetProcessSP()); + + if (!process) + return; + + ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); + + if (!language_runtime) + return; + + DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); + + if (!decl_vendor) + return; + + bool append = false; + uint32_t max_matches = 1; + std::vector<clang::NamedDecl *> decls; + + auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor); + if (!clang_decl_vendor->FindDecls(name, append, max_matches, decls)) + return; + + LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\" in the runtime", + name); + + clang::Decl *copied_decl = CopyDecl(decls[0]); + clang::NamedDecl *copied_named_decl = + copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; + + if (!copied_named_decl) { + LLDB_LOG(log, " CAS::FEVD - Couldn't export a type from the runtime"); + + return; + } + + context.AddNamedDecl(copied_named_decl); +} + +void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); const DeclarationName &decl_name(context.m_decl_name); const DeclContext *decl_ctx(context.m_decl_context); @@ -1020,8 +944,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { ObjCInterfaceDecl *original_interface_decl = dyn_cast<ObjCInterfaceDecl>(original.decl); - if (FindObjCMethodDeclsWithOrigin(current_id, context, - original_interface_decl, "at origin")) + if (FindObjCMethodDeclsWithOrigin(context, original_interface_decl, + "at origin")) return; // found it, no need to look any further } while (false); @@ -1046,12 +970,11 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { ConstString selector_name(ss.GetString()); - LLDB_LOGF(log, - "ClangASTSource::FindObjCMethodDecls[%d] on (ASTContext*)%p " - "for selector [%s %s]", - current_id, static_cast<void *>(m_ast_context), - interface_decl->getNameAsString().c_str(), - selector_name.AsCString()); + LLDB_LOG(log, + "ClangASTSource::FindObjCMethodDecls on (ASTContext*){0} '{1}' " + "for selector [{2} {3}]", + m_ast_context, m_clang_ast_context->getDisplayName(), + interface_decl->getName(), selector_name); SymbolContextList sc_list; const bool include_symbols = false; @@ -1148,7 +1071,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { continue; ObjCMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsObjCMethodDecl(function_decl_ctx); + TypeSystemClang::DeclContextGetAsObjCMethodDecl(function_decl_ctx); if (!method_decl) continue; @@ -1171,7 +1094,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (!copied_method_decl) continue; - LLDB_LOG(log, " CAS::FOMD[{0}] found (in symbols)\n{1}", current_id, + LLDB_LOG(log, " CAS::FOMD found (in symbols)\n{0}", ClangUtil::DumpDecl(copied_method_decl)); context.AddNamedDecl(copied_method_decl); @@ -1199,13 +1122,12 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (complete_interface_decl == interface_decl) break; // already checked this one - LLDB_LOGF(log, - "CAS::FOPD[%d] trying origin " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, static_cast<void *>(complete_interface_decl), - static_cast<void *>(&complete_iface_decl->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD trying origin " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + complete_interface_decl, &complete_iface_decl->getASTContext()); - FindObjCMethodDeclsWithOrigin(current_id, context, complete_interface_decl, + FindObjCMethodDeclsWithOrigin(context, complete_interface_decl, "in debug info"); return; @@ -1232,8 +1154,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (!interface_decl_from_modules) break; - if (FindObjCMethodDeclsWithOrigin( - current_id, context, interface_decl_from_modules, "in modules")) + if (FindObjCMethodDeclsWithOrigin(context, interface_decl_from_modules, + "in modules")) return; } } while (false); @@ -1273,13 +1195,13 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (!runtime_interface_decl) break; - FindObjCMethodDeclsWithOrigin(current_id, context, runtime_interface_decl, + FindObjCMethodDeclsWithOrigin(context, runtime_interface_decl, "in runtime"); } while (false); } static bool FindObjCPropertyAndIvarDeclsWithOrigin( - unsigned int current_id, NameSearchContext &context, ClangASTSource &source, + NameSearchContext &context, ClangASTSource &source, DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1301,7 +1223,7 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( DeclFromParser<ObjCPropertyDecl> parser_property_decl( origin_property_decl.Import(source)); if (parser_property_decl.IsValid()) { - LLDB_LOG(log, " CAS::FOPD[{0}] found\n{1}", current_id, + LLDB_LOG(log, " CAS::FOPD found\n{0}", ClangUtil::DumpDecl(parser_property_decl.decl)); context.AddNamedDecl(parser_property_decl.decl); @@ -1316,10 +1238,8 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( DeclFromParser<ObjCIvarDecl> parser_ivar_decl( origin_ivar_decl.Import(source)); if (parser_ivar_decl.IsValid()) { - if (log) { - LLDB_LOG(log, " CAS::FOPD[{0}] found\n{1}", current_id, - ClangUtil::DumpDecl(parser_ivar_decl.decl)); - } + LLDB_LOG(log, " CAS::FOPD found\n{0}", + ClangUtil::DumpDecl(parser_ivar_decl.decl)); context.AddNamedDecl(parser_ivar_decl.decl); found = true; @@ -1332,9 +1252,6 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl( cast<ObjCInterfaceDecl>(context.m_decl_context)); DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl( @@ -1342,23 +1259,20 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { ConstString class_name(parser_iface_decl->getNameAsString().c_str()); - LLDB_LOGF(log, - "ClangASTSource::FindObjCPropertyAndIvarDecls[%d] on " - "(ASTContext*)%p for '%s.%s'", - current_id, static_cast<void *>(m_ast_context), - parser_iface_decl->getNameAsString().c_str(), - context.m_decl_name.getAsString().c_str()); + LLDB_LOG(log, + "ClangASTSource::FindObjCPropertyAndIvarDecls on " + "(ASTContext*){0} '{1}' for '{2}.{3}'", + m_ast_context, m_clang_ast_context->getDisplayName(), + parser_iface_decl->getName(), context.m_decl_name.getAsString()); - if (FindObjCPropertyAndIvarDeclsWithOrigin( - current_id, context, *this, origin_iface_decl)) + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, origin_iface_decl)) return; - LLDB_LOGF(log, - "CAS::FOPD[%d] couldn't find the property on origin " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p, searching " - "elsewhere...", - current_id, static_cast<const void *>(origin_iface_decl.decl), - static_cast<void *>(&origin_iface_decl->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD couldn't find the property on origin " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}, searching " + "elsewhere...", + origin_iface_decl.decl, &origin_iface_decl->getASTContext()); SymbolContext null_sc; TypeList type_list; @@ -1379,14 +1293,12 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (complete_iface_decl.decl == origin_iface_decl.decl) break; // already checked this one - LLDB_LOGF(log, - "CAS::FOPD[%d] trying origin " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, static_cast<const void *>(complete_iface_decl.decl), - static_cast<void *>(&complete_iface_decl->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD trying origin " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + complete_iface_decl.decl, &complete_iface_decl->getASTContext()); - FindObjCPropertyAndIvarDeclsWithOrigin(current_id, context, *this, - complete_iface_decl); + FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, complete_iface_decl); return; } while (false); @@ -1414,14 +1326,13 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (!interface_decl_from_modules.IsValid()) break; - LLDB_LOGF( - log, - "CAS::FOPD[%d] trying module " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, static_cast<const void *>(interface_decl_from_modules.decl), - static_cast<void *>(&interface_decl_from_modules->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD[{0}] trying module " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + interface_decl_from_modules.decl, + &interface_decl_from_modules->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, context, *this, + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, interface_decl_from_modules)) return; } while (false); @@ -1459,19 +1370,43 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (!interface_decl_from_runtime.IsValid()) break; - LLDB_LOGF( - log, - "CAS::FOPD[%d] trying runtime " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, static_cast<const void *>(interface_decl_from_runtime.decl), - static_cast<void *>(&interface_decl_from_runtime->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD[{0}] trying runtime " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + interface_decl_from_runtime.decl, + &interface_decl_from_runtime->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin( - current_id, context, *this, interface_decl_from_runtime)) + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, + interface_decl_from_runtime)) return; } while (false); } +void ClangASTSource::LookupInNamespace(NameSearchContext &context) { + const NamespaceDecl *namespace_context = + dyn_cast<NamespaceDecl>(context.m_decl_context); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + ClangASTImporter::NamespaceMapSP namespace_map = + m_ast_importer_sp->GetNamespaceMap(namespace_context); + + LLDB_LOGV(log, " CAS::FEVD Inspecting namespace map {0} ({1} entries)", + namespace_map.get(), namespace_map->size()); + + if (!namespace_map) + return; + + for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), + e = namespace_map->end(); + i != e; ++i) { + LLDB_LOG(log, " CAS::FEVD Searching namespace {0} in module {1}", + i->second.GetName(), i->first->GetFileSpec().GetFilename()); + + FindExternalVisibleDecls(context, i->first, i->second); + } +} + typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap; typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetMap; @@ -1557,17 +1492,14 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, FieldOffsetMap &field_offsets, BaseOffsetMap &base_offsets, BaseOffsetMap &virtual_base_offsets) { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - LLDB_LOGF(log, - "LayoutRecordType[%u] on (ASTContext*)%p for (RecordDecl*)%p " - "[name = '%s']", - current_id, static_cast<void *>(m_ast_context), - static_cast<const void *>(record), - record->getNameAsString().c_str()); + LLDB_LOG(log, + "LayoutRecordType on (ASTContext*){0} '{1}' for (RecordDecl*)" + "{3} [name = '{4}']", + m_ast_context, m_clang_ast_context->getDisplayName(), record, + record->getName()); DeclFromParser<const RecordDecl> parser_record(record); DeclFromUser<const RecordDecl> origin_record( @@ -1580,7 +1512,7 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, BaseOffsetMap origin_base_offsets; BaseOffsetMap origin_virtual_base_offsets; - ClangASTContext::GetCompleteDecl( + TypeSystemClang::GetCompleteDecl( &origin_record->getASTContext(), const_cast<RecordDecl *>(origin_record.decl)); @@ -1631,25 +1563,23 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, m_ast_context->getCharWidth(); if (log) { - LLDB_LOGF(log, "LRT[%u] returned:", current_id); - LLDB_LOGF(log, "LRT[%u] Original = (RecordDecl*)%p", current_id, - static_cast<const void *>(origin_record.decl)); - LLDB_LOGF(log, "LRT[%u] Size = %" PRId64, current_id, size); - LLDB_LOGF(log, "LRT[%u] Alignment = %" PRId64, current_id, alignment); - LLDB_LOGF(log, "LRT[%u] Fields:", current_id); + LLDB_LOG(log, "LRT returned:"); + LLDB_LOG(log, "LRT Original = (RecordDecl*)%p", + static_cast<const void *>(origin_record.decl)); + LLDB_LOG(log, "LRT Size = %" PRId64, size); + LLDB_LOG(log, "LRT Alignment = %" PRId64, alignment); + LLDB_LOG(log, "LRT Fields:"); for (RecordDecl::field_iterator fi = record->field_begin(), fe = record->field_end(); fi != fe; ++fi) { - LLDB_LOGF(log, - "LRT[%u] (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 - " bits", - current_id, static_cast<void *>(*fi), - fi->getNameAsString().c_str(), field_offsets[*fi]); + LLDB_LOG(log, + "LRT (FieldDecl*){0}, Name = '{1}', Offset = {2} bits", + *fi, fi->getName(), field_offsets[*fi]); } DeclFromParser<const CXXRecordDecl> parser_cxx_record = DynCast<const CXXRecordDecl>(parser_record); if (parser_cxx_record.IsValid()) { - LLDB_LOGF(log, "LRT[%u] Bases:", current_id); + LLDB_LOG(log, "LRT Bases:"); for (CXXRecordDecl::base_class_const_iterator bi = parser_cxx_record->bases_begin(), be = parser_cxx_record->bases_end(); @@ -1662,19 +1592,17 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, DeclFromParser<CXXRecordDecl> base_cxx_record = DynCast<CXXRecordDecl>(base_record); - LLDB_LOGF( - log, - "LRT[%u] %s(CXXRecordDecl*)%p, Name = '%s', Offset = %" PRId64 - " chars", - current_id, (is_virtual ? "Virtual " : ""), - static_cast<void *>(base_cxx_record.decl), - base_cxx_record.decl->getNameAsString().c_str(), - (is_virtual - ? virtual_base_offsets[base_cxx_record.decl].getQuantity() - : base_offsets[base_cxx_record.decl].getQuantity())); + LLDB_LOG(log, + "LRT {0}(CXXRecordDecl*){1}, Name = '{2}', Offset = " + "{3} chars", + (is_virtual ? "Virtual " : ""), base_cxx_record.decl, + base_cxx_record.decl->getName(), + (is_virtual + ? virtual_base_offsets[base_cxx_record.decl].getQuantity() + : base_offsets[base_cxx_record.decl].getQuantity())); } } else { - LLDB_LOGF(log, "LRD[%u] Not a CXXRecord, so no bases", current_id); + LLDB_LOG(log, "LRD Not a CXXRecord, so no bases"); } } @@ -1684,25 +1612,21 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, void ClangASTSource::CompleteNamespaceMap( ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name, ClangASTImporter::NamespaceMapSP &parent_map) const { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (log) { if (parent_map && parent_map->size()) - LLDB_LOGF(log, - "CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for " - "namespace %s in namespace %s", - current_id, static_cast<void *>(m_ast_context), - name.GetCString(), - parent_map->begin()->second.GetName().AsCString()); + LLDB_LOG(log, + "CompleteNamespaceMap on (ASTContext*){0} '{1}' Searching " + "for namespace {2} in namespace {3}", + m_ast_context, m_clang_ast_context->getDisplayName(), name, + parent_map->begin()->second.GetName()); else - LLDB_LOGF(log, - "CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for " - "namespace %s", - current_id, static_cast<void *>(m_ast_context), - name.GetCString()); + LLDB_LOG(log, + "CompleteNamespaceMap on (ASTContext*){0} '{1}' Searching " + "for namespace {2}", + m_ast_context, m_clang_ast_context->getDisplayName(), name); } if (parent_map) { @@ -1720,7 +1644,7 @@ void ClangASTSource::CompleteNamespaceMap( continue; found_namespace_decl = - symbol_file->FindNamespace(name, &module_parent_namespace_decl); + symbol_file->FindNamespace(name, module_parent_namespace_decl); if (!found_namespace_decl) continue; @@ -1728,9 +1652,8 @@ void ClangASTSource::CompleteNamespaceMap( namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>( module_sp, found_namespace_decl)); - LLDB_LOGF(log, " CMN[%u] Found namespace %s in module %s", current_id, - name.GetCString(), - module_sp->GetFileSpec().GetFilename().GetCString()); + LLDB_LOG(log, " CMN Found namespace {0} in module {1}", name, + module_sp->GetFileSpec().GetFilename()); } } else { const ModuleList &target_images = m_target->GetImages(); @@ -1752,7 +1675,7 @@ void ClangASTSource::CompleteNamespaceMap( continue; found_namespace_decl = - symbol_file->FindNamespace(name, &null_namespace_decl); + symbol_file->FindNamespace(name, null_namespace_decl); if (!found_namespace_decl) continue; @@ -1760,9 +1683,8 @@ void ClangASTSource::CompleteNamespaceMap( namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>( image, found_namespace_decl)); - LLDB_LOGF(log, " CMN[%u] Found namespace %s in module %s", current_id, - name.GetCString(), - image->GetFileSpec().GetFilename().GetCString()); + LLDB_LOG(log, " CMN[{0}] Found namespace {0} in module {1}", name, + image->GetFileSpec().GetFilename()); } } } @@ -1776,11 +1698,11 @@ NamespaceDecl *ClangASTSource::AddNamespace( const CompilerDeclContext &namespace_decl = namespace_decls->begin()->second; clang::ASTContext *src_ast = - ClangASTContext::DeclContextGetClangASTContext(namespace_decl); + TypeSystemClang::DeclContextGetTypeSystemClang(namespace_decl); if (!src_ast) return nullptr; clang::NamespaceDecl *src_namespace_decl = - ClangASTContext::DeclContextGetAsNamespaceDecl(namespace_decl); + TypeSystemClang::DeclContextGetAsNamespaceDecl(namespace_decl); if (!src_namespace_decl) return nullptr; @@ -1804,42 +1726,21 @@ NamespaceDecl *ClangASTSource::AddNamespace( } clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) { - if (m_ast_importer_sp) { - return m_ast_importer_sp->CopyDecl(m_ast_context, src_decl); - } else { - lldbassert(0 && "No mechanism for copying a decl!"); - return nullptr; - } + return m_ast_importer_sp->CopyDecl(m_ast_context, src_decl); } ClangASTImporter::DeclOrigin ClangASTSource::GetDeclOrigin(const clang::Decl *decl) { - if (m_ast_importer_sp) { - return m_ast_importer_sp->GetDeclOrigin(decl); - } else { - // this can happen early enough that no ExternalASTSource is installed. - return ClangASTImporter::DeclOrigin(); - } + return m_ast_importer_sp->GetDeclOrigin(decl); } CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { - ClangASTContext *src_ast = - llvm::dyn_cast_or_null<ClangASTContext>(src_type.GetTypeSystem()); + TypeSystemClang *src_ast = + llvm::dyn_cast_or_null<TypeSystemClang>(src_type.GetTypeSystem()); if (src_ast == nullptr) return CompilerType(); - SetImportInProgress(true); - - QualType copied_qual_type; - - if (m_ast_importer_sp) { - copied_qual_type = ClangUtil::GetQualType( - m_ast_importer_sp->CopyType(*m_clang_ast_context, src_type)); - } else { - lldbassert(0 && "No mechanism for copying a type!"); - return CompilerType(); - } - - SetImportInProgress(false); + QualType copied_qual_type = ClangUtil::GetQualType( + m_ast_importer_sp->CopyType(*m_clang_ast_context, src_type)); if (copied_qual_type.getAsOpaquePtr() && copied_qual_type->getCanonicalTypeInternal().isNull()) @@ -1849,170 +1750,3 @@ CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { return m_clang_ast_context->GetType(copied_qual_type); } - -clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { - assert(type && "Type for variable must be valid!"); - - if (!type.IsValid()) - return nullptr; - - ClangASTContext *lldb_ast = - llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); - if (!lldb_ast) - return nullptr; - - IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo(); - - clang::ASTContext &ast = lldb_ast->getASTContext(); - - clang::NamedDecl *Decl = VarDecl::Create( - ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), - SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static); - m_decls.push_back(Decl); - - return Decl; -} - -clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, - bool extern_c) { - assert(type && "Type for variable must be valid!"); - - if (!type.IsValid()) - return nullptr; - - if (m_function_types.count(type)) - return nullptr; - - ClangASTContext *lldb_ast = - llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); - if (!lldb_ast) - return nullptr; - - m_function_types.insert(type); - - QualType qual_type(ClangUtil::GetQualType(type)); - - clang::ASTContext &ast = lldb_ast->getASTContext(); - - const bool isInlineSpecified = false; - const bool hasWrittenPrototype = true; - const bool isConstexprSpecified = false; - - 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); - } - - // Pass the identifier info for functions the decl_name is needed for - // operators - clang::DeclarationName decl_name = - m_decl_name.getNameKind() == DeclarationName::Identifier - ? m_decl_name.getAsIdentifierInfo() - : m_decl_name; - - clang::FunctionDecl *func_decl = FunctionDecl::Create( - ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, - nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, - isConstexprSpecified ? CSK_constexpr : CSK_unspecified); - - // We have to do more than just synthesize the FunctionDecl. We have to - // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do - // this, we raid the function's FunctionProtoType for types. - - const FunctionProtoType *func_proto_type = - qual_type.getTypePtr()->getAs<FunctionProtoType>(); - - if (func_proto_type) { - unsigned NumArgs = func_proto_type->getNumParams(); - unsigned ArgIndex; - - SmallVector<ParmVarDecl *, 5> parm_var_decls; - - for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) { - QualType arg_qual_type(func_proto_type->getParamType(ArgIndex)); - - parm_var_decls.push_back( - ParmVarDecl::Create(ast, const_cast<DeclContext *>(context), - SourceLocation(), SourceLocation(), nullptr, - arg_qual_type, nullptr, SC_Static, nullptr)); - } - - func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls)); - } else { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - LLDB_LOGF(log, "Function type wasn't a FunctionProtoType"); - } - - // If this is an operator (e.g. operator new or operator==), only insert the - // declaration we inferred from the symbol if we can provide the correct - // number of arguments. We shouldn't really inject random decl(s) for - // functions that are analyzed semantically in a special way, otherwise we - // will crash in clang. - clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; - if (func_proto_type && - ClangASTContext::IsOperator(decl_name.getAsString().c_str(), op_kind)) { - if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount( - false, op_kind, func_proto_type->getNumParams())) - return nullptr; - } - m_decls.push_back(func_decl); - - return func_decl; -} - -clang::NamedDecl *NameSearchContext::AddGenericFunDecl() { - FunctionProtoType::ExtProtoInfo proto_info; - - proto_info.Variadic = true; - - QualType generic_function_type(m_ast_source.m_ast_context->getFunctionType( - m_ast_source.m_ast_context->UnknownAnyTy, // result - ArrayRef<QualType>(), // argument types - proto_info)); - - return AddFunDecl( - m_ast_source.m_clang_ast_context->GetType(generic_function_type), true); -} - -clang::NamedDecl * -NameSearchContext::AddTypeDecl(const CompilerType &clang_type) { - if (ClangUtil::IsClangType(clang_type)) { - QualType qual_type = ClangUtil::GetQualType(clang_type); - - if (const TypedefType *typedef_type = - llvm::dyn_cast<TypedefType>(qual_type)) { - TypedefNameDecl *typedef_name_decl = typedef_type->getDecl(); - - m_decls.push_back(typedef_name_decl); - - return (NamedDecl *)typedef_name_decl; - } else if (const TagType *tag_type = qual_type->getAs<TagType>()) { - TagDecl *tag_decl = tag_type->getDecl(); - - m_decls.push_back(tag_decl); - - return tag_decl; - } else if (const ObjCObjectType *objc_object_type = - qual_type->getAs<ObjCObjectType>()) { - ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface(); - - m_decls.push_back((NamedDecl *)interface_decl); - - return (NamedDecl *)interface_decl; - } - } - return nullptr; -} - -void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) { - for (clang::NamedDecl *decl : result) - m_decls.push_back(decl); -} - -void NameSearchContext::AddNamedDecl(clang::NamedDecl *decl) { - m_decls.push_back(decl); -} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index 3149b4266b2f..14761fbeb26b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -6,12 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangASTSource_h_ -#define liblldb_ClangASTSource_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H #include <set> -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/NameSearchContext.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "clang/AST/ExternalASTSource.h" @@ -42,7 +43,7 @@ public: /// \param[in] importer /// The ClangASTImporter to use. ClangASTSource(const lldb::TargetSP &target, - const lldb::ClangASTImporterSP &importer); + const std::shared_ptr<ClangASTImporter> &importer); /// Destructor ~ClangASTSource() override; @@ -60,7 +61,7 @@ public: } void MaterializeVisibleDecls(const clang::DeclContext *DC) { return; } - void InstallASTContext(ClangASTContext &ast_context); + void InstallASTContext(TypeSystemClang &ast_context); // // APIs for ExternalASTSource @@ -196,11 +197,6 @@ public: clang::Sema *getSema(); - void SetImportInProgress(bool import_in_progress) { - m_import_in_progress = import_in_progress; - } - bool GetImportInProgress() { return m_import_in_progress; } - void SetLookupsEnabled(bool lookups_enabled) { m_lookups_enabled = lookups_enabled; } @@ -282,14 +278,9 @@ protected: /// /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. void FindExternalVisibleDecls(NameSearchContext &context, lldb::ModuleSP module, - CompilerDeclContext &namespace_decl, - unsigned int current_id); + CompilerDeclContext &namespace_decl); /// Find all Objective-C methods matching a given selector. /// @@ -307,7 +298,13 @@ protected: /// is the containing object. void FindObjCPropertyAndIvarDecls(NameSearchContext &context); - /// A wrapper for ClangASTContext::CopyType that sets a flag that + /// Performs lookup into a namespace. + /// + /// \param context + /// The NameSearchContext for a lookup inside a namespace. + void LookupInNamespace(NameSearchContext &context); + + /// A wrapper for TypeSystemClang::CopyType that sets a flag that /// indicates that we should not respond to queries during import. /// /// \param[in] src_type @@ -331,7 +328,6 @@ public: /// global lookup for performance reasons. bool IgnoreName(const ConstString name, bool ignore_all_dollar_names); -public: /// Copies a single Decl into the parser's AST context. /// /// \param[in] src_decl @@ -346,139 +342,51 @@ public: /// \param[in] decl /// The Decl whose origin is to be found. /// - /// \param[out] original_decl - /// A pointer whose target is filled in with the original Decl. - /// - /// \param[in] original_ctx - /// A pointer whose target is filled in with the original's ASTContext. - /// /// \return /// True if lookup succeeded; false otherwise. ClangASTImporter::DeclOrigin GetDeclOrigin(const clang::Decl *decl); + /// Returns the TypeSystem that uses this ClangASTSource instance as it's + /// ExternalASTSource. + TypeSystemClang *GetTypeSystem() const { return m_clang_ast_context; } + protected: bool FindObjCMethodDeclsWithOrigin( - unsigned int current_id, NameSearchContext &context, + NameSearchContext &context, clang::ObjCInterfaceDecl *original_interface_decl, const char *log_info); + void FindDeclInModules(NameSearchContext &context, ConstString name); + void FindDeclInObjCRuntime(NameSearchContext &context, ConstString name); + + /// Fills the namespace map of the given NameSearchContext. + /// + /// \param context The NameSearchContext with the namespace map to fill. + /// \param module_sp The module to search for namespaces or a nullptr if + /// the current target should be searched. + /// \param namespace_decl The DeclContext in which to search for namespaces. + void FillNamespaceMap(NameSearchContext &context, lldb::ModuleSP module_sp, + const CompilerDeclContext &namespace_decl); + + clang::TagDecl *FindCompleteType(const clang::TagDecl *decl); + friend struct NameSearchContext; - bool m_import_in_progress; bool m_lookups_enabled; /// The target to use in finding variables and types. const lldb::TargetSP m_target; /// The AST context requests are coming in for. clang::ASTContext *m_ast_context; - /// The ClangASTContext for m_ast_context. - ClangASTContext *m_clang_ast_context; + /// The TypeSystemClang for m_ast_context. + TypeSystemClang *m_clang_ast_context; /// The file manager paired with the AST context. clang::FileManager *m_file_manager; /// The target's AST importer. - lldb::ClangASTImporterSP m_ast_importer_sp; + std::shared_ptr<ClangASTImporter> m_ast_importer_sp; std::set<const clang::Decl *> m_active_lexical_decls; std::set<const char *> m_active_lookups; }; -/// \class NameSearchContext ClangASTSource.h -/// "lldb/Expression/ClangASTSource.h" Container for all objects relevant to a -/// single name lookup -/// -/// LLDB needs to create Decls for entities it finds. This class communicates -/// what name is being searched for and provides helper functions to construct -/// Decls given appropriate type information. -struct NameSearchContext { - /// The AST source making the request. - ClangASTSource &m_ast_source; - /// The list of declarations already constructed. - llvm::SmallVectorImpl<clang::NamedDecl *> &m_decls; - /// The mapping of all namespaces found for this request back to their - /// modules. - ClangASTImporter::NamespaceMapSP m_namespace_map; - /// The name being looked for. - const clang::DeclarationName &m_decl_name; - /// The DeclContext to put declarations into. - const clang::DeclContext *m_decl_context; - /// All the types of functions that have been reported, so we don't - /// report conflicts. - llvm::SmallSet<CompilerType, 5> m_function_types; - - struct { - bool variable : 1; - bool function_with_type_info : 1; - bool function : 1; - bool local_vars_nsp : 1; - bool type : 1; - } m_found; - - /// Constructor - /// - /// Initializes class variables. - /// - /// \param[in] astSource - /// A reference to the AST source making a request. - /// - /// \param[in] decls - /// A reference to a list into which new Decls will be placed. This - /// list is typically empty when the function is called. - /// - /// \param[in] name - /// The name being searched for (always an Identifier). - /// - /// \param[in] dc - /// The DeclContext to register Decls in. - NameSearchContext(ClangASTSource &astSource, - llvm::SmallVectorImpl<clang::NamedDecl *> &decls, - clang::DeclarationName &name, const clang::DeclContext *dc) - : m_ast_source(astSource), m_decls(decls), m_decl_name(name), - m_decl_context(dc) { - memset(&m_found, 0, sizeof(m_found)); - } - - /// Create a VarDecl with the name being searched for and the provided type - /// and register it in the right places. - /// - /// \param[in] type - /// The opaque QualType for the VarDecl being registered. - clang::NamedDecl *AddVarDecl(const CompilerType &type); - - /// Create a FunDecl with the name being searched for and the provided type - /// and register it in the right places. - /// - /// \param[in] type - /// The opaque QualType for the FunDecl being registered. - /// - /// \param[in] extern_c - /// If true, build an extern "C" linkage specification for this. - clang::NamedDecl *AddFunDecl(const CompilerType &type, bool extern_c = false); - - /// Create a FunDecl with the name being searched for and generic type (i.e. - /// intptr_t NAME_GOES_HERE(...)) and register it in the right places. - clang::NamedDecl *AddGenericFunDecl(); - - /// Create a TypeDecl with the name being searched for and the provided type - /// and register it in the right places. - /// - /// \param[in] compiler_type - /// The opaque QualType for the TypeDecl being registered. - clang::NamedDecl *AddTypeDecl(const CompilerType &compiler_type); - - /// Add Decls from the provided DeclContextLookupResult to the list of - /// results. - /// - /// \param[in] result - /// The DeclContextLookupResult, usually returned as the result - /// of querying a DeclContext. - void AddLookupResult(clang::DeclContextLookupResult result); - - /// Add a NamedDecl to the list of results. - /// - /// \param[in] decl - /// The NamedDecl, usually returned as the result - /// of querying a DeclContext. - void AddNamedDecl(clang::NamedDecl *decl); -}; - } // namespace lldb_private -#endif // liblldb_ClangASTSource_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp index c87507a25855..867d4ff0a907 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp @@ -1,4 +1,4 @@ -//===-- ClangDeclVendor.cpp -------------------------------------*- C++ -*-===// +//===-- ClangDeclVendor.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,8 +7,9 @@ //===----------------------------------------------------------------------===// #include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Utility/ConstString.h" using namespace lldb_private; @@ -22,7 +23,7 @@ uint32_t ClangDeclVendor::FindDecls(ConstString name, bool append, std::vector<CompilerDecl> compiler_decls; uint32_t ret = FindDecls(name, /*append*/ false, max_matches, compiler_decls); for (CompilerDecl compiler_decl : compiler_decls) { - clang::Decl *d = static_cast<clang::Decl *>(compiler_decl.GetOpaqueDecl()); + clang::Decl *d = ClangUtil::GetDecl(compiler_decl); clang::NamedDecl *nd = llvm::cast<clang::NamedDecl>(d); decls.push_back(nd); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h index 0c888de08841..bf52bec4b1fa 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h @@ -6,12 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangDeclVendor_h_ -#define liblldb_ClangDeclVendor_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDECLVENDOR_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDECLVENDOR_H -#include "lldb/Core/ClangForward.h" #include "lldb/Symbol/DeclVendor.h" +namespace clang { +class NamedDecl; +} + namespace lldb_private { // A clang specialized extension to DeclVendor. @@ -32,7 +35,8 @@ public: } private: - DISALLOW_COPY_AND_ASSIGN(ClangDeclVendor); + ClangDeclVendor(const ClangDeclVendor &) = delete; + const ClangDeclVendor &operator=(const ClangDeclVendor &) = delete; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h index 48cd1c4b99fa..7459b715dbe2 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_ClangDiagnostic_h -#define lldb_ClangDiagnostic_h +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H #include <vector> @@ -47,4 +47,4 @@ private: }; } // namespace lldb_private -#endif /* lldb_ClangDiagnostic_h */ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index bf3023be5f60..8c49898e1d6c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1,4 +1,4 @@ -//===-- ClangExpressionDeclMap.cpp -----------------------------*- C++ -*-===// +//===-- ClangExpressionDeclMap.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -11,15 +11,15 @@ #include "ClangASTSource.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" +#include "ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/Materializer.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" @@ -65,8 +65,8 @@ const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars"; ClangExpressionDeclMap::ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, - const lldb::TargetSP &target, const lldb::ClangASTImporterSP &importer, - ValueObject *ctx_obj) + const lldb::TargetSP &target, + const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj) : ClangASTSource(target, importer), m_found_entities(), m_struct_members(), m_keep_result_in_memory(keep_result_in_memory), m_result_delegate(result_delegate), m_ctx_obj(ctx_obj), m_parser_vars(), @@ -109,7 +109,7 @@ bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx, m_parser_vars->m_persistent_vars = llvm::cast<ClangPersistentVariables>( target->GetPersistentExpressionStateForLanguage(eLanguageTypeC)); - if (!ClangASTContext::GetScratch(*target)) + if (!TypeSystemClang::GetScratch(*target)) return false; } @@ -174,19 +174,14 @@ ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() { return ret; } -TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target, - ClangASTContext &source, +TypeFromUser ClangExpressionDeclMap::DeportType(TypeSystemClang &target, + TypeSystemClang &source, TypeFromParser parser_type) { - assert(&target == ClangASTContext::GetScratch(*m_target)); + assert(&target == TypeSystemClang::GetScratch(*m_target)); assert((TypeSystem *)&source == parser_type.GetTypeSystem()); assert(&source.getASTContext() == m_ast_context); - if (m_ast_importer_sp) { - return TypeFromUser(m_ast_importer_sp->DeportType(target, parser_type)); - } else { - lldbassert(0 && "No mechanism for deporting a type!"); - return TypeFromUser(); - } + return TypeFromUser(m_ast_importer_sp->DeportType(target, parser_type)); } bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, @@ -196,8 +191,8 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, bool is_lvalue) { assert(m_parser_vars.get()); - ClangASTContext *ast = - llvm::dyn_cast_or_null<ClangASTContext>(parser_type.GetTypeSystem()); + TypeSystemClang *ast = + llvm::dyn_cast_or_null<TypeSystemClang>(parser_type.GetTypeSystem()); if (ast == nullptr) return false; @@ -209,7 +204,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - auto *clang_ast_context = ClangASTContext::GetScratch(*target); + auto *clang_ast_context = TypeSystemClang::GetScratch(*target); if (!clang_ast_context) return false; @@ -231,7 +226,6 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, var->GetParserVars(GetParserID()); parser_vars->m_named_decl = decl; - parser_vars->m_parser_type = parser_type; var->EnableJITVars(GetParserID()); @@ -248,14 +242,14 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - ClangASTContext *context = ClangASTContext::GetScratch(*target); + TypeSystemClang *context = TypeSystemClang::GetScratch(*target); if (!context) return false; TypeFromUser user_type = DeportType(*context, *ast, parser_type); if (!user_type.GetOpaqueQualType()) { - LLDB_LOGF(log, "Persistent variable's type wasn't copied successfully"); + LLDB_LOG(log, "Persistent variable's type wasn't copied successfully"); return false; } @@ -297,7 +291,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, var->m_flags |= ClangExpressionVariable::EVKeepInTarget; } - LLDB_LOGF(log, "Created persistent variable with flags 0x%hx", var->m_flags); + LLDB_LOG(log, "Created persistent variable with flags {0:x}", var->m_flags); var->EnableParserVars(GetParserID()); @@ -305,7 +299,6 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, var->GetParserVars(GetParserID()); parser_vars->m_named_decl = decl; - parser_vars->m_parser_type = parser_type; return true; } @@ -339,9 +332,8 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, if (!var) return false; - LLDB_LOGF(log, "Adding value for (NamedDecl*)%p [%s - %s] to the structure", - static_cast<const void *>(decl), name.GetCString(), - var->GetName().GetCString()); + LLDB_LOG(log, "Adding value for (NamedDecl*)%p [%s - %s] to the structure", + decl, name, var->GetName()); // We know entity->m_parser_vars is valid because we used a parser variable // to find it @@ -355,8 +347,7 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, llvm::cast<ClangExpressionVariable>(var)->GetJITVars(GetParserID())) { // We already laid this out; do not touch - LLDB_LOGF(log, "Already placed at 0x%llx", - (unsigned long long)jit_vars->m_offset); + LLDB_LOG(log, "Already placed at {0:x}", jit_vars->m_offset); } llvm::cast<ClangExpressionVariable>(var)->EnableJITVars(GetParserID()); @@ -391,7 +382,7 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, if (!err.Success()) return false; - LLDB_LOGF(log, "Placed at 0x%llx", (unsigned long long)offset); + LLDB_LOG(log, "Placed at {0:x}", offset); jit_vars->m_offset = offset; // TODO DoStructLayout() should not change this. @@ -600,7 +591,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(ConstString name, lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( Target &target, ModuleSP &module, ConstString name, - CompilerDeclContext *namespace_decl) { + const CompilerDeclContext &namespace_decl) { VariableList vars; if (module && namespace_decl) @@ -613,7 +604,7 @@ lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( return vars.GetVariableAtIndex(0); } -ClangASTContext *ClangExpressionDeclMap::GetClangASTContext() { +TypeSystemClang *ClangExpressionDeclMap::GetTypeSystemClang() { StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); if (frame == nullptr) return nullptr; @@ -627,7 +618,7 @@ ClangASTContext *ClangExpressionDeclMap::GetClangASTContext() { if (!frame_decl_context) return nullptr; - return llvm::dyn_cast_or_null<ClangASTContext>( + return llvm::dyn_cast_or_null<TypeSystemClang>( frame_decl_context.GetTypeSystem()); } @@ -641,34 +632,23 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (GetImportInProgress()) { - if (log && log->GetVerbose()) - LLDB_LOGF(log, "Ignoring a query during an import"); - return; - } - - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - if (log) { if (!context.m_decl_context) - LLDB_LOGF(log, - "ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " - "'%s' in a NULL DeclContext", - current_id, name.GetCString()); + LLDB_LOG(log, + "ClangExpressionDeclMap::FindExternalVisibleDecls for " + "'{0}' in a NULL DeclContext", + name); else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context)) - LLDB_LOGF(log, - "ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " - "'%s' in '%s'", - current_id, name.GetCString(), - context_named_decl->getNameAsString().c_str()); + LLDB_LOG(log, + "ClangExpressionDeclMap::FindExternalVisibleDecls for " + "'{0}' in '{1}'", + name, context_named_decl->getNameAsString()); else - LLDB_LOGF(log, - "ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " - "'%s' in a '%s'", - current_id, name.GetCString(), - context.m_decl_context->getDeclKindName()); + LLDB_LOG(log, + "ClangExpressionDeclMap::FindExternalVisibleDecls for " + "'{0}' in a '{1}'", + name, context.m_decl_context->getDeclKindName()); } if (const NamespaceDecl *namespace_context = @@ -678,42 +658,31 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( CompilerDeclContext compiler_decl_ctx = m_clang_ast_context->CreateDeclContext( const_cast<clang::DeclContext *>(context.m_decl_context)); - FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx, - current_id); + FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx); return; } ClangASTImporter::NamespaceMapSP namespace_map = - m_ast_importer_sp - ? m_ast_importer_sp->GetNamespaceMap(namespace_context) - : ClangASTImporter::NamespaceMapSP(); + m_ast_importer_sp->GetNamespaceMap(namespace_context); if (!namespace_map) return; - if (log && log->GetVerbose()) - log->Printf(" CEDM::FEVD[%u] Inspecting (NamespaceMap*)%p (%d entries)", - current_id, static_cast<void *>(namespace_map.get()), - (int)namespace_map->size()); + LLDB_LOGV(log, " CEDM::FEVD Inspecting (NamespaceMap*){0:x} ({1} entries)", + namespace_map.get(), namespace_map->size()); - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), - e = namespace_map->end(); - i != e; ++i) { - if (log) - log->Printf(" CEDM::FEVD[%u] Searching namespace %s in module %s", - current_id, i->second.GetName().AsCString(), - i->first->GetFileSpec().GetFilename().GetCString()); + for (ClangASTImporter::NamespaceMapItem &n : *namespace_map) { + LLDB_LOG(log, " CEDM::FEVD Searching namespace {0} in module {1}", + n.second.GetName(), n.first->GetFileSpec().GetFilename()); - FindExternalVisibleDecls(context, i->first, i->second, current_id); + FindExternalVisibleDecls(context, n.first, n.second); } } else if (isa<TranslationUnitDecl>(context.m_decl_context)) { CompilerDeclContext namespace_decl; - if (log) - log->Printf(" CEDM::FEVD[%u] Searching the root namespace", current_id); + LLDB_LOG(log, " CEDM::FEVD Searching the root namespace"); - FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl, - current_id); + FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl); } ClangASTSource::FindExternalVisibleDecls(context); @@ -734,7 +703,7 @@ clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) { if (!target) return nullptr; - ClangASTContext::GetScratch(*target); + TypeSystemClang::GetScratch(*target); if (!m_parser_vars->m_persistent_vars) return nullptr; @@ -742,8 +711,7 @@ clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) { } void ClangExpressionDeclMap::SearchPersistenDecls(NameSearchContext &context, - const ConstString name, - unsigned int current_id) { + const ConstString name) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); NamedDecl *persistent_decl = GetPersistentDecl(name); @@ -766,14 +734,12 @@ void ClangExpressionDeclMap::SearchPersistenDecls(NameSearchContext &context, MaybeRegisterFunctionBody(parser_function_decl); } - LLDB_LOGF(log, " CEDM::FEVD[%u] Found persistent decl %s", current_id, - name.GetCString()); + LLDB_LOG(log, " CEDM::FEVD Found persistent decl %s", name); context.AddNamedDecl(parser_named_decl); } -void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, - unsigned int current_id) { +void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); @@ -788,8 +754,7 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, if (!ctx_obj_ptr || status.Fail()) return; - AddThisType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), - current_id); + AddContextClassType(context, TypeFromUser(m_ctx_obj->GetCompilerType())); m_struct_vars->m_object_pointer_type = TypeFromUser(ctx_obj_ptr->GetCompilerType()); @@ -814,7 +779,7 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, return; clang::CXXMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsCXXMethodDecl(function_decl_ctx); + TypeSystemClang::DeclContextGetAsCXXMethodDecl(function_decl_ctx); if (method_decl) { clang::CXXRecordDecl *class_decl = method_decl->getParent(); @@ -824,10 +789,10 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, TypeFromUser class_user_type(class_qual_type.getAsOpaquePtr(), function_decl_ctx.GetTypeSystem()); - LLDB_LOG(log, " CEDM::FEVD[{0}] Adding type for $__lldb_class: {1}", - current_id, class_qual_type.getAsString()); + LLDB_LOG(log, " CEDM::FEVD Adding type for $__lldb_class: {1}", + class_qual_type.getAsString()); - AddThisType(context, class_user_type, current_id); + AddContextClassType(context, class_user_type); if (method_decl->isInstance()) { // self is a pointer to the object @@ -866,17 +831,16 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, TypeFromUser pointee_type = this_type->GetForwardCompilerType().GetPointeeType(); - LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_class: {1}", current_id, + LLDB_LOG(log, " FEVD Adding type for $__lldb_class: {1}", ClangUtil::GetQualType(pointee_type).getAsString()); - AddThisType(context, pointee_type, current_id); + AddContextClassType(context, pointee_type); TypeFromUser this_user_type(this_type->GetFullCompilerType()); m_struct_vars->m_object_pointer_type = this_user_type; } } -void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, - unsigned int current_id) { +void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); @@ -887,7 +851,7 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, if (!ctx_obj_ptr || status.Fail()) return; - AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), current_id); + AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType())); m_struct_vars->m_object_pointer_type = TypeFromUser(ctx_obj_ptr->GetCompilerType()); @@ -915,7 +879,7 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, return; clang::ObjCMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsObjCMethodDecl(function_decl_ctx); + TypeSystemClang::DeclContextGetAsObjCMethodDecl(function_decl_ctx); if (method_decl) { ObjCInterfaceDecl *self_interface = method_decl->getClassInterface(); @@ -933,9 +897,9 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, function_decl_ctx.GetTypeSystem()); LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_objc_class: {1}", - current_id, ClangUtil::ToString(interface_type)); + ClangUtil::ToString(interface_type)); - AddOneType(context, class_user_type, current_id); + AddOneType(context, class_user_type); if (method_decl->isInstanceMethod()) { // self is a pointer to the object @@ -984,10 +948,10 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, CompilerType self_clang_type = self_type->GetFullCompilerType(); - if (ClangASTContext::IsObjCClassType(self_clang_type)) { + if (TypeSystemClang::IsObjCClassType(self_clang_type)) { return; } - if (!ClangASTContext::IsObjCObjectPointerType(self_clang_type)) + if (!TypeSystemClang::IsObjCObjectPointerType(self_clang_type)) return; self_clang_type = self_clang_type.GetPointeeType(); @@ -995,11 +959,11 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, return; LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_objc_class: {1}", - current_id, ClangUtil::ToString(self_type->GetFullCompilerType())); + ClangUtil::ToString(self_type->GetFullCompilerType())); TypeFromUser class_user_type(self_clang_type); - AddOneType(context, class_user_type, current_id); + AddOneType(context, class_user_type); TypeFromUser self_user_type(self_type->GetFullCompilerType()); @@ -1015,25 +979,25 @@ void ClangExpressionDeclMap::LookupLocalVarNamespace( if (!frame_decl_context) return; - ClangASTContext *frame_ast = llvm::dyn_cast_or_null<ClangASTContext>( + TypeSystemClang *frame_ast = llvm::dyn_cast_or_null<TypeSystemClang>( frame_decl_context.GetTypeSystem()); if (!frame_ast) return; clang::NamespaceDecl *namespace_decl = m_clang_ast_context->GetUniqueNamespaceDeclaration( - g_lldb_local_vars_namespace_cstr, nullptr); + g_lldb_local_vars_namespace_cstr, nullptr, OptionalClangModuleID()); if (!namespace_decl) return; name_context.AddNamedDecl(namespace_decl); clang::DeclContext *ctxt = clang::Decl::castToDeclContext(namespace_decl); ctxt->setHasExternalVisibleStorage(true); - name_context.m_found.local_vars_nsp = true; + name_context.m_found_local_vars_nsp = true; } void ClangExpressionDeclMap::LookupInModulesDeclVendor( - NameSearchContext &context, ConstString name, unsigned current_id) { + NameSearchContext &context, ConstString name) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (!m_target) @@ -1054,16 +1018,14 @@ void ClangExpressionDeclMap::LookupInModulesDeclVendor( clang::NamedDecl *const decl_from_modules = decls[0]; LLDB_LOG(log, - " CAS::FEVD[{0}] Matching decl found for " + " CAS::FEVD Matching decl found for " "\"{1}\" in the modules", - current_id, name); + name); clang::Decl *copied_decl = CopyDecl(decl_from_modules); if (!copied_decl) { - LLDB_LOG(log, - " CAS::FEVD[{0}] - Couldn't export a " - "declaration from the modules", - current_id); + LLDB_LOG(log, " CAS::FEVD - Couldn't export a " + "declaration from the modules"); return; } @@ -1072,17 +1034,17 @@ void ClangExpressionDeclMap::LookupInModulesDeclVendor( context.AddNamedDecl(copied_function); - context.m_found.function_with_type_info = true; - context.m_found.function = true; + context.m_found_function_with_type_info = true; + context.m_found_function = true; } else if (auto copied_var = dyn_cast<clang::VarDecl>(copied_decl)) { context.AddNamedDecl(copied_var); - context.m_found.variable = true; + context.m_found_variable = true; } } bool ClangExpressionDeclMap::LookupLocalVariable( - NameSearchContext &context, ConstString name, unsigned current_id, - SymbolContext &sym_ctx, CompilerDeclContext &namespace_decl) { + NameSearchContext &context, ConstString name, SymbolContext &sym_ctx, + const CompilerDeclContext &namespace_decl) { if (sym_ctx.block == nullptr) return false; @@ -1117,8 +1079,8 @@ bool ClangExpressionDeclMap::LookupLocalVariable( if (var && !variable_found) { variable_found = true; ValueObjectSP valobj = ValueObjectVariable::Create(frame, var); - AddOneVariable(context, var, valobj, current_id); - context.m_found.variable = true; + AddOneVariable(context, var, valobj); + context.m_found_variable = true; } } return variable_found; @@ -1148,7 +1110,7 @@ SymbolContextList ClangExpressionDeclMap::SearchFunctionsInSymbolContexts( decl_infos.reserve(num_indices); clang::DeclContext *frame_decl_ctx = (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext(); - ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>( + TypeSystemClang *ast = llvm::dyn_cast_or_null<TypeSystemClang>( frame_decl_context.GetTypeSystem()); for (uint32_t index = 0; index < num_indices; ++index) { @@ -1222,11 +1184,9 @@ SymbolContextList ClangExpressionDeclMap::SearchFunctionsInSymbolContexts( return sc_func_list; } -void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, - lldb::ModuleSP module_sp, - ConstString name, - CompilerDeclContext &namespace_decl, - unsigned current_id) { +void ClangExpressionDeclMap::LookupFunction( + NameSearchContext &context, lldb::ModuleSP module_sp, ConstString name, + const CompilerDeclContext &namespace_decl) { if (!m_parser_vars) return; @@ -1246,7 +1206,7 @@ void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, if (namespace_decl && module_sp) { const bool include_symbols = false; - module_sp->FindFunctions(name, &namespace_decl, eFunctionNameTypeBase, + module_sp->FindFunctions(name, namespace_decl, eFunctionNameTypeBase, include_symbols, include_inlines, sc_list); } else if (target && !namespace_decl) { const bool include_symbols = true; @@ -1304,9 +1264,9 @@ void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr)) continue; - AddOneFunction(context, sym_ctx.function, nullptr, current_id); - context.m_found.function_with_type_info = true; - context.m_found.function = true; + AddOneFunction(context, sym_ctx.function, nullptr); + context.m_found_function_with_type_info = true; + context.m_found_function = true; } else if (sym_ctx.symbol) { if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target) { sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target); @@ -1321,26 +1281,26 @@ void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, } } - if (!context.m_found.function_with_type_info) { + if (!context.m_found_function_with_type_info) { for (clang::NamedDecl *decl : decls_from_modules) { if (llvm::isa<clang::FunctionDecl>(decl)) { clang::NamedDecl *copied_decl = llvm::cast_or_null<FunctionDecl>(CopyDecl(decl)); if (copied_decl) { context.AddNamedDecl(copied_decl); - context.m_found.function_with_type_info = true; + context.m_found_function_with_type_info = true; } } } } - if (!context.m_found.function_with_type_info) { + if (!context.m_found_function_with_type_info) { if (extern_symbol) { - AddOneFunction(context, nullptr, extern_symbol, current_id); - context.m_found.function = true; + AddOneFunction(context, nullptr, extern_symbol); + context.m_found_function = true; } else if (non_extern_symbol) { - AddOneFunction(context, nullptr, non_extern_symbol, current_id); - context.m_found.function = true; + AddOneFunction(context, nullptr, non_extern_symbol); + context.m_found_function = true; } } } @@ -1348,7 +1308,7 @@ void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, void ClangExpressionDeclMap::FindExternalVisibleDecls( NameSearchContext &context, lldb::ModuleSP module_sp, - CompilerDeclContext &namespace_decl, unsigned int current_id) { + const CompilerDeclContext &namespace_decl) { assert(m_ast_context); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1373,16 +1333,16 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( // Try the persistent decls, which take precedence over all else. if (!namespace_decl) - SearchPersistenDecls(context, name, current_id); + SearchPersistenDecls(context, name); if (name.GetStringRef().startswith("$") && !namespace_decl) { if (name == "$__lldb_class") { - LookUpLldbClass(context, current_id); + LookUpLldbClass(context); return; } if (name == "$__lldb_objc_class") { - LookUpLldbObjCClass(context, current_id); + LookUpLldbObjCClass(context); return; } if (name == g_lldb_local_vars_namespace_cstr) { @@ -1402,7 +1362,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( m_parser_vars->m_persistent_vars->GetVariable(name)); if (pvar_sp) { - AddOneVariable(context, pvar_sp, current_id); + AddOneVariable(context, pvar_sp); return; } @@ -1415,10 +1375,9 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( reg_name)); if (reg_info) { - LLDB_LOGF(log, " CEDM::FEVD[%u] Found register %s", current_id, - reg_info->name); + LLDB_LOG(log, " CEDM::FEVD Found register {0}", reg_info->name); - AddOneRegister(context, reg_info, current_id); + AddOneRegister(context, reg_info); } } return; @@ -1427,29 +1386,29 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( bool local_var_lookup = !namespace_decl || (namespace_decl.GetName() == g_lldb_local_vars_namespace_cstr); if (frame && local_var_lookup) - if (LookupLocalVariable(context, name, current_id, sym_ctx, namespace_decl)) + if (LookupLocalVariable(context, name, sym_ctx, namespace_decl)) return; if (target) { ValueObjectSP valobj; VariableSP var; - var = FindGlobalVariable(*target, module_sp, name, &namespace_decl); + var = FindGlobalVariable(*target, module_sp, name, namespace_decl); if (var) { valobj = ValueObjectVariable::Create(target, var); - AddOneVariable(context, var, valobj, current_id); - context.m_found.variable = true; + AddOneVariable(context, var, valobj); + context.m_found_variable = true; return; } } - LookupFunction(context, module_sp, name, namespace_decl, current_id); + LookupFunction(context, module_sp, name, namespace_decl); // Try the modules next. - if (!context.m_found.function_with_type_info) - LookupInModulesDeclVendor(context, name, current_id); + if (!context.m_found_function_with_type_info) + LookupInModulesDeclVendor(context, name); - if (target && !context.m_found.variable && !namespace_decl) { + if (target && !context.m_found_variable && !namespace_decl) { // We couldn't find a non-symbol variable for this. Now we'll hunt for a // generic data symbol, and -- if it is found -- treat it as a variable. Status error; @@ -1471,8 +1430,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( m_ast_context->getDiagnostics().getCustomDiagID( clang::DiagnosticsEngine::Level::Warning, "%0"); m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str(); - AddOneGenericVariable(context, *data_symbol, current_id); - context.m_found.variable = true; + AddOneGenericVariable(context, *data_symbol); + context.m_found_variable = true; } } } @@ -1486,25 +1445,22 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, Type *var_type = var->GetType(); if (!var_type) { - if (log) - log->PutCString("Skipped a definition because it has no type"); + LLDB_LOG(log, "Skipped a definition because it has no type"); return false; } CompilerType var_clang_type = var_type->GetFullCompilerType(); if (!var_clang_type) { - if (log) - log->PutCString("Skipped a definition because it has no Clang type"); + LLDB_LOG(log, "Skipped a definition because it has no Clang type"); return false; } - ClangASTContext *clang_ast = llvm::dyn_cast_or_null<ClangASTContext>( + TypeSystemClang *clang_ast = llvm::dyn_cast_or_null<TypeSystemClang>( var_type->GetForwardCompilerType().GetTypeSystem()); if (!clang_ast) { - if (log) - log->PutCString("Skipped a definition because it has no Clang AST"); + LLDB_LOG(log, "Skipped a definition because it has no Clang AST"); return false; } @@ -1521,7 +1477,7 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, const_value_extractor.GetByteSize()); var_location.SetValueType(Value::eValueTypeHostAddress); } else { - LLDB_LOGF(log, "Error evaluating constant variable: %s", err.AsCString()); + LLDB_LOG(log, "Error evaluating constant variable: {0}", err.AsCString()); return false; } } @@ -1529,8 +1485,8 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, CompilerType type_to_use = GuardedCopyType(var_clang_type); if (!type_to_use) { - LLDB_LOGF(log, - "Couldn't copy a variable's type into the parser's AST context"); + LLDB_LOG(log, + "Couldn't copy a variable's type into the parser's AST context"); return false; } @@ -1567,8 +1523,7 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, VariableSP var, - ValueObjectSP valobj, - unsigned int current_id) { + ValueObjectSP valobj) { assert(m_parser_vars.get()); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1611,7 +1566,6 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, entity->EnableParserVars(GetParserID()); ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID()); - parser_vars->m_parser_type = pt; parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value = var_location; @@ -1620,15 +1574,12 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, if (is_reference) entity->m_flags |= ClangExpressionVariable::EVTypeIsReference; - LLDB_LOG(log, - " CEDM::FEVD[{0}] Found variable {1}, returned\n{2} (original {3})", - current_id, decl_name, ClangUtil::DumpDecl(var_decl), - ClangUtil::ToString(ut)); + LLDB_LOG(log, " CEDM::FEVD Found variable {1}, returned\n{2} (original {3})", + decl_name, ClangUtil::DumpDecl(var_decl), ClangUtil::ToString(ut)); } void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, - ExpressionVariableSP &pvar_sp, - unsigned int current_id) { + ExpressionVariableSP &pvar_sp) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); TypeFromUser user_type( @@ -1637,8 +1588,8 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, TypeFromParser parser_type(GuardedCopyType(user_type)); if (!parser_type.GetOpaqueQualType()) { - LLDB_LOGF(log, " CEDM::FEVD[%u] Couldn't import type for pvar %s", - current_id, pvar_sp->GetName().GetCString()); + LLDB_LOG(log, " CEDM::FEVD Couldn't import type for pvar {0}", + pvar_sp->GetName()); return; } @@ -1650,18 +1601,16 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, ClangExpressionVariable::ParserVars *parser_vars = llvm::cast<ClangExpressionVariable>(pvar_sp.get()) ->GetParserVars(GetParserID()); - parser_vars->m_parser_type = parser_type; parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value.Clear(); - LLDB_LOG(log, " CEDM::FEVD[{0}] Added pvar {1}, returned\n{2}", current_id, + LLDB_LOG(log, " CEDM::FEVD Added pvar {1}, returned\n{2}", pvar_sp->GetName(), ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, - const Symbol &symbol, - unsigned int current_id) { + const Symbol &symbol) { assert(m_parser_vars.get()); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1671,7 +1620,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, if (target == nullptr) return; - ClangASTContext *scratch_ast_context = ClangASTContext::GetScratch(*target); + TypeSystemClang *scratch_ast_context = TypeSystemClang::GetScratch(*target); if (!scratch_ast_context) return; @@ -1704,18 +1653,16 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, parser_vars->m_lldb_value.GetScalar() = symbol_load_addr; parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress); - parser_vars->m_parser_type = parser_type; parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_sym = &symbol; - LLDB_LOG(log, " CEDM::FEVD[{0}] Found variable {1}, returned\n{2}", - current_id, decl_name, ClangUtil::DumpDecl(var_decl)); + LLDB_LOG(log, " CEDM::FEVD Found variable {1}, returned\n{2}", decl_name, + ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, - const RegisterInfo *reg_info, - unsigned int current_id) { + const RegisterInfo *reg_info) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); CompilerType clang_type = @@ -1723,8 +1670,8 @@ void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, reg_info->encoding, reg_info->byte_size * 8); if (!clang_type) { - LLDB_LOGF(log, " Tried to add a type for %s, but couldn't get one", - context.m_decl_name.getAsString().c_str()); + LLDB_LOG(log, " Tried to add a type for {0}, but couldn't get one", + context.m_decl_name.getAsString()); return; } @@ -1744,20 +1691,18 @@ void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, entity->EnableParserVars(GetParserID()); ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID()); - parser_vars->m_parser_type = parser_clang_type; parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value.Clear(); entity->m_flags |= ClangExpressionVariable::EVBareRegister; - LLDB_LOG(log, " CEDM::FEVD[{0}] Added register {1}, returned\n{2}", - current_id, context.m_decl_name.getAsString(), - ClangUtil::DumpDecl(var_decl)); + LLDB_LOG(log, " CEDM::FEVD Added register {1}, returned\n{2}", + context.m_decl_name.getAsString(), ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, - Function *function, Symbol *symbol, - unsigned int current_id) { + Function *function, + Symbol *symbol) { assert(m_parser_vars.get()); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1780,7 +1725,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, if (!extern_c) { TypeSystem *type_system = function->GetDeclContext().GetTypeSystem(); - if (llvm::isa<ClangASTContext>(type_system)) { + if (llvm::isa<TypeSystemClang>(type_system)) { clang::DeclContext *src_decl_context = (clang::DeclContext *)function->GetDeclContext() .GetOpaqueDeclContext(); @@ -1800,9 +1745,9 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, function->DumpSymbolContext(&ss); LLDB_LOG(log, - " CEDM::FEVD[{0}] Imported decl for function template" + " CEDM::FEVD Imported decl for function template" " {1} (description {2}), returned\n{3}", - current_id, copied_function_template->getNameAsString(), + copied_function_template->getNameAsString(), ss.GetData(), ClangUtil::DumpDecl(copied_function_template)); } @@ -1819,35 +1764,31 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, function->DumpSymbolContext(&ss); LLDB_LOG(log, - " CEDM::FEVD[{0}]] Imported decl for function {1} " + " CEDM::FEVD Imported decl for function {1} " "(description {2}), returned\n{3}", - current_id, copied_function_decl->getNameAsString(), - ss.GetData(), ClangUtil::DumpDecl(copied_function_decl)); + copied_function_decl->getNameAsString(), ss.GetData(), + ClangUtil::DumpDecl(copied_function_decl)); } context.AddNamedDecl(copied_function_decl); return; } else { - if (log) { - LLDB_LOGF(log, " Failed to import the function decl for '%s'", - src_function_decl->getName().str().c_str()); - } + LLDB_LOG(log, " Failed to import the function decl for '{0}'", + src_function_decl->getName()); } } } } if (!function_type) { - if (log) - log->PutCString(" Skipped a function because it has no type"); + LLDB_LOG(log, " Skipped a function because it has no type"); return; } function_clang_type = function_type->GetFullCompilerType(); if (!function_clang_type) { - if (log) - log->PutCString(" Skipped a function because it has no Clang type"); + LLDB_LOG(log, " Skipped a function because it has no Clang type"); return; } @@ -1858,24 +1799,17 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, function_decl = context.AddFunDecl(copied_function_type, extern_c); if (!function_decl) { - if (log) { - LLDB_LOGF( - log, - " Failed to create a function decl for '%s' {0x%8.8" PRIx64 "}", - function_type->GetName().GetCString(), function_type->GetID()); - } + LLDB_LOG(log, " Failed to create a function decl for '{0}' ({1:x})", + function_type->GetName(), function_type->GetID()); return; } } else { // We failed to copy the type we found - if (log) { - LLDB_LOGF(log, - " Failed to import the function type '%s' {0x%8.8" PRIx64 - "} into the expression parser AST contenxt", - function_type->GetName().GetCString(), - function_type->GetID()); - } + LLDB_LOG(log, + " Failed to import the function type '{0}' ({1:x})" + " into the expression parser AST contenxt", + function_type->GetName(), function_type->GetID()); return; } @@ -1884,8 +1818,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, function_decl = context.AddGenericFunDecl(); is_indirect_function = symbol->IsIndirect(); } else { - if (log) - log->PutCString(" AddOneFunction called with no function and no symbol"); + LLDB_LOG(log, " AddOneFunction called with no function and no symbol"); return; } @@ -1931,25 +1864,22 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, Address::DumpStyleResolvedDescription); LLDB_LOG(log, - " CEDM::FEVD[{0}] Found {1} function {2} (description {3}), " + " CEDM::FEVD Found {1} function {2} (description {3}), " "returned\n{4}", - current_id, (function ? "specific" : "generic"), decl_name, - ss.GetData(), ClangUtil::DumpDecl(function_decl)); + (function ? "specific" : "generic"), decl_name, ss.GetData(), + ClangUtil::DumpDecl(function_decl)); } } -void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, - const TypeFromUser &ut, - unsigned int current_id) { +void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context, + const TypeFromUser &ut) { CompilerType copied_clang_type = GuardedCopyType(ut); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (!copied_clang_type) { - if (log) - LLDB_LOGF( - log, - "ClangExpressionDeclMap::AddThisType - Couldn't import the type"); + LLDB_LOG(log, + "ClangExpressionDeclMap::AddThisType - Couldn't import the type"); return; } @@ -2009,16 +1939,14 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, } void ClangExpressionDeclMap::AddOneType(NameSearchContext &context, - const TypeFromUser &ut, - unsigned int current_id) { + const TypeFromUser &ut) { CompilerType copied_clang_type = GuardedCopyType(ut); if (!copied_clang_type) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (log) - LLDB_LOGF( - log, "ClangExpressionDeclMap::AddOneType - Couldn't import the type"); + LLDB_LOG(log, + "ClangExpressionDeclMap::AddOneType - Couldn't import the type"); return; } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index 722f5e15a2aa..6974535a8993 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpressionDeclMap_h_ -#define liblldb_ClangExpressionDeclMap_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H #include <signal.h> #include <stdint.h> @@ -17,7 +17,6 @@ #include "ClangASTSource.h" #include "ClangExpressionVariable.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/SymbolContext.h" @@ -29,6 +28,8 @@ namespace lldb_private { +class ClangPersistentVariables; + /// \class ClangExpressionDeclMap ClangExpressionDeclMap.h /// "lldb/Expression/ClangExpressionDeclMap.h" Manages named entities that are /// defined in LLDB's debug information. @@ -79,8 +80,8 @@ public: ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, - const lldb::TargetSP &target, const lldb::ClangASTImporterSP &importer, - ValueObject *ctx_obj); + const lldb::TargetSP &target, + const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj); /// Destructor ~ClangExpressionDeclMap() override; @@ -274,14 +275,9 @@ public: /// /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. void FindExternalVisibleDecls(NameSearchContext &context, lldb::ModuleSP module, - CompilerDeclContext &namespace_decl, - unsigned int current_id); + const CompilerDeclContext &namespace_decl); protected: /// Retrieves the declaration with the given name from the storage of @@ -335,7 +331,8 @@ private: ///that receives new top-level ///functions. private: - DISALLOW_COPY_AND_ASSIGN(ParserVars); + ParserVars(const ParserVars &) = delete; + const ParserVars &operator=(const ParserVars &) = delete; }; std::unique_ptr<ParserVars> m_parser_vars; @@ -394,32 +391,19 @@ private: /// /// \param[in] name /// The name of the entities that need to be found. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - void SearchPersistenDecls(NameSearchContext &context, const ConstString name, - unsigned int current_id); + void SearchPersistenDecls(NameSearchContext &context, const ConstString name); /// Handles looking up $__lldb_class which requires special treatment. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - void LookUpLldbClass(NameSearchContext &context, unsigned int current_id); + void LookUpLldbClass(NameSearchContext &context); /// Handles looking up $__lldb_objc_class which requires special treatment. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - void LookUpLldbObjCClass(NameSearchContext &context, unsigned int current_id); + void LookUpLldbObjCClass(NameSearchContext &context); /// Handles looking up the synthetic namespace that contains our local /// variables for the current frame. @@ -438,12 +422,7 @@ private: /// /// \param[in] name /// The name of the entities that need to be found. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - void LookupInModulesDeclVendor(NameSearchContext &context, ConstString name, - unsigned current_id); + void LookupInModulesDeclVendor(NameSearchContext &context, ConstString name); /// Looks up a local variable. /// @@ -453,10 +432,6 @@ private: /// \param[in] name /// The name of the entities that need to be found. /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - /// /// \param[in] sym_ctx /// The current SymbolContext of this frame. /// @@ -466,8 +441,8 @@ private: /// \return /// True iff a local variable was found. bool LookupLocalVariable(NameSearchContext &context, ConstString name, - unsigned current_id, SymbolContext &sym_ctx, - CompilerDeclContext &namespace_decl); + SymbolContext &sym_ctx, + const CompilerDeclContext &namespace_decl); /// Searches for functions in the given SymbolContextList. /// @@ -499,13 +474,9 @@ private: /// /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. void LookupFunction(NameSearchContext &context, lldb::ModuleSP module_sp, - ConstString name, CompilerDeclContext &namespace_decl, - unsigned current_id); + ConstString name, + const CompilerDeclContext &namespace_decl); /// Given a target, find a variable that matches the given name and type. /// @@ -523,9 +494,9 @@ private: /// /// \return /// The LLDB Variable found, or NULL if none was found. - lldb::VariableSP FindGlobalVariable(Target &target, lldb::ModuleSP &module, - ConstString name, - CompilerDeclContext *namespace_decl); + lldb::VariableSP + FindGlobalVariable(Target &target, lldb::ModuleSP &module, ConstString name, + const CompilerDeclContext &namespace_decl); /// Get the value of a variable in a given execution context and return the /// associated Types if needed. @@ -565,7 +536,7 @@ private: /// \param[in] valobj /// The LLDB ValueObject for that variable. void AddOneVariable(NameSearchContext &context, lldb::VariableSP var, - lldb::ValueObjectSP valobj, unsigned int current_id); + lldb::ValueObjectSP valobj); /// Use the NameSearchContext to generate a Decl for the given persistent /// variable, and put it in the list of found entities. @@ -575,18 +546,12 @@ private: /// /// \param[in] pvar_sp /// The persistent variable that needs a Decl. - /// - /// \param[in] current_id - /// The ID of the current invocation of FindExternalVisibleDecls - /// for logging purposes. void AddOneVariable(NameSearchContext &context, - lldb::ExpressionVariableSP &pvar_sp, - unsigned int current_id); + lldb::ExpressionVariableSP &pvar_sp); /// Use the NameSearchContext to generate a Decl for the given LLDB symbol /// (treated as a variable), and put it in the list of found entities. - void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol, - unsigned int current_id); + void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol); /// Use the NameSearchContext to generate a Decl for the given function. /// (Functions are not placed in the Tuple list.) Can handle both fully @@ -602,8 +567,7 @@ private: /// \param[in] sym /// The Symbol that corresponds to a function that needs to be /// created with generic type (unitptr_t foo(...)). - void AddOneFunction(NameSearchContext &context, Function *fun, Symbol *sym, - unsigned int current_id); + void AddOneFunction(NameSearchContext &context, Function *fun, Symbol *sym); /// Use the NameSearchContext to generate a Decl for the given register. /// @@ -612,8 +576,7 @@ private: /// /// \param[in] reg_info /// The information corresponding to that register. - void AddOneRegister(NameSearchContext &context, const RegisterInfo *reg_info, - unsigned int current_id); + void AddOneRegister(NameSearchContext &context, const RegisterInfo *reg_info); /// Use the NameSearchContext to generate a Decl for the given type. (Types /// are not placed in the Tuple list.) @@ -623,38 +586,40 @@ private: /// /// \param[in] type /// The type that needs to be created. - void AddOneType(NameSearchContext &context, const TypeFromUser &type, - unsigned int current_id); + void AddOneType(NameSearchContext &context, const TypeFromUser &type); - /// Generate a Decl for "*this" and add a member function declaration to it - /// for the expression, then report it. + /// Adds the class in which the expression is evaluated to the lookup and + /// prepares the class to be used as a context for expression evaluation (for + /// example, it creates a fake member function that will contain the + /// expression LLDB is trying to evaluate). /// /// \param[in] context - /// The NameSearchContext to use when constructing the Decl. + /// The NameSearchContext to which the class should be added as a lookup + /// result. /// /// \param[in] type - /// The type for *this. - void AddThisType(NameSearchContext &context, const TypeFromUser &type, - unsigned int current_id); + /// The type of the class that serves as the evaluation context. + void AddContextClassType(NameSearchContext &context, + const TypeFromUser &type); /// Move a type out of the current ASTContext into another, but make sure to /// export all components of the type also. /// /// \param[in] target - /// The ClangASTContext to move to. + /// The TypeSystemClang to move to. /// \param[in] source - /// The ClangASTContext to move from. This is assumed to be going away. + /// The TypeSystemClang to move from. This is assumed to be going away. /// \param[in] parser_type /// The type as it appears in the source context. /// /// \return /// Returns the moved type, or an empty type if there was a problem. - TypeFromUser DeportType(ClangASTContext &target, ClangASTContext &source, + TypeFromUser DeportType(TypeSystemClang &target, TypeSystemClang &source, TypeFromParser parser_type); - ClangASTContext *GetClangASTContext(); + TypeSystemClang *GetTypeSystemClang(); }; } // namespace lldb_private -#endif // liblldb_ClangExpressionDeclMap_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h index 48da5abb9126..e33e5df22236 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h @@ -6,21 +6,24 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpression_h_ -#define liblldb_ClangExpression_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H #include <map> #include <string> #include <vector> - -#include "lldb/Core/ClangForward.h" #include "lldb/Expression/ExpressionTypeSystemHelper.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" +namespace clang { +class ASTConsumer; +} + namespace lldb_private { +class ClangExpressionDeclMap; class RecordingMemoryManager; // ClangExpressionHelper @@ -57,4 +60,4 @@ protected: } // namespace lldb_private -#endif // liblldb_ClangExpression_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 8abd14942885..6ff028cf6980 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -1,4 +1,4 @@ -//===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===// +//===-- ClangExpressionParser.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -67,6 +67,7 @@ #include "IRForTarget.h" #include "ModuleDependencyCollector.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" @@ -75,7 +76,6 @@ #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/File.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Language.h" @@ -91,6 +91,7 @@ #include "lldb/Utility/StringList.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h" #include <cctype> #include <memory> @@ -146,21 +147,40 @@ public: llvm::StringRef getErrorString() { return m_error_stream.GetString(); } }; +static void AddAllFixIts(ClangDiagnostic *diag, const clang::Diagnostic &Info) { + for (auto &fix_it : Info.getFixItHints()) { + if (fix_it.isNull()) + continue; + diag->AddFixitHint(fix_it); + } +} + class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer { public: ClangDiagnosticManagerAdapter(DiagnosticOptions &opts) { - DiagnosticOptions *m_options = new DiagnosticOptions(opts); - m_options->ShowPresumedLoc = true; - m_options->ShowLevel = false; - m_os.reset(new llvm::raw_string_ostream(m_output)); - m_passthrough.reset( - new clang::TextDiagnosticPrinter(*m_os, m_options, false)); + DiagnosticOptions *options = new DiagnosticOptions(opts); + options->ShowPresumedLoc = true; + options->ShowLevel = false; + m_os = std::make_shared<llvm::raw_string_ostream>(m_output); + m_passthrough = + std::make_shared<clang::TextDiagnosticPrinter>(*m_os, options); } void ResetManager(DiagnosticManager *manager = nullptr) { m_manager = manager; } + /// Returns the last ClangDiagnostic message that the DiagnosticManager + /// received or a nullptr if the DiagnosticMangager hasn't seen any + /// Clang diagnostics yet. + ClangDiagnostic *MaybeGetLastClangDiag() const { + if (m_manager->Diagnostics().empty()) + return nullptr; + lldb_private::Diagnostic *diag = m_manager->Diagnostics().back().get(); + ClangDiagnostic *clang_diag = dyn_cast<ClangDiagnostic>(diag); + return clang_diag; + } + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override { if (!m_manager) { @@ -180,6 +200,9 @@ public: return; } + // Update error/warning counters. + DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); + // Render diagnostic message to m_output. m_output.clear(); m_passthrough->HandleDiagnostic(DiagLevel, Info); @@ -203,11 +226,29 @@ public: case DiagnosticsEngine::Level::Note: m_manager->AppendMessageToDiagnostic(m_output); make_new_diagnostic = false; + + // 'note:' diagnostics for errors and warnings can also contain Fix-Its. + // We add these Fix-Its to the last error diagnostic to make sure + // that we later have all Fix-Its related to an 'error' diagnostic when + // we apply them to the user expression. + auto *clang_diag = MaybeGetLastClangDiag(); + // If we don't have a previous diagnostic there is nothing to do. + // If the previous diagnostic already has its own Fix-Its, assume that + // the 'note:' Fix-It is just an alternative way to solve the issue and + // ignore these Fix-Its. + if (!clang_diag || clang_diag->HasFixIts()) + break; + // Ignore all Fix-Its that are not associated with an error. + if (clang_diag->GetSeverity() != eDiagnosticSeverityError) + break; + AddAllFixIts(clang_diag, Info); + break; } if (make_new_diagnostic) { // ClangDiagnostic messages are expected to have no whitespace/newlines // around them. - std::string stripped_output = llvm::StringRef(m_output).trim(); + std::string stripped_output = + std::string(llvm::StringRef(m_output).trim()); auto new_diagnostic = std::make_unique<ClangDiagnostic>( stripped_output, severity, Info.getID()); @@ -216,20 +257,18 @@ public: // enough context in an expression for the warning to be useful. // FIXME: Should we try to filter out FixIts that apply to our generated // code, and not the user's expression? - if (severity == eDiagnosticSeverityError) { - size_t num_fixit_hints = Info.getNumFixItHints(); - for (size_t i = 0; i < num_fixit_hints; i++) { - const clang::FixItHint &fixit = Info.getFixItHint(i); - if (!fixit.isNull()) - new_diagnostic->AddFixitHint(fixit); - } - } + if (severity == eDiagnosticSeverityError) + AddAllFixIts(new_diagnostic.get(), Info); m_manager->AddDiagnostic(std::move(new_diagnostic)); } } - clang::TextDiagnosticPrinter *GetPassthrough() { return m_passthrough.get(); } + void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override { + m_passthrough->BeginSourceFile(LO, PP); + } + + void EndSourceFile() override { m_passthrough->EndSourceFile(); } private: DiagnosticManager *m_manager = nullptr; @@ -253,9 +292,9 @@ static void SetupModuleHeaderPaths(CompilerInstance *compiler, } llvm::SmallString<128> module_cache; - auto props = ModuleList::GetGlobalModuleListProperties(); + const auto &props = ModuleList::GetGlobalModuleListProperties(); props.GetClangModulesCachePath().GetPath(module_cache); - search_opts.ModuleCachePath = module_cache.str(); + search_opts.ModuleCachePath = std::string(module_cache.str()); LLDB_LOG(log, "Using module cache path: {0}", module_cache.c_str()); search_opts.ResourceDir = GetClangResourceDir().GetPath(); @@ -279,28 +318,27 @@ ClangExpressionParser::ClangExpressionParser( // We can't compile expressions without a target. So if the exe_scope is // null or doesn't have a target, then we just need to get out of here. I'll - // lldb_assert and not make any of the compiler objects since + // lldbassert and not make any of the compiler objects since // I can't return errors directly from the constructor. Further calls will // check if the compiler was made and // bag out if it wasn't. if (!exe_scope) { - lldb_assert(exe_scope, "Can't make an expression parser with a null scope.", - __FUNCTION__, __FILE__, __LINE__); + lldbassert(exe_scope && + "Can't make an expression parser with a null scope."); return; } lldb::TargetSP target_sp; target_sp = exe_scope->CalculateTarget(); if (!target_sp) { - lldb_assert(target_sp.get(), - "Can't make an expression parser with a null target.", - __FUNCTION__, __FILE__, __LINE__); + lldbassert(target_sp.get() && + "Can't make an expression parser with a null target."); return; } // 1. Create a new compiler instance. - m_compiler.reset(new CompilerInstance()); + m_compiler = std::make_unique<CompilerInstance>(); // When capturing a reproducer, hook up the file collector with clang to // collector modules and headers. @@ -391,9 +429,13 @@ ClangExpressionParser::ClangExpressionParser( // target. In this case, a specialized language runtime is available and we // can query it for extra options. For 99% of use cases, this will not be // needed and should be provided when basic platform detection is not enough. - if (lang_rt) + // FIXME: Generalize this. Only RenderScriptRuntime currently supports this + // currently. Hardcoding this isn't ideal but it's better than LanguageRuntime + // having knowledge of clang::TargetOpts. + if (auto *renderscript_rt = + llvm::dyn_cast_or_null<RenderScriptRuntime>(lang_rt)) overridden_target_opts = - lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); + renderscript_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); if (overridden_target_opts) if (log && log->GetVerbose()) { @@ -606,11 +648,12 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->createASTContext(); clang::ASTContext &ast_context = m_compiler->getASTContext(); - m_ast_context.reset(new ClangASTContext(ast_context)); + m_ast_context = std::make_unique<TypeSystemClang>( + "Expression ASTContext for '" + m_filename + "'", ast_context); std::string module_name("$__lldb_module"); - m_llvm_context.reset(new LLVMContext()); + m_llvm_context = std::make_unique<LLVMContext>(); m_code_generator.reset(CreateLLVMCodeGen( m_compiler->getDiagnostics(), module_name, m_compiler->getHeaderSearchOpts(), m_compiler->getPreprocessorOpts(), @@ -631,11 +674,33 @@ class CodeComplete : public CodeCompleteConsumer { std::string m_expr; unsigned m_position = 0; - CompletionRequest &m_request; /// The printing policy we use when printing declarations for our completion /// descriptions. clang::PrintingPolicy m_desc_policy; + struct CompletionWithPriority { + CompletionResult::Completion completion; + /// See CodeCompletionResult::Priority; + unsigned Priority; + + /// Establishes a deterministic order in a list of CompletionWithPriority. + /// The order returned here is the order in which the completions are + /// displayed to the user. + bool operator<(const CompletionWithPriority &o) const { + // High priority results should come first. + if (Priority != o.Priority) + return Priority > o.Priority; + + // Identical priority, so just make sure it's a deterministic order. + return completion.GetUniqueKey() < o.completion.GetUniqueKey(); + } + }; + + /// The stored completions. + /// Warning: These are in a non-deterministic order until they are sorted + /// and returned back to the caller. + std::vector<CompletionWithPriority> m_completions; + /// Returns true if the given character can be used in an identifier. /// This also returns true for numbers because for completion we usually /// just iterate backwards over iterators. @@ -652,7 +717,7 @@ class CodeComplete : public CodeCompleteConsumer { /// Drops all tokens in front of the expression that are unrelated for /// the completion of the cmd line. 'unrelated' means here that the token /// is not interested for the lldb completion API result. - StringRef dropUnrelatedFrontTokens(StringRef cmd) { + StringRef dropUnrelatedFrontTokens(StringRef cmd) const { if (cmd.empty()) return cmd; @@ -673,18 +738,18 @@ class CodeComplete : public CodeCompleteConsumer { } /// Removes the last identifier token from the given cmd line. - StringRef removeLastToken(StringRef cmd) { + StringRef removeLastToken(StringRef cmd) const { while (!cmd.empty() && IsIdChar(cmd.back())) { cmd = cmd.drop_back(); } return cmd; } - /// Attemps to merge the given completion from the given position into the + /// Attempts to merge the given completion from the given position into the /// existing command. Returns the completion string that can be returned to /// the lldb completion API. std::string mergeCompletion(StringRef existing, unsigned pos, - StringRef completion) { + StringRef completion) const { StringRef existing_command = existing.substr(0, pos); // We rewrite the last token with the completion, so let's drop that // token from the command. @@ -706,11 +771,10 @@ public: /// \param[out] position /// The character position of the user cursor in the `expr` parameter. /// - CodeComplete(CompletionRequest &request, clang::LangOptions ops, - std::string expr, unsigned position) + CodeComplete(clang::LangOptions ops, std::string expr, unsigned position) : CodeCompleteConsumer(CodeCompleteOptions()), m_info(std::make_shared<GlobalCodeCompletionAllocator>()), m_expr(expr), - m_position(position), m_request(request), m_desc_policy(ops) { + m_position(position), m_desc_policy(ops) { // Ensure that the printing policy is producing a description that is as // short as possible. @@ -723,9 +787,6 @@ public: m_desc_policy.Bool = true; } - /// Deregisters and destroys this code-completion consumer. - ~CodeComplete() override {} - /// \name Code-completion filtering /// Check if the result should be filtered out. bool isResultFilteredOut(StringRef Filter, @@ -753,6 +814,85 @@ public: return true; } +private: + /// Generate the completion strings for the given CodeCompletionResult. + /// Note that this function has to process results that could come in + /// non-deterministic order, so this function should have no side effects. + /// To make this easier to enforce, this function and all its parameters + /// should always be const-qualified. + /// \return Returns llvm::None if no completion should be provided for the + /// given CodeCompletionResult. + llvm::Optional<CompletionWithPriority> + getCompletionForResult(const CodeCompletionResult &R) const { + std::string ToInsert; + std::string Description; + // Handle the different completion kinds that come from the Sema. + switch (R.Kind) { + case CodeCompletionResult::RK_Declaration: { + const NamedDecl *D = R.Declaration; + ToInsert = R.Declaration->getNameAsString(); + // If we have a function decl that has no arguments we want to + // complete the empty parantheses for the user. If the function has + // arguments, we at least complete the opening bracket. + if (const FunctionDecl *F = dyn_cast<FunctionDecl>(D)) { + if (F->getNumParams() == 0) + ToInsert += "()"; + else + ToInsert += "("; + raw_string_ostream OS(Description); + F->print(OS, m_desc_policy, false); + OS.flush(); + } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { + Description = V->getType().getAsString(m_desc_policy); + } else if (const FieldDecl *F = dyn_cast<FieldDecl>(D)) { + Description = F->getType().getAsString(m_desc_policy); + } else if (const NamespaceDecl *N = dyn_cast<NamespaceDecl>(D)) { + // If we try to complete a namespace, then we can directly append + // the '::'. + if (!N->isAnonymousNamespace()) + ToInsert += "::"; + } + break; + } + case CodeCompletionResult::RK_Keyword: + ToInsert = R.Keyword; + break; + case CodeCompletionResult::RK_Macro: + ToInsert = R.Macro->getName().str(); + break; + case CodeCompletionResult::RK_Pattern: + ToInsert = R.Pattern->getTypedText(); + break; + } + // We also filter some internal lldb identifiers here. The user + // shouldn't see these. + if (llvm::StringRef(ToInsert).startswith("$__lldb_")) + return llvm::None; + if (ToInsert.empty()) + return llvm::None; + // Merge the suggested Token into the existing command line to comply + // with the kind of result the lldb API expects. + std::string CompletionSuggestion = + mergeCompletion(m_expr, m_position, ToInsert); + + CompletionResult::Completion completion(CompletionSuggestion, Description, + CompletionMode::Normal); + return {{completion, R.Priority}}; + } + +public: + /// Adds the completions to the given CompletionRequest. + void GetCompletions(CompletionRequest &request) { + // Bring m_completions into a deterministic order and pass it on to the + // CompletionRequest. + llvm::sort(m_completions); + + for (const CompletionWithPriority &C : m_completions) + request.AddCompletion(C.completion.GetCompletion(), + C.completion.GetDescription(), + C.completion.GetMode()); + } + /// \name Code-completion callbacks /// Process the finalized code-completion results. void ProcessCodeCompleteResults(Sema &SemaRef, CodeCompletionContext Context, @@ -771,59 +911,11 @@ public: continue; CodeCompletionResult &R = Results[I]; - std::string ToInsert; - std::string Description; - // Handle the different completion kinds that come from the Sema. - switch (R.Kind) { - case CodeCompletionResult::RK_Declaration: { - const NamedDecl *D = R.Declaration; - ToInsert = R.Declaration->getNameAsString(); - // If we have a function decl that has no arguments we want to - // complete the empty parantheses for the user. If the function has - // arguments, we at least complete the opening bracket. - if (const FunctionDecl *F = dyn_cast<FunctionDecl>(D)) { - if (F->getNumParams() == 0) - ToInsert += "()"; - else - ToInsert += "("; - raw_string_ostream OS(Description); - F->print(OS, m_desc_policy, false); - OS.flush(); - } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { - Description = V->getType().getAsString(m_desc_policy); - } else if (const FieldDecl *F = dyn_cast<FieldDecl>(D)) { - Description = F->getType().getAsString(m_desc_policy); - } else if (const NamespaceDecl *N = dyn_cast<NamespaceDecl>(D)) { - // If we try to complete a namespace, then we can directly append - // the '::'. - if (!N->isAnonymousNamespace()) - ToInsert += "::"; - } - break; - } - case CodeCompletionResult::RK_Keyword: - ToInsert = R.Keyword; - break; - case CodeCompletionResult::RK_Macro: - ToInsert = R.Macro->getName().str(); - break; - case CodeCompletionResult::RK_Pattern: - ToInsert = R.Pattern->getTypedText(); - break; - } - // At this point all information is in the ToInsert string. - - // We also filter some internal lldb identifiers here. The user - // shouldn't see these. - if (StringRef(ToInsert).startswith("$__lldb_")) + llvm::Optional<CompletionWithPriority> CompletionAndPriority = + getCompletionForResult(R); + if (!CompletionAndPriority) continue; - if (!ToInsert.empty()) { - // Merge the suggested Token into the existing command line to comply - // with the kind of result the lldb API expects. - std::string CompletionSuggestion = - mergeCompletion(m_expr, m_position, ToInsert); - m_request.AddCompletion(CompletionSuggestion, Description); - } + m_completions.push_back(*CompletionAndPriority); } } @@ -860,12 +952,13 @@ bool ClangExpressionParser::Complete(CompletionRequest &request, unsigned line, // the LLVMUserExpression which exposes the right API. This should never fail // as we always have a ClangUserExpression whenever we call this. ClangUserExpression *llvm_expr = cast<ClangUserExpression>(&m_expr); - CodeComplete CC(request, m_compiler->getLangOpts(), llvm_expr->GetUserText(), + CodeComplete CC(m_compiler->getLangOpts(), llvm_expr->GetUserText(), typed_pos); // We don't need a code generator for parsing. m_code_generator.reset(); // Start parsing the expression with our custom code completion consumer. ParseInternal(mgr, &CC, line, pos); + CC.GetCompletions(request); return true; } @@ -881,7 +974,6 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, ClangDiagnosticManagerAdapter *adapter = static_cast<ClangDiagnosticManagerAdapter *>( m_compiler->getDiagnostics().getClient()); - auto diag_buf = adapter->GetPassthrough(); adapter->ResetManager(&diagnostic_manager); @@ -936,8 +1028,8 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, source_mgr.setMainFileID(source_mgr.createFileID(std::move(memory_buffer))); } - diag_buf->BeginSourceFile(m_compiler->getLangOpts(), - &m_compiler->getPreprocessor()); + adapter->BeginSourceFile(m_compiler->getLangOpts(), + &m_compiler->getPreprocessor()); ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); @@ -961,11 +1053,11 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, std::unique_ptr<clang::ASTConsumer> Consumer; if (ast_transformer) { - Consumer.reset(new ASTConsumerForwarder(ast_transformer)); + Consumer = std::make_unique<ASTConsumerForwarder>(ast_transformer); } else if (m_code_generator) { - Consumer.reset(new ASTConsumerForwarder(m_code_generator.get())); + Consumer = std::make_unique<ASTConsumerForwarder>(m_code_generator.get()); } else { - Consumer.reset(new ASTConsumer()); + Consumer = std::make_unique<ASTConsumer>(); } clang::ASTContext &ast_context = m_compiler->getASTContext(); @@ -1022,9 +1114,9 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, // original behavior of ParseAST (which also destroys the Sema after parsing). m_compiler->setSema(nullptr); - diag_buf->EndSourceFile(); + adapter->EndSourceFile(); - unsigned num_errors = diag_buf->getNumErrors(); + unsigned num_errors = adapter->getNumErrors(); if (m_pp_callbacks && m_pp_callbacks->hasErrors()) { num_errors++; @@ -1065,6 +1157,28 @@ ClangExpressionParser::GetClangTargetABI(const ArchSpec &target_arch) { return abi; } +/// Applies the given Fix-It hint to the given commit. +static void ApplyFixIt(const FixItHint &fixit, clang::edit::Commit &commit) { + // This is cobbed from clang::Rewrite::FixItRewriter. + if (fixit.CodeToInsert.empty()) { + if (fixit.InsertFromRange.isValid()) { + commit.insertFromRange(fixit.RemoveRange.getBegin(), + fixit.InsertFromRange, /*afterToken=*/false, + fixit.BeforePreviousInsertions); + return; + } + commit.remove(fixit.RemoveRange); + return; + } + if (fixit.RemoveRange.isTokenRange() || + fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd()) { + commit.replace(fixit.RemoveRange, fixit.CodeToInsert); + return; + } + commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert, + /*afterToken=*/false, fixit.BeforePreviousInsertions); +} + bool ClangExpressionParser::RewriteExpression( DiagnosticManager &diagnostic_manager) { clang::SourceManager &source_manager = m_compiler->getSourceManager(); @@ -1096,26 +1210,12 @@ bool ClangExpressionParser::RewriteExpression( for (const auto &diag : diagnostic_manager.Diagnostics()) { const auto *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag.get()); - if (diagnostic && diagnostic->HasFixIts()) { - for (const FixItHint &fixit : diagnostic->FixIts()) { - // This is cobbed from clang::Rewrite::FixItRewriter. - if (fixit.CodeToInsert.empty()) { - if (fixit.InsertFromRange.isValid()) { - commit.insertFromRange(fixit.RemoveRange.getBegin(), - fixit.InsertFromRange, /*afterToken=*/false, - fixit.BeforePreviousInsertions); - } else - commit.remove(fixit.RemoveRange); - } else { - if (fixit.RemoveRange.isTokenRange() || - fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd()) - commit.replace(fixit.RemoveRange, fixit.CodeToInsert); - else - commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert, - /*afterToken=*/false, fixit.BeforePreviousInsertions); - } - } - } + if (!diagnostic) + continue; + if (!diagnostic->HasFixIts()) + continue; + for (const FixItHint &fixit : diagnostic->FixIts()) + ApplyFixIt(fixit, commit); } // FIXME - do we want to try to propagate specific errors here? @@ -1230,18 +1330,13 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( type_system_helper->DeclMap(); // result can be NULL if (decl_map) { - Target *target = exe_ctx.GetTargetPtr(); - auto &error_stream = target->GetDebugger().GetErrorStream(); + StreamString error_stream; IRForTarget ir_for_target(decl_map, m_expr.NeedsVariableResolution(), *execution_unit_sp, error_stream, function_name.AsCString()); - bool ir_can_run = - ir_for_target.runOnModule(*execution_unit_sp->GetModule()); - - if (!ir_can_run) { - err.SetErrorString( - "The expression could not be prepared to run in the target"); + if (!ir_for_target.runOnModule(*execution_unit_sp->GetModule())) { + err.SetErrorString(error_stream.GetString()); return err; } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 4a410cecb94a..6afee22da8d1 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -6,10 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpressionParser_h_ -#define liblldb_ClangExpressionParser_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H -#include "lldb/Core/ClangForward.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/ExpressionParser.h" #include "lldb/Utility/ArchSpec.h" @@ -19,13 +18,20 @@ #include <string> #include <vector> +namespace llvm { +class LLVMContext; +} + namespace clang { +class CodeGenerator; class CodeCompleteConsumer; -} +class CompilerInstance; +} // namespace clang namespace lldb_private { class IRExecutionUnit; +class TypeSystemClang; /// \class ClangExpressionParser ClangExpressionParser.h /// "lldb/Expression/ClangExpressionParser.h" Encapsulates an instance of @@ -171,7 +177,7 @@ private: class LLDBPreprocessorCallbacks; LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor ///encounters module imports - std::unique_ptr<ClangASTContext> m_ast_context; + std::unique_ptr<TypeSystemClang> m_ast_context; std::vector<std::string> m_include_directories; /// File name used for the user expression. @@ -179,4 +185,4 @@ private: }; } -#endif // liblldb_ClangExpressionParser_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index 7ebb5fee1ec6..a429963277d1 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -1,4 +1,4 @@ -//===-- ClangExpressionSourceCode.cpp ---------------------------*- C++ -*-===// +//===-- ClangExpressionSourceCode.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,6 +9,7 @@ #include "ClangExpressionSourceCode.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/StringRef.h" @@ -173,8 +174,8 @@ static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, lldb_private::ClangExpressionSourceCode::ClangExpressionSourceCode( llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix, - llvm::StringRef body, Wrapping wrap) - : ExpressionSourceCode(name, prefix, body, wrap) { + llvm::StringRef body, Wrapping wrap, WrapKind wrap_kind) + : ExpressionSourceCode(name, prefix, body, wrap), m_wrap_kind(wrap_kind) { // Use #line markers to pretend that we have a single-line source file // containing only the user expression. This will hide our wrapper code // from the user when we render diagnostics with Clang. @@ -260,10 +261,9 @@ TokenVerifier::TokenVerifier(std::string body) { } } -static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, - StreamString &stream, - const std::string &expr, - lldb::LanguageType wrapping_language) { +void ClangExpressionSourceCode::AddLocalVariableDecls( + const lldb::VariableListSP &var_list_sp, StreamString &stream, + const std::string &expr) const { TokenVerifier tokens(expr); for (size_t i = 0; i < var_list_sp->GetSize(); i++) { @@ -280,13 +280,12 @@ static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, if (!expr.empty() && !tokens.hasToken(var_name.GetStringRef())) continue; - if ((var_name == "self" || var_name == "_cmd") && - (wrapping_language == lldb::eLanguageTypeObjC || - wrapping_language == lldb::eLanguageTypeObjC_plus_plus)) + const bool is_objc = m_wrap_kind == WrapKind::ObjCInstanceMethod || + m_wrap_kind == WrapKind::ObjCStaticMethod; + if ((var_name == "self" || var_name == "_cmd") && is_objc) continue; - if (var_name == "this" && - wrapping_language == lldb::eLanguageTypeC_plus_plus) + if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction) continue; stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString()); @@ -294,9 +293,8 @@ static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, } bool ClangExpressionSourceCode::GetText( - std::string &text, lldb::LanguageType wrapping_language, bool static_method, - ExecutionContext &exe_ctx, bool add_locals, bool force_add_all_locals, - llvm::ArrayRef<std::string> modules) const { + std::string &text, ExecutionContext &exe_ctx, bool add_locals, + bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const { const char *target_specific_defines = "typedef signed char BOOL;\n"; std::string module_macros; @@ -373,21 +371,11 @@ bool ClangExpressionSourceCode::GetText( lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false, true); AddLocalVariableDecls(var_list_sp, lldb_local_var_decls, - force_add_all_locals ? "" : m_body, - wrapping_language); + force_add_all_locals ? "" : m_body); } } if (m_wrap) { - switch (wrapping_language) { - default: - return false; - case lldb::eLanguageTypeC: - case lldb::eLanguageTypeC_plus_plus: - case lldb::eLanguageTypeObjC: - break; - } - // Generate a list of @import statements that will import the specified // module into our expression. std::string module_imports; @@ -406,22 +394,12 @@ bool ClangExpressionSourceCode::GetText( // First construct a tagged form of the user expression so we can find it // later: std::string tagged_body; - switch (wrapping_language) { - default: - tagged_body = m_body; - break; - case lldb::eLanguageTypeC: - case lldb::eLanguageTypeC_plus_plus: - case lldb::eLanguageTypeObjC: - tagged_body.append(m_start_marker); - tagged_body.append(m_body); - tagged_body.append(m_end_marker); - break; - } - switch (wrapping_language) { - default: - break; - case lldb::eLanguageTypeC: + tagged_body.append(m_start_marker); + tagged_body.append(m_body); + tagged_body.append(m_end_marker); + + switch (m_wrap_kind) { + case WrapKind::Function: wrap_stream.Printf("%s" "void \n" "%s(void *$__lldb_arg) \n" @@ -432,7 +410,7 @@ bool ClangExpressionSourceCode::GetText( module_imports.c_str(), m_name.c_str(), lldb_local_var_decls.GetData(), tagged_body.c_str()); break; - case lldb::eLanguageTypeC_plus_plus: + case WrapKind::CppMemberFunction: wrap_stream.Printf("%s" "void \n" "$__lldb_class::%s(void *$__lldb_arg) \n" @@ -443,42 +421,42 @@ bool ClangExpressionSourceCode::GetText( module_imports.c_str(), m_name.c_str(), lldb_local_var_decls.GetData(), tagged_body.c_str()); break; - case lldb::eLanguageTypeObjC: - if (static_method) { - wrap_stream.Printf( - "%s" - "@interface $__lldb_objc_class ($__lldb_category) \n" - "+(void)%s:(void *)$__lldb_arg; \n" - "@end \n" - "@implementation $__lldb_objc_class ($__lldb_category) \n" - "+(void)%s:(void *)$__lldb_arg \n" - "{ \n" - " %s; \n" - "%s" - "} \n" - "@end \n", - module_imports.c_str(), m_name.c_str(), m_name.c_str(), - lldb_local_var_decls.GetData(), tagged_body.c_str()); - } else { - wrap_stream.Printf( - "%s" - "@interface $__lldb_objc_class ($__lldb_category) \n" - "-(void)%s:(void *)$__lldb_arg; \n" - "@end \n" - "@implementation $__lldb_objc_class ($__lldb_category) \n" - "-(void)%s:(void *)$__lldb_arg \n" - "{ \n" - " %s; \n" - "%s" - "} \n" - "@end \n", - module_imports.c_str(), m_name.c_str(), m_name.c_str(), - lldb_local_var_decls.GetData(), tagged_body.c_str()); - } + case WrapKind::ObjCInstanceMethod: + wrap_stream.Printf( + "%s" + "@interface $__lldb_objc_class ($__lldb_category) \n" + "-(void)%s:(void *)$__lldb_arg; \n" + "@end \n" + "@implementation $__lldb_objc_class ($__lldb_category) \n" + "-(void)%s:(void *)$__lldb_arg \n" + "{ \n" + " %s; \n" + "%s" + "} \n" + "@end \n", + module_imports.c_str(), m_name.c_str(), m_name.c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); + break; + + case WrapKind::ObjCStaticMethod: + wrap_stream.Printf( + "%s" + "@interface $__lldb_objc_class ($__lldb_category) \n" + "+(void)%s:(void *)$__lldb_arg; \n" + "@end \n" + "@implementation $__lldb_objc_class ($__lldb_category) \n" + "+(void)%s:(void *)$__lldb_arg \n" + "{ \n" + " %s; \n" + "%s" + "} \n" + "@end \n", + module_imports.c_str(), m_name.c_str(), m_name.c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); break; } - text = wrap_stream.GetString(); + text = std::string(wrap_stream.GetString()); } else { text.append(m_body); } @@ -487,17 +465,7 @@ bool ClangExpressionSourceCode::GetText( } bool ClangExpressionSourceCode::GetOriginalBodyBounds( - std::string transformed_text, lldb::LanguageType wrapping_language, - size_t &start_loc, size_t &end_loc) { - switch (wrapping_language) { - default: - return false; - case lldb::eLanguageTypeC: - case lldb::eLanguageTypeC_plus_plus: - case lldb::eLanguageTypeObjC: - break; - } - + std::string transformed_text, size_t &start_loc, size_t &end_loc) { start_loc = transformed_text.find(m_start_marker); if (start_loc == std::string::npos) return false; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h index 1d159670b962..9a54f0e3ad8d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpressionSourceCode_h -#define liblldb_ClangExpressionSourceCode_h +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONSOURCECODE_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONSOURCECODE_H #include "lldb/Expression/Expression.h" #include "lldb/Expression/ExpressionSourceCode.h" @@ -28,20 +28,30 @@ public: static const llvm::StringRef g_prefix_file_name; static const char *g_expression_prefix; + /// The possible ways an expression can be wrapped. + enum class WrapKind { + /// Wrapped in a non-static member function of a C++ class. + CppMemberFunction, + /// Wrapped in an instance Objective-C method. + ObjCInstanceMethod, + /// Wrapped in a static Objective-C method. + ObjCStaticMethod, + /// Wrapped in a non-member function. + /// Note that this is also used for static member functions of a C++ class. + Function + }; + static ClangExpressionSourceCode *CreateWrapped(llvm::StringRef filename, llvm::StringRef prefix, - llvm::StringRef body) { + llvm::StringRef body, + WrapKind wrap_kind) { return new ClangExpressionSourceCode(filename, "$__lldb_expr", prefix, body, - Wrap); + Wrap, wrap_kind); } /// Generates the source code that will evaluate the expression. /// /// \param text output parameter containing the source code string. - /// \param wrapping_language If the expression is supossed to be wrapped, - /// then this is the language that should be used for that. - /// \param static_method True iff the expression is valuated inside a static - /// Objective-C method. /// \param exe_ctx The execution context in which the expression will be /// evaluated. /// \param add_locals True iff local variables should be injected into the @@ -51,8 +61,7 @@ public: /// \param modules A list of (C++) modules that the expression should import. /// /// \return true iff the source code was successfully generated. - bool GetText(std::string &text, lldb::LanguageType wrapping_language, - bool static_method, ExecutionContext &exe_ctx, bool add_locals, + bool GetText(std::string &text, ExecutionContext &exe_ctx, bool add_locals, bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const; @@ -60,19 +69,24 @@ public: // passed to CreateWrapped. Return true if the bounds could be found. This // will also work on text with FixItHints applied. bool GetOriginalBodyBounds(std::string transformed_text, - lldb::LanguageType wrapping_language, size_t &start_loc, size_t &end_loc); protected: ClangExpressionSourceCode(llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix, llvm::StringRef body, - Wrapping wrap); + Wrapping wrap, WrapKind wrap_kind); private: + void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, + StreamString &stream, + const std::string &expr) const; + /// String marking the start of the user expression. std::string m_start_marker; /// String marking the end of the user expression. std::string m_end_marker; + /// How the expression has been wrapped. + const WrapKind m_wrap_kind; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp index b5a2c80b5349..9af92e194da9 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp @@ -1,4 +1,4 @@ -//===-- ClangExpressionVariable.cpp -----------------------------*- C++ -*-===// +//===-- ClangExpressionVariable.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index 0e6de28ee4df..58d589962abe 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpressionVariable_h_ -#define liblldb_ClangExpressionVariable_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H #include <signal.h> #include <stdint.h> @@ -19,7 +19,6 @@ #include "llvm/Support/Casting.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Symbol/TaggedASTType.h" @@ -30,6 +29,10 @@ namespace llvm { class Value; } +namespace clang { +class NamedDecl; +} + namespace lldb_private { class ValueObjectConstResult; @@ -114,11 +117,9 @@ public: class ParserVars { public: ParserVars() - : m_parser_type(), m_named_decl(nullptr), m_llvm_value(nullptr), + : m_named_decl(nullptr), m_llvm_value(nullptr), m_lldb_value(), m_lldb_var(), m_lldb_sym(nullptr) {} - TypeFromParser - m_parser_type; ///< The type of the variable according to the parser const clang::NamedDecl *m_named_decl; ///< The Decl corresponding to this variable llvm::Value *m_llvm_value; ///< The IR value corresponding to this variable; @@ -196,9 +197,11 @@ public: } /// Members - DISALLOW_COPY_AND_ASSIGN(ClangExpressionVariable); + ClangExpressionVariable(const ClangExpressionVariable &) = delete; + const ClangExpressionVariable & + operator=(const ClangExpressionVariable &) = delete; }; } // namespace lldb_private -#endif // liblldb_ClangExpressionVariable_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp new file mode 100644 index 000000000000..390afb458b5a --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp @@ -0,0 +1,88 @@ +//===-- ClangExternalASTSourceCallbacks.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 "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" + +using namespace lldb_private; + +char ClangExternalASTSourceCallbacks::ID; + +void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) { + m_ast.CompleteTagDecl(tag_decl); +} + +void ClangExternalASTSourceCallbacks::CompleteType( + clang::ObjCInterfaceDecl *objc_decl) { + m_ast.CompleteObjCInterfaceDecl(objc_decl); +} + +bool ClangExternalASTSourceCallbacks::layoutRecordType( + const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &VirtualBaseOffsets) { + return m_ast.LayoutRecordType(Record, Size, Alignment, FieldOffsets, + BaseOffsets, VirtualBaseOffsets); +} + +void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls( + const clang::DeclContext *decl_ctx, + llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant, + llvm::SmallVectorImpl<clang::Decl *> &decls) { + if (decl_ctx) { + clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>( + const_cast<clang::DeclContext *>(decl_ctx)); + if (tag_decl) + CompleteType(tag_decl); + } +} + +bool ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName( + const clang::DeclContext *DC, clang::DeclarationName Name) { + llvm::SmallVector<clang::NamedDecl *, 4> decls; + // Objective-C methods are not added into the LookupPtr when they originate + // from an external source. SetExternalVisibleDeclsForName() adds them. + if (auto *oid = llvm::dyn_cast<clang::ObjCInterfaceDecl>(DC)) { + clang::ObjCContainerDecl::method_range noload_methods(oid->noload_decls()); + for (auto *omd : noload_methods) + if (omd->getDeclName() == Name) + decls.push_back(omd); + } + return !SetExternalVisibleDeclsForName(DC, Name, decls).empty(); +} + +OptionalClangModuleID +ClangExternalASTSourceCallbacks::RegisterModule(clang::Module *module) { + m_modules.push_back(module); + unsigned id = m_modules.size(); + m_ids.insert({module, id}); + return OptionalClangModuleID(id); +} + +llvm::Optional<clang::ASTSourceDescriptor> +ClangExternalASTSourceCallbacks::getSourceDescriptor(unsigned id) { + if (clang::Module *module = getModule(id)) + return {*module}; + return {}; +} + +clang::Module *ClangExternalASTSourceCallbacks::getModule(unsigned id) { + if (id && id <= m_modules.size()) + return m_modules[id - 1]; + return nullptr; +} + +OptionalClangModuleID +ClangExternalASTSourceCallbacks::GetIDForModule(clang::Module *module) { + return OptionalClangModuleID(m_ids[module]); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h new file mode 100644 index 000000000000..69088d9c82a5 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h @@ -0,0 +1,66 @@ +//===-- ClangExternalASTSourceCallbacks.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_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H + +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "clang/Basic/Module.h" + +namespace lldb_private { + +class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { + /// LLVM RTTI support. + static char ID; + +public: + /// LLVM RTTI support. + bool isA(const void *ClassID) const override { return ClassID == &ID; } + static bool classof(const clang::ExternalASTSource *s) { return s->isA(&ID); } + + ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {} + + void FindExternalLexicalDecls( + const clang::DeclContext *DC, + llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant, + llvm::SmallVectorImpl<clang::Decl *> &Result) override; + + bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC, + clang::DeclarationName Name) override; + + void CompleteType(clang::TagDecl *tag_decl) override; + + void CompleteType(clang::ObjCInterfaceDecl *objc_decl) override; + + bool layoutRecordType( + const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &BaseOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &VirtualBaseOffsets) override; + + TypeSystemClang &GetTypeSystem() const { return m_ast; } + + /// Module-related methods. + /// \{ + llvm::Optional<clang::ASTSourceDescriptor> + getSourceDescriptor(unsigned ID) override; + clang::Module *getModule(unsigned ID) override; + OptionalClangModuleID RegisterModule(clang::Module *module); + OptionalClangModuleID GetIDForModule(clang::Module *module); + /// \} +private: + TypeSystemClang &m_ast; + std::vector<clang::Module *> m_modules; + llvm::DenseMap<clang::Module *, unsigned> m_ids; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 7f7c0a97f538..0c9ad2021035 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -1,4 +1,4 @@ -//===-- ClangFunctionCaller.cpp ---------------------------------*- C++ -*-===// +//===-- ClangFunctionCaller.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -21,12 +21,12 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/IR/Module.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ExecutionContext.h" @@ -209,8 +209,8 @@ ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp, clang::ASTConsumer * ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer( clang::ASTConsumer *passthrough) { - m_struct_extractor.reset(new ASTStructExtractor( - passthrough, m_owner.GetWrapperStructName(), m_owner)); + m_struct_extractor = std::make_unique<ASTStructExtractor>( + passthrough, m_owner.GetWrapperStructName(), m_owner); return m_struct_extractor.get(); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h index 150a913152d0..8060b8c0aedc 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h @@ -6,13 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangFunctionCaller_h_ -#define liblldb_ClangFunctionCaller_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H #include "ClangExpressionHelper.h" #include "lldb/Core/Address.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/FunctionCaller.h" @@ -150,4 +149,4 @@ private: } // namespace lldb_private -#endif // liblldb_ClangFunctionCaller_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 42d3f22014dd..8abb7e420575 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -1,4 +1,4 @@ -//===-- ClangHost.cpp -------------------------------------------*- C++ -*-===// +//===-- ClangHost.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -67,10 +67,10 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, llvm::sys::path::native(relative_path); llvm::sys::path::append(clang_dir, relative_path); if (!verify || VerifyClangPath(clang_dir)) { - LLDB_LOGF(log, - "DefaultComputeClangResourceDir: Setting ClangResourceDir " - "to \"%s\", verify = %s", - clang_dir.str().str().c_str(), verify ? "true" : "false"); + LLDB_LOG(log, + "DefaultComputeClangResourceDir: Setting ClangResourceDir " + "to \"{0}\", verify = {1}", + clang_dir.str(), verify ? "true" : "false"); file_spec.GetDirectory().SetString(clang_dir); FileSystem::Instance().Resolve(file_spec); return true; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h index 9d49188178cd..d6809909a625 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H -#define LLDB_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H namespace lldb_private { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 0696c669f2e2..95acb883774d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -1,4 +1,4 @@ -//===-- ClangModulesDeclVendor.cpp ------------------------------*- C++ -*-===// +//===-- ClangModulesDeclVendor.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,11 +6,10 @@ // //===----------------------------------------------------------------------===// -#include <mutex> - #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Parse/Parser.h" @@ -24,10 +23,10 @@ #include "ClangModulesDeclVendor.h" #include "ModuleDependencyCollector.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ModuleList.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Target.h" @@ -37,6 +36,9 @@ #include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" +#include <memory> +#include <mutex> + using namespace lldb_private; namespace { @@ -54,10 +56,21 @@ public: void DumpDiagnostics(Stream &error_stream); + void BeginSourceFile(const clang::LangOptions &LangOpts, + const clang::Preprocessor *PP = nullptr) override; + void EndSourceFile() override; + private: typedef std::pair<clang::DiagnosticsEngine::Level, std::string> IDAndDiagnostic; std::vector<IDAndDiagnostic> m_diagnostics; + /// The DiagnosticPrinter used for creating the full diagnostic messages + /// that are stored in m_diagnostics. + std::shared_ptr<clang::TextDiagnosticPrinter> m_diag_printer; + /// Output stream of m_diag_printer. + std::shared_ptr<llvm::raw_string_ostream> m_os; + /// Output string filled by m_os. Will be reused for different diagnostics. + std::string m_output; Log *m_log; }; @@ -108,25 +121,30 @@ private: typedef std::set<ModuleID> ImportedModuleSet; ImportedModuleMap m_imported_modules; ImportedModuleSet m_user_imported_modules; - // We assume that every ASTContext has an ClangASTContext, so we also store - // a custom ClangASTContext for our internal ASTContext. - std::unique_ptr<ClangASTContext> m_ast_context; + // We assume that every ASTContext has an TypeSystemClang, so we also store + // a custom TypeSystemClang for our internal ASTContext. + std::unique_ptr<TypeSystemClang> m_ast_context; }; } // anonymous namespace StoringDiagnosticConsumer::StoringDiagnosticConsumer() { m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + clang::DiagnosticOptions *m_options = new clang::DiagnosticOptions(); + m_os = std::make_shared<llvm::raw_string_ostream>(m_output); + m_diag_printer = + std::make_shared<clang::TextDiagnosticPrinter>(*m_os, m_options); } void StoringDiagnosticConsumer::HandleDiagnostic( clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info) { - llvm::SmallVector<char, 256> diagnostic_string; + // Print the diagnostic to m_output. + m_output.clear(); + m_diag_printer->HandleDiagnostic(DiagLevel, info); + m_os->flush(); - info.FormatDiagnostic(diagnostic_string); - - m_diagnostics.push_back( - IDAndDiagnostic(DiagLevel, std::string(diagnostic_string.data(), - diagnostic_string.size()))); + // Store the diagnostic for later. + m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, m_output)); } void StoringDiagnosticConsumer::ClearDiagnostics() { m_diagnostics.clear(); } @@ -144,6 +162,15 @@ void StoringDiagnosticConsumer::DumpDiagnostics(Stream &error_stream) { } } +void StoringDiagnosticConsumer::BeginSourceFile( + const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) { + m_diag_printer->BeginSourceFile(LangOpts, PP); +} + +void StoringDiagnosticConsumer::EndSourceFile() { + m_diag_printer->EndSourceFile(); +} + ClangModulesDeclVendor::ClangModulesDeclVendor() : ClangDeclVendor(eClangModuleDeclVendor) {} @@ -159,8 +186,10 @@ ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl( m_compiler_instance(std::move(compiler_instance)), m_parser(std::move(parser)) { - // Initialize our ClangASTContext. - m_ast_context.reset(new ClangASTContext(m_compiler_instance->getASTContext())); + // Initialize our TypeSystemClang. + m_ast_context = + std::make_unique<TypeSystemClang>("ClangModulesDeclVendor ASTContext", + m_compiler_instance->getASTContext()); } void ClangModulesDeclVendorImpl::ReportModuleExportsHelper( @@ -382,7 +411,7 @@ ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, if (num_matches >= max_matches) return num_matches; - decls.push_back(CompilerDecl(m_ast_context.get(), named_decl)); + decls.push_back(m_ast_context->GetCompilerDecl(named_decl)); ++num_matches; } @@ -601,10 +630,10 @@ ClangModulesDeclVendor::Create(Target &target) { { llvm::SmallString<128> path; - auto props = ModuleList::GetGlobalModuleListProperties(); + const auto &props = ModuleList::GetGlobalModuleListProperties(); props.GetClangModulesCachePath().GetPath(path); std::string module_cache_argument("-fmodules-cache-path="); - module_cache_argument.append(path.str()); + module_cache_argument.append(std::string(path.str())); compiler_invocation_arguments.push_back(module_cache_argument); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h index e099b59041d8..f04d1b07f03d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h @@ -6,10 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangModulesDeclVendor_h -#define liblldb_ClangModulesDeclVendor_h +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H -#include "lldb/Core/ClangForward.h" #include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Platform.h" @@ -113,4 +112,4 @@ public: } // namespace lldb_private -#endif // liblldb_ClangModulesDeclVendor_h +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 41d62a462ab4..42afac9edb0d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -1,4 +1,4 @@ -//===-- ClangPersistentVariables.cpp ----------------------------*- C++ -*-===// +//===-- ClangPersistentVariables.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,9 +7,10 @@ //===----------------------------------------------------------------------===// #include "ClangPersistentVariables.h" +#include "ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Value.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" @@ -82,7 +83,7 @@ ClangPersistentVariables::GetCompilerTypeFromPersistentDecl( void ClangPersistentVariables::RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl, - ClangASTContext *ctx) { + TypeSystemClang *ctx) { PersistentDecl p = {decl, ctx}; m_persistent_decls.insert(std::make_pair(name.GetCString(), p)); @@ -99,3 +100,22 @@ clang::NamedDecl * ClangPersistentVariables::GetPersistentDecl(ConstString name) { return m_persistent_decls.lookup(name.GetCString()).m_decl; } + +std::shared_ptr<ClangASTImporter> +ClangPersistentVariables::GetClangASTImporter() { + if (!m_ast_importer_sp) { + m_ast_importer_sp = std::make_shared<ClangASTImporter>(); + } + return m_ast_importer_sp; +} + +ConstString +ClangPersistentVariables::GetNextPersistentVariableName(bool is_error) { + llvm::SmallString<64> name; + { + llvm::raw_svector_ostream os(name); + os << GetPersistentVariablePrefix(is_error) + << m_next_persistent_variable_id++; + } + return ConstString(name); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 434196b35fd5..f888b2d56e68 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangPersistentVariables_h_ -#define liblldb_ClangPersistentVariables_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H #include "llvm/ADT/DenseMap.h" @@ -18,6 +18,9 @@ namespace lldb_private { +class ClangASTImporter; +class TypeSystemClang; + /// \class ClangPersistentVariables ClangPersistentVariables.h /// "lldb/Expression/ClangPersistentVariables.h" Manages persistent values /// that need to be preserved between expression invocations. @@ -36,6 +39,8 @@ public: return pv->getKind() == PersistentExpressionState::eKindClang; } + std::shared_ptr<ClangASTImporter> GetClangASTImporter(); + lldb::ExpressionVariableSP CreatePersistentVariable(const lldb::ValueObjectSP &valobj_sp) override; @@ -46,9 +51,7 @@ public: void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; - llvm::StringRef GetPersistentVariablePrefix(bool is_error) const override { - return "$"; - } + ConstString GetNextPersistentVariableName(bool is_error = false) override; /// Returns the next file name that should be used for user expressions. std::string GetNextExprFileName() { @@ -63,7 +66,7 @@ public: GetCompilerTypeFromPersistentDecl(ConstString type_name) override; void RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl, - ClangASTContext *ctx); + TypeSystemClang *ctx); clang::NamedDecl *GetPersistentDecl(ConstString name); @@ -75,6 +78,12 @@ public: return m_hand_loaded_clang_modules; } +protected: + llvm::StringRef + GetPersistentVariablePrefix(bool is_error = false) const override { + return "$"; + } + private: /// The counter used by GetNextExprFileName. uint32_t m_next_user_file_id = 0; @@ -84,8 +93,8 @@ private: struct PersistentDecl { /// The persistent decl. clang::NamedDecl *m_decl = nullptr; - /// The ClangASTContext for the ASTContext of m_decl. - ClangASTContext *m_context = nullptr; + /// The TypeSystemClang for the ASTContext of m_decl. + TypeSystemClang *m_context = nullptr; }; typedef llvm::DenseMap<const char *, PersistentDecl> PersistentDeclMap; @@ -96,8 +105,9 @@ private: m_hand_loaded_clang_modules; ///< These are Clang modules we hand-loaded; ///these are the highest- ///< priority source for macros. + std::shared_ptr<ClangASTImporter> m_ast_importer_sp; }; } // namespace lldb_private -#endif // liblldb_ClangPersistentVariables_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 6698797617a3..a28b4a7fb42c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -1,4 +1,4 @@ -//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===// +//===-- ClangUserExpression.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -20,6 +20,7 @@ #include "ClangUserExpression.h" #include "ASTResultSynthesizer.h" +#include "ClangASTMetadata.h" #include "ClangDiagnostic.h" #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" @@ -27,6 +28,7 @@ #include "ClangPersistentVariables.h" #include "CppModuleConfiguration.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" @@ -37,8 +39,6 @@ #include "lldb/Expression/Materializer.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" @@ -154,7 +154,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { } m_needs_object_ptr = true; } else if (clang::CXXMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsCXXMethodDecl(decl_context)) { + TypeSystemClang::DeclContextGetAsCXXMethodDecl(decl_context)) { if (m_allow_cxx && method_decl->isInstance()) { if (m_enforce_valid_object) { lldb::VariableListSP variable_list_sp( @@ -183,7 +183,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { m_needs_object_ptr = true; } } else if (clang::ObjCMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsObjCMethodDecl( + TypeSystemClang::DeclContextGetAsObjCMethodDecl( decl_context)) { if (m_allow_objc) { if (m_enforce_valid_object) { @@ -216,7 +216,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { m_in_static_method = true; } } else if (clang::FunctionDecl *function_decl = - ClangASTContext::DeclContextGetAsFunctionDecl(decl_context)) { + TypeSystemClang::DeclContextGetAsFunctionDecl(decl_context)) { // We might also have a function that said in the debug information that it // captured an object pointer. The best way to deal with getting to the // ivars at present is by pretending that this is a method of a class in @@ -224,7 +224,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { // that here. ClangASTMetadata *metadata = - ClangASTContext::DeclContextGetMetaData(decl_context, function_decl); + TypeSystemClang::DeclContextGetMetaData(decl_context, function_decl); if (metadata && metadata->HasObjectPtr()) { lldb::LanguageType language = metadata->GetObjectPtrLanguage(); if (language == lldb::eLanguageTypeC_plus_plus) { @@ -292,9 +292,9 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { return; } - if (ClangASTContext::IsObjCClassType(self_clang_type)) { + if (TypeSystemClang::IsObjCClassType(self_clang_type)) { return; - } else if (ClangASTContext::IsObjCObjectPointerType( + } else if (TypeSystemClang::IsObjCObjectPointerType( self_clang_type)) { m_in_objectivec_method = true; m_needs_object_ptr = true; @@ -347,50 +347,70 @@ bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_man return true; } -static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) { - if (ClangModulesDeclVendor *decl_vendor = - target->GetClangModulesDeclVendor()) { - auto *persistent_state = llvm::cast<ClangPersistentVariables>( - target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); - if (!persistent_state) - return; - const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = - persistent_state->GetHandLoadedClangModules(); - ClangModulesDeclVendor::ModuleVector modules_for_macros; +static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target, + DiagnosticManager &diagnostic_manager) { + ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor(); + if (!decl_vendor) + return; - for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) { - modules_for_macros.push_back(module); - } + if (!target->GetEnableAutoImportClangModules()) + return; - if (target->GetEnableAutoImportClangModules()) { - if (StackFrame *frame = exe_ctx.GetFramePtr()) { - if (Block *block = frame->GetFrameBlock()) { - SymbolContext sc; + auto *persistent_state = llvm::cast<ClangPersistentVariables>( + target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); + if (!persistent_state) + return; - block->CalculateSymbolContext(&sc); + StackFrame *frame = exe_ctx.GetFramePtr(); + if (!frame) + return; - if (sc.comp_unit) { - StreamString error_stream; + Block *block = frame->GetFrameBlock(); + if (!block) + return; + SymbolContext sc; - decl_vendor->AddModulesForCompileUnit( - *sc.comp_unit, modules_for_macros, error_stream); - } - } - } - } + block->CalculateSymbolContext(&sc); + + if (!sc.comp_unit) + return; + StreamString error_stream; + + ClangModulesDeclVendor::ModuleVector modules_for_macros = + persistent_state->GetHandLoadedClangModules(); + if (decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros, + error_stream)) + return; + + // Failed to load some modules, so emit the error stream as a diagnostic. + if (!error_stream.Empty()) { + // The error stream already contains several Clang diagnostics that might + // be either errors or warnings, so just print them all as one remark + // diagnostic to prevent that the message starts with "error: error:". + diagnostic_manager.PutString(eDiagnosticSeverityRemark, + error_stream.GetString()); + return; } + + diagnostic_manager.PutString(eDiagnosticSeverityError, + "Unknown error while loading modules needed for " + "current compilation unit."); } -void ClangUserExpression::UpdateLanguageForExpr() { - m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown; - if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) - return; +ClangExpressionSourceCode::WrapKind ClangUserExpression::GetWrapKind() const { + assert(m_options.GetExecutionPolicy() != eExecutionPolicyTopLevel && + "Top level expressions aren't wrapped."); + using Kind = ClangExpressionSourceCode::WrapKind; if (m_in_cplusplus_method) - m_expr_lang = lldb::eLanguageTypeC_plus_plus; - else if (m_in_objectivec_method) - m_expr_lang = lldb::eLanguageTypeObjC; - else - m_expr_lang = lldb::eLanguageTypeC; + return Kind::CppMemberFunction; + else if (m_in_objectivec_method) { + if (m_in_static_method) + return Kind::ObjCStaticMethod; + return Kind::ObjCInstanceMethod; + } + // Not in any kind of 'special' function, so just wrap it in a normal C + // function. + return Kind::Function; } void ClangUserExpression::CreateSourceCode( @@ -404,10 +424,9 @@ void ClangUserExpression::CreateSourceCode( m_transformed_text = m_expr_text; } else { m_source_code.reset(ClangExpressionSourceCode::CreateWrapped( - m_filename, prefix.c_str(), m_expr_text.c_str())); + m_filename, prefix, m_expr_text, GetWrapKind())); - if (!m_source_code->GetText(m_transformed_text, m_expr_lang, - m_in_static_method, exe_ctx, !m_ctx_obj, + if (!m_source_code->GetText(m_transformed_text, exe_ctx, !m_ctx_obj, for_completion, modules_to_import)) { diagnostic_manager.PutString(eDiagnosticSeverityError, "couldn't construct expression body"); @@ -419,7 +438,7 @@ void ClangUserExpression::CreateSourceCode( std::size_t original_start; std::size_t original_end; bool found_bounds = m_source_code->GetOriginalBodyBounds( - m_transformed_text, m_expr_lang, original_start, original_end); + m_transformed_text, original_start, original_end); if (found_bounds) m_user_expression_start_pos = original_start; } @@ -530,7 +549,7 @@ bool ClangUserExpression::PrepareForParsing( ApplyObjcCastHack(m_expr_text); - SetupDeclVendor(exe_ctx, m_target); + SetupDeclVendor(exe_ctx, m_target, diagnostic_manager); CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); llvm::ArrayRef<std::string> imported_modules = @@ -544,7 +563,6 @@ bool ClangUserExpression::PrepareForParsing( llvm::make_range(m_include_directories.begin(), m_include_directories.end())); - UpdateLanguageForExpr(); CreateSourceCode(diagnostic_manager, exe_ctx, imported_modules, for_completion); return true; @@ -577,7 +595,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // Parse the expression // - m_materializer_up.reset(new Materializer()); + m_materializer_up = std::make_unique<Materializer>(); ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory); @@ -616,15 +634,13 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, if (parser.RewriteExpression(diagnostic_manager)) { size_t fixed_start; size_t fixed_end; - const std::string &fixed_expression = - diagnostic_manager.GetFixedExpression(); + m_fixed_text = diagnostic_manager.GetFixedExpression(); // Retrieve the original expression in case we don't have a top level // expression (which has no surrounding source code). - if (m_source_code && - m_source_code->GetOriginalBodyBounds(fixed_expression, m_expr_lang, - fixed_start, fixed_end)) + if (m_source_code && m_source_code->GetOriginalBodyBounds( + m_fixed_text, fixed_start, fixed_end)) m_fixed_text = - fixed_expression.substr(fixed_start, fixed_end - fixed_start); + m_fixed_text.substr(fixed_start, fixed_end - fixed_start); } } return false; @@ -659,7 +675,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, const char *error_cstr = static_init_error.AsCString(); if (error_cstr && error_cstr[0]) diagnostic_manager.Printf(eDiagnosticSeverityError, - "couldn't run static initializers: %s\n", + "%s\n", error_cstr); else diagnostic_manager.PutString(eDiagnosticSeverityError, @@ -767,7 +783,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, // Parse the expression // - m_materializer_up.reset(new Materializer()); + m_materializer_up = std::make_unique<Materializer>(); ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true); @@ -896,16 +912,23 @@ void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap( Materializer::PersistentVariableDelegate &delegate, bool keep_result_in_memory, ValueObject *ctx_obj) { - m_expr_decl_map_up.reset(new ClangExpressionDeclMap( - keep_result_in_memory, &delegate, exe_ctx.GetTargetSP(), - exe_ctx.GetTargetRef().GetClangASTImporter(), ctx_obj)); + std::shared_ptr<ClangASTImporter> ast_importer; + auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage( + lldb::eLanguageTypeC); + if (state) { + auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); + ast_importer = persistent_vars->GetClangASTImporter(); + } + m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>( + keep_result_in_memory, &delegate, exe_ctx.GetTargetSP(), ast_importer, + ctx_obj); } clang::ASTConsumer * ClangUserExpression::ClangUserExpressionHelper::ASTTransformer( clang::ASTConsumer *passthrough) { - m_result_synthesizer_up.reset( - new ASTResultSynthesizer(passthrough, m_top_level, m_target)); + m_result_synthesizer_up = std::make_unique<ASTResultSynthesizer>( + passthrough, m_top_level, m_target); return m_result_synthesizer_up.get(); } @@ -917,9 +940,7 @@ void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() { } ConstString ClangUserExpression::ResultDelegate::GetName() { - auto prefix = m_persistent_state->GetPersistentVariablePrefix(); - return m_persistent_state->GetNextPersistentVariableName(*m_target_sp, - prefix); + return m_persistent_state->GetNextPersistentVariableName(false); } void ClangUserExpression::ResultDelegate::DidDematerialize( diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index 00cbffa7fd6f..f734069655ef 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangUserExpression_h_ -#define liblldb_ClangUserExpression_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H #include <vector> @@ -20,7 +20,6 @@ #include "IRForTarget.h" #include "lldb/Core/Address.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Expression/LLVMUserExpression.h" #include "lldb/Expression/Materializer.h" #include "lldb/Target/ExecutionContext.h" @@ -186,7 +185,8 @@ private: ExecutionContext &exe_ctx, std::vector<std::string> modules_to_import, bool for_completion); - void UpdateLanguageForExpr(); + /// Defines how the current expression should be wrapped. + ClangExpressionSourceCode::WrapKind GetWrapKind() const; bool SetupPersistentState(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx); bool PrepareForParsing(DiagnosticManager &diagnostic_manager, @@ -209,8 +209,6 @@ private: lldb::TargetSP m_target_sp; }; - /// The language type of the current expression. - lldb::LanguageType m_expr_lang = lldb::eLanguageTypeUnknown; /// The include directories that should be used when parsing the expression. std::vector<std::string> m_include_directories; @@ -251,4 +249,4 @@ private: } // namespace lldb_private -#endif // liblldb_ClangUserExpression_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp new file mode 100644 index 000000000000..a7f5dce8558f --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp @@ -0,0 +1,87 @@ +//===-- ClangUtil.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 +// +// A collection of helper methods and data structures for manipulating clang +// types and decls. +//===----------------------------------------------------------------------===// + +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +using namespace clang; +using namespace lldb_private; + +bool ClangUtil::IsClangType(const CompilerType &ct) { + // Invalid types are never Clang types. + if (!ct) + return false; + + if (llvm::dyn_cast_or_null<TypeSystemClang>(ct.GetTypeSystem()) == nullptr) + return false; + + if (!ct.GetOpaqueQualType()) + return false; + + return true; +} + +clang::Decl *ClangUtil::GetDecl(const CompilerDecl &decl) { + assert(llvm::isa<TypeSystemClang>(decl.GetTypeSystem())); + return static_cast<clang::Decl *>(decl.GetOpaqueDecl()); +} + +QualType ClangUtil::GetQualType(const CompilerType &ct) { + // Make sure we have a clang type before making a clang::QualType + if (!IsClangType(ct)) + return QualType(); + + return QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); +} + +QualType ClangUtil::GetCanonicalQualType(const CompilerType &ct) { + if (!IsClangType(ct)) + return QualType(); + + return GetQualType(ct).getCanonicalType(); +} + +CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) { + if (!IsClangType(ct)) + return ct; + + QualType qual_type(GetQualType(ct)); + qual_type.removeLocalFastQualifiers(); + return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr()); +} + +clang::TagDecl *ClangUtil::GetAsTagDecl(const CompilerType &type) { + clang::QualType qual_type = ClangUtil::GetCanonicalQualType(type); + if (qual_type.isNull()) + return nullptr; + + return qual_type->getAsTagDecl(); +} + +std::string ClangUtil::DumpDecl(const clang::Decl *d) { + if (!d) + return "nullptr"; + + std::string result; + llvm::raw_string_ostream stream(result); + bool deserialize = false; + d->dump(stream, deserialize); + + stream.flush(); + return result; +} + +std::string ClangUtil::ToString(const clang::Type *t) { + return clang::QualType(t, 0).getAsString(); +} + +std::string ClangUtil::ToString(const CompilerType &c) { + return ClangUtil::GetQualType(c).getAsString(); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h new file mode 100644 index 000000000000..50cae42bc7c2 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h @@ -0,0 +1,50 @@ +//===-- ClangUtil.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 +// +// A collection of helper methods and data structures for manipulating clang +// types and decls. +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTIL_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTIL_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/Type.h" + +#include "lldb/Symbol/CompilerType.h" + +namespace clang { +class TagDecl; +} + +namespace lldb_private { +struct ClangUtil { + static bool IsClangType(const CompilerType &ct); + + /// Returns the clang::Decl of the given CompilerDecl. + /// CompilerDecl has to be valid and represent a clang::Decl. + static clang::Decl *GetDecl(const CompilerDecl &decl); + + static clang::QualType GetQualType(const CompilerType &ct); + + static clang::QualType GetCanonicalQualType(const CompilerType &ct); + + static CompilerType RemoveFastQualifiers(const CompilerType &ct); + + static clang::TagDecl *GetAsTagDecl(const CompilerType &type); + + /// Returns a textual representation of the given Decl's AST. Does not + /// deserialize any child nodes. + static std::string DumpDecl(const clang::Decl *d); + /// Returns a textual representation of the given type. + static std::string ToString(const clang::Type *t); + /// Returns a textual representation of the given CompilerType (assuming + /// its underlying type is a Clang type). + static std::string ToString(const CompilerType &c); +}; +} + +#endif diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 199e4898e118..25ec982220a0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -1,4 +1,4 @@ -//===-- ClangUtilityFunction.cpp ---------------------------------*- C++-*-===// +//===-- ClangUtilityFunction.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -12,6 +12,7 @@ #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" #include "ClangExpressionSourceCode.h" +#include "ClangPersistentVariables.h" #include <stdio.h> #if HAVE_SYS_TYPES_H @@ -159,7 +160,14 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap( ExecutionContext &exe_ctx, bool keep_result_in_memory) { - m_expr_decl_map_up.reset(new ClangExpressionDeclMap( - keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), - exe_ctx.GetTargetRef().GetClangASTImporter(), nullptr)); + std::shared_ptr<ClangASTImporter> ast_importer; + auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage( + lldb::eLanguageTypeC); + if (state) { + auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); + ast_importer = persistent_vars->GetClangASTImporter(); + } + m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>( + keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer, + nullptr); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index 9efaa0254c3e..1f2dd5fdbecc 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangUtilityFunction_h_ -#define liblldb_ClangUtilityFunction_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H #include <map> #include <string> @@ -15,7 +15,6 @@ #include "ClangExpressionHelper.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Expression/UtilityFunction.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" @@ -107,4 +106,4 @@ private: } // namespace lldb_private -#endif // liblldb_ClangUtilityFunction_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp index 51ae73285b53..f1272c67d20f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp @@ -73,7 +73,7 @@ CppModuleConfiguration::CppModuleConfiguration( llvm::SmallString<256> resource_dir; llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(), "include"); - m_resource_inc = resource_dir.str(); + m_resource_inc = std::string(resource_dir.str()); // This order matches the way Clang orders these directories. m_include_dirs = {m_std_inc.Get(), m_resource_inc, m_c_inc.Get()}; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h index 8e892e37d0de..235ac2bd090c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_CppModuleConfiguration_h_ -#define liblldb_CppModuleConfiguration_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CPPMODULECONFIGURATION_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CPPMODULECONFIGURATION_H #include <lldb/Core/FileSpecList.h> #include <llvm/Support/Regex.h> @@ -56,7 +56,7 @@ class CppModuleConfiguration { bool analyzeFile(const FileSpec &f); public: - /// Creates a configuraiton by analyzing the given list of used source files. + /// Creates a configuration by analyzing the given list of used source files. /// /// Currently only looks at the used paths and doesn't actually access the /// files on the disk. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp new file mode 100644 index 000000000000..2f8cf1846ee7 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp @@ -0,0 +1,289 @@ +//===-- CxxModuleHandler.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 "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +#include "lldb/Utility/Log.h" +#include "clang/Sema/Lookup.h" +#include "llvm/Support/Error.h" + +using namespace lldb_private; +using namespace clang; + +CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) + : m_importer(&importer), + m_sema(TypeSystemClang::GetASTContext(target)->getSema()) { + + std::initializer_list<const char *> supported_names = { + // containers + "deque", + "forward_list", + "list", + "queue", + "stack", + "vector", + // pointers + "shared_ptr", + "unique_ptr", + "weak_ptr", + // utility + "allocator", + }; + m_supported_templates.insert(supported_names.begin(), supported_names.end()); +} + +/// Builds a list of scopes that point into the given context. +/// +/// \param sema The sema that will be using the scopes. +/// \param ctxt The context that the scope should look into. +/// \param result A list of scopes. The scopes need to be freed by the caller +/// (except the TUScope which is owned by the sema). +static void makeScopes(Sema &sema, DeclContext *ctxt, + std::vector<Scope *> &result) { + // FIXME: The result should be a list of unique_ptrs, but the TUScope makes + // this currently impossible as it's owned by the Sema. + + if (auto parent = ctxt->getParent()) { + makeScopes(sema, parent, result); + + Scope *scope = + new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics()); + scope->setEntity(ctxt); + result.push_back(scope); + } else + result.push_back(sema.TUScope); +} + +/// Uses the Sema to look up the given name in the given DeclContext. +static std::unique_ptr<LookupResult> +emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) { + IdentifierInfo &ident = sema.getASTContext().Idents.get(name); + + std::unique_ptr<LookupResult> lookup_result; + lookup_result = std::make_unique<LookupResult>(sema, DeclarationName(&ident), + SourceLocation(), + Sema::LookupOrdinaryName); + + // Usually during parsing we already encountered the scopes we would use. But + // here don't have these scopes so we have to emulate the behavior of the + // Sema during parsing. + std::vector<Scope *> scopes; + makeScopes(sema, ctxt, scopes); + + // Now actually perform the lookup with the sema. + sema.LookupName(*lookup_result, scopes.back()); + + // Delete all the allocated scopes beside the translation unit scope (which + // has depth 0). + for (Scope *s : scopes) + if (s->getDepth() != 0) + delete s; + + return lookup_result; +} + +/// Error class for handling problems when finding a certain DeclContext. +struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> { + + static char ID; + + MissingDeclContext(DeclContext *context, std::string error) + : m_context(context), m_error(error) {} + + DeclContext *m_context; + std::string m_error; + + void log(llvm::raw_ostream &OS) const override { + OS << llvm::formatv("error when reconstructing context of kind {0}:{1}", + m_context->getDeclKindName(), m_error); + } + + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } +}; + +char MissingDeclContext::ID = 0; + +/// Given a foreign decl context, this function finds the equivalent local +/// decl context in the ASTContext of the given Sema. Potentially deserializes +/// decls from the 'std' module if necessary. +static llvm::Expected<DeclContext *> +getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) { + + // Inline namespaces don't matter for lookups, so let's skip them. + while (foreign_ctxt && foreign_ctxt->isInlineNamespace()) + foreign_ctxt = foreign_ctxt->getParent(); + + // If the foreign context is the TU, we just return the local TU. + if (foreign_ctxt->isTranslationUnit()) + return sema.getASTContext().getTranslationUnitDecl(); + + // Recursively find/build the parent DeclContext. + llvm::Expected<DeclContext *> parent = + getEqualLocalDeclContext(sema, foreign_ctxt->getParent()); + if (!parent) + return parent; + + // We currently only support building namespaces. + if (foreign_ctxt->isNamespace()) { + NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt); + llvm::StringRef ns_name = ns->getName(); + + auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent); + for (NamedDecl *named_decl : *lookup_result) { + if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl)) + return DC->getPrimaryContext(); + } + return llvm::make_error<MissingDeclContext>( + foreign_ctxt, + "Couldn't find namespace " + ns->getQualifiedNameAsString()); + } + + return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context "); +} + +/// Returns true iff tryInstantiateStdTemplate supports instantiating a template +/// with the given template arguments. +static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) { + for (const TemplateArgument &arg : a) { + switch (arg.getKind()) { + case TemplateArgument::Type: + case TemplateArgument::Integral: + break; + default: + // TemplateArgument kind hasn't been handled yet. + return false; + } + } + return true; +} + +/// Constructor function for Clang declarations. Ensures that the created +/// declaration is registered with the ASTImporter. +template <typename T, typename... Args> +T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) { + T *to_d = T::Create(std::forward<Args>(args)...); + importer.RegisterImportedDecl(from_d, to_d); + return to_d; +} + +llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + // If we don't have a template to instiantiate, then there is nothing to do. + auto td = dyn_cast<ClassTemplateSpecializationDecl>(d); + if (!td) + return {}; + + // We only care about templates in the std namespace. + if (!td->getDeclContext()->isStdNamespace()) + return {}; + + // We have a list of supported template names. + if (m_supported_templates.find(td->getName()) == m_supported_templates.end()) + return {}; + + // Early check if we even support instantiating this template. We do this + // before we import anything into the target AST. + auto &foreign_args = td->getTemplateInstantiationArgs(); + if (!templateArgsAreSupported(foreign_args.asArray())) + return {}; + + // Find the local DeclContext that corresponds to the DeclContext of our + // decl we want to import. + llvm::Expected<DeclContext *> to_context = + getEqualLocalDeclContext(*m_sema, td->getDeclContext()); + if (!to_context) { + LLDB_LOG_ERROR(log, to_context.takeError(), + "Got error while searching equal local DeclContext for decl " + "'{1}':\n{0}", + td->getName()); + return {}; + } + + // Look up the template in our local context. + std::unique_ptr<LookupResult> lookup = + emulateLookupInCtxt(*m_sema, td->getName(), *to_context); + + ClassTemplateDecl *new_class_template = nullptr; + for (auto LD : *lookup) { + if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD))) + break; + } + if (!new_class_template) + return {}; + + // Import the foreign template arguments. + llvm::SmallVector<TemplateArgument, 4> imported_args; + + // If this logic is changed, also update templateArgsAreSupported. + for (const TemplateArgument &arg : foreign_args.asArray()) { + switch (arg.getKind()) { + case TemplateArgument::Type: { + llvm::Expected<QualType> type = m_importer->Import(arg.getAsType()); + if (!type) { + LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); + return {}; + } + imported_args.push_back(TemplateArgument(*type)); + break; + } + case TemplateArgument::Integral: { + llvm::APSInt integral = arg.getAsIntegral(); + llvm::Expected<QualType> type = + m_importer->Import(arg.getIntegralType()); + if (!type) { + LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); + return {}; + } + imported_args.push_back( + TemplateArgument(d->getASTContext(), integral, *type)); + break; + } + default: + assert(false && "templateArgsAreSupported not updated?"); + } + } + + // Find the class template specialization declaration that + // corresponds to these arguments. + void *InsertPos = nullptr; + ClassTemplateSpecializationDecl *result = + new_class_template->findSpecialization(imported_args, InsertPos); + + if (result) { + // We found an existing specialization in the module that fits our arguments + // so we can treat it as the result and register it with the ASTImporter. + m_importer->RegisterImportedDecl(d, result); + return result; + } + + // Instantiate the template. + result = createDecl<ClassTemplateSpecializationDecl>( + *m_importer, d, m_sema->getASTContext(), + new_class_template->getTemplatedDecl()->getTagKind(), + new_class_template->getDeclContext(), + new_class_template->getTemplatedDecl()->getLocation(), + new_class_template->getLocation(), new_class_template, imported_args, + nullptr); + + new_class_template->AddSpecialization(result, InsertPos); + if (new_class_template->isOutOfLine()) + result->setLexicalDeclContext( + new_class_template->getLexicalDeclContext()); + return result; +} + +llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) { + if (!isValid()) + return {}; + + return tryInstantiateStdTemplate(d); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h new file mode 100644 index 000000000000..6490af7f8978 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h @@ -0,0 +1,65 @@ +//===-- CxxModuleHandler.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_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H + +#include "clang/AST/ASTImporter.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/StringSet.h" + +namespace lldb_private { + +/// Handles importing decls into an ASTContext with an attached C++ module. +/// +/// This class searches a C++ module (which must be attached to the target +/// ASTContext) for an equivalent decl to the one that should be imported. +/// If the decl that is found in the module is a suitable replacement +/// for the decl that should be imported, the module decl will be treated as +/// the result of the import process. +/// +/// If the Decl that should be imported is a template specialization +/// that doesn't exist yet in the target ASTContext (e.g. `std::vector<int>`), +/// then this class tries to create the template specialization in the target +/// ASTContext. This is only possible if the CxxModuleHandler can determine +/// that instantiating this template is safe to do, e.g. because the target +/// decl is a container class from the STL. +class CxxModuleHandler { + /// The ASTImporter that should be used to import any Decls which aren't + /// directly handled by this class itself. + clang::ASTImporter *m_importer = nullptr; + + /// The Sema instance of the target ASTContext. + clang::Sema *m_sema = nullptr; + + /// List of template names this class currently supports. These are the + /// template names inside the 'std' namespace such as 'vector' or 'list'. + llvm::StringSet<> m_supported_templates; + + /// Tries to manually instantiate the given foreign template in the target + /// context (designated by m_sema). + llvm::Optional<clang::Decl *> tryInstantiateStdTemplate(clang::Decl *d); + +public: + CxxModuleHandler() = default; + CxxModuleHandler(clang::ASTImporter &importer, clang::ASTContext *target); + + /// Attempts to import the given decl into the target ASTContext by + /// deserializing it from the 'std' module. This function returns a Decl if a + /// Decl has been deserialized from the 'std' module. Otherwise this function + /// returns nothing. + llvm::Optional<clang::Decl *> Import(clang::Decl *d); + + /// Returns true iff this instance is capable of importing any declarations + /// in the target ASTContext. + bool isValid() const { return m_sema != nullptr; } +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp index d5ffb9529f36..b92f00ec2b63 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp @@ -1,4 +1,4 @@ -//===-- IRDynamicChecks.cpp -------------------------------------*- C++ -*-===// +//===-- IRDynamicChecks.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -181,8 +181,8 @@ protected: /// /// \param[in] inst /// The instruction to be instrumented. - void RegisterInstruction(llvm::Instruction &i) { - m_to_instrument.push_back(&i); + void RegisterInstruction(llvm::Instruction &inst) { + m_to_instrument.push_back(&inst); } /// Determine whether a single instruction is interesting to instrument, @@ -465,7 +465,7 @@ protected: } static llvm::Function *GetCalledFunction(llvm::CallInst *inst) { - return GetFunction(inst->getCalledValue()); + return GetFunction(inst->getCalledOperand()); } bool InspectInstruction(llvm::Instruction &i) override { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h index 5b9c8007ab76..a4de527e4512 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_IRDynamicChecks_h_ -#define liblldb_IRDynamicChecks_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRDYNAMICCHECKS_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRDYNAMICCHECKS_H #include "lldb/Expression/DynamicCheckerFunctions.h" #include "lldb/lldb-types.h" @@ -124,4 +124,4 @@ private: } // namespace lldb_private -#endif // liblldb_IRDynamicChecks_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRDYNAMICCHECKS_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 103a7ee46f35..8511e554509a 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -1,4 +1,4 @@ -//===-- IRForTarget.cpp -----------------------------------------*- C++ -*-===// +//===-- IRForTarget.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,7 +9,9 @@ #include "IRForTarget.h" #include "ClangExpressionDeclMap.h" +#include "ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InstrTypes.h" @@ -27,8 +29,6 @@ #include "lldb/Core/dwarf.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataBufferHeap.h" @@ -283,17 +283,13 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { clang::QualType element_qual_type = pointer_pointertype->getPointeeType(); m_result_type = lldb_private::TypeFromParser( - element_qual_type.getAsOpaquePtr(), - lldb_private::ClangASTContext::GetASTContext( - &result_decl->getASTContext())); + m_decl_map->GetTypeSystem()->GetType(element_qual_type)); } else if (pointer_objcobjpointertype) { clang::QualType element_qual_type = clang::QualType(pointer_objcobjpointertype->getObjectType(), 0); m_result_type = lldb_private::TypeFromParser( - element_qual_type.getAsOpaquePtr(), - lldb_private::ClangASTContext::GetASTContext( - &result_decl->getASTContext())); + m_decl_map->GetTypeSystem()->GetType(element_qual_type)); } else { LLDB_LOG(log, "Expected result to have pointer type, but it did not"); @@ -305,9 +301,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { } } else { m_result_type = lldb_private::TypeFromParser( - result_var->getType().getAsOpaquePtr(), - lldb_private::ClangASTContext::GetASTContext( - &result_decl->getASTContext())); + m_decl_map->GetTypeSystem()->GetType(result_var->getType())); } lldb::TargetSP target_sp(m_execution_unit.GetTarget()); @@ -433,7 +427,7 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str, m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str, missing_weak); if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS || missing_weak) { - log->PutCString("Couldn't find CFStringCreateWithBytes in the target"); + LLDB_LOG(log, "Couldn't find CFStringCreateWithBytes in the target"); m_error_stream.Printf("Error [IRForTarget]: Rewriting an Objective-C " "constant string requires " @@ -823,7 +817,8 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) { if (!omvn_initializer_array->isString()) return false; - std::string omvn_initializer_string = omvn_initializer_array->getAsString(); + std::string omvn_initializer_string = + std::string(omvn_initializer_array->getAsString()); LLDB_LOG(log, "Found Objective-C selector reference \"{0}\"", omvn_initializer_string); @@ -981,7 +976,8 @@ bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) { if (!ocn_initializer_array->isString()) return false; - std::string ocn_initializer_string = ocn_initializer_array->getAsString(); + std::string ocn_initializer_string = + std::string(ocn_initializer_array->getAsString()); LLDB_LOG(log, "Found Objective-C class reference \"{0}\"", ocn_initializer_string); @@ -1092,8 +1088,7 @@ bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) { clang::VarDecl *decl = reinterpret_cast<clang::VarDecl *>(ptr); lldb_private::TypeFromParser result_decl_type( - decl->getType().getAsOpaquePtr(), - lldb_private::ClangASTContext::GetASTContext(&decl->getASTContext())); + m_decl_map->GetTypeSystem()->GetType(decl->getType())); StringRef decl_name(decl->getName()); lldb_private::ConstString persistent_variable_name(decl_name.data(), @@ -1125,7 +1120,9 @@ bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) { // Now, since the variable is a pointer variable, we will drop in a load of // that pointer variable. - LoadInst *persistent_load = new LoadInst(persistent_global, "", alloc); + LoadInst *persistent_load = + new LoadInst(persistent_global->getType()->getPointerElementType(), + persistent_global, "", alloc); LLDB_LOG(log, "Replacing \"{0}\" with \"{1}\"", PrintValue(alloc), PrintValue(persistent_load)); @@ -1223,10 +1220,8 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { if (value_decl == nullptr) return false; - lldb_private::CompilerType compiler_type( - lldb_private::ClangASTContext::GetASTContext( - &value_decl->getASTContext()), - value_decl->getType().getAsOpaquePtr()); + lldb_private::CompilerType compiler_type = + m_decl_map->GetTypeSystem()->GetType(value_decl->getType()); const Type *value_type = nullptr; @@ -1400,7 +1395,7 @@ bool IRForTarget::RemoveCXAAtExit(BasicBlock &basic_block) { if (func && func->getName() == "__cxa_atexit") remove = true; - llvm::Value *val = call->getCalledValue(); + llvm::Value *val = call->getCalledOperand(); if (val && val->getName() == "__cxa_atexit") remove = true; @@ -1799,7 +1794,9 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { get_element_ptr, value->getType()->getPointerTo(), "", entry_instruction); - LoadInst *load = new LoadInst(bit_cast, "", entry_instruction); + LoadInst *load = + new LoadInst(bit_cast->getType()->getPointerElementType(), + bit_cast, "", entry_instruction); return load; } else { @@ -1845,7 +1842,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) { lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); m_module = &llvm_module; - m_target_data.reset(new DataLayout(m_module)); + m_target_data = std::make_unique<DataLayout>(m_module); m_intptr_ty = llvm::Type::getIntNTy(m_module->getContext(), m_target_data->getPointerSizeInBits()); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h index 262e8ee0c06c..ebfc0cae626c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h @@ -7,10 +7,9 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_IRForTarget_h_ -#define liblldb_IRForTarget_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H -#include "lldb/Core/ClangForward.h" #include "lldb/Symbol/TaggedASTType.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" @@ -38,6 +37,10 @@ class DataLayout; class Value; } +namespace clang { +class NamedDecl; +} + namespace lldb_private { class ClangExpressionDeclMap; class IRExecutionUnit; @@ -506,4 +509,4 @@ private: bool CompleteDataAllocation(); }; -#endif // liblldb_IRForTarget_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h index 7553860f2492..b7b6640c4810 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ModuleDependencyCollector_h_ -#define liblldb_ModuleDependencyCollector_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_MODULEDEPENDENCYCOLLECTOR_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_MODULEDEPENDENCYCOLLECTOR_H #include "clang/Frontend/Utils.h" #include "llvm/ADT/StringRef.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp new file mode 100644 index 000000000000..c1f88889f1dc --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -0,0 +1,179 @@ +//===-- NameSearchContext.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 "NameSearchContext.h" +#include "ClangUtil.h" + +using namespace clang; +using namespace lldb_private; + +clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { + assert(type && "Type for variable must be valid!"); + + if (!type.IsValid()) + return nullptr; + + TypeSystemClang *lldb_ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!lldb_ast) + return nullptr; + + IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo(); + + clang::ASTContext &ast = lldb_ast->getASTContext(); + + clang::NamedDecl *Decl = VarDecl::Create( + ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), + SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static); + m_decls.push_back(Decl); + + return Decl; +} + +clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, + bool extern_c) { + assert(type && "Type for variable must be valid!"); + + if (!type.IsValid()) + return nullptr; + + if (m_function_types.count(type)) + return nullptr; + + TypeSystemClang *lldb_ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!lldb_ast) + return nullptr; + + m_function_types.insert(type); + + QualType qual_type(ClangUtil::GetQualType(type)); + + clang::ASTContext &ast = lldb_ast->getASTContext(); + + const bool isInlineSpecified = false; + const bool hasWrittenPrototype = true; + const bool isConstexprSpecified = false; + + 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); + } + + // Pass the identifier info for functions the decl_name is needed for + // operators + clang::DeclarationName decl_name = + m_decl_name.getNameKind() == DeclarationName::Identifier + ? m_decl_name.getAsIdentifierInfo() + : m_decl_name; + + clang::FunctionDecl *func_decl = FunctionDecl::Create( + ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, + nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, + isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + + // We have to do more than just synthesize the FunctionDecl. We have to + // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do + // this, we raid the function's FunctionProtoType for types. + + const FunctionProtoType *func_proto_type = + qual_type.getTypePtr()->getAs<FunctionProtoType>(); + + if (func_proto_type) { + unsigned NumArgs = func_proto_type->getNumParams(); + unsigned ArgIndex; + + SmallVector<ParmVarDecl *, 5> parm_var_decls; + + for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) { + QualType arg_qual_type(func_proto_type->getParamType(ArgIndex)); + + parm_var_decls.push_back( + ParmVarDecl::Create(ast, const_cast<DeclContext *>(context), + SourceLocation(), SourceLocation(), nullptr, + arg_qual_type, nullptr, SC_Static, nullptr)); + } + + func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls)); + } else { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + LLDB_LOG(log, "Function type wasn't a FunctionProtoType"); + } + + // If this is an operator (e.g. operator new or operator==), only insert the + // declaration we inferred from the symbol if we can provide the correct + // number of arguments. We shouldn't really inject random decl(s) for + // functions that are analyzed semantically in a special way, otherwise we + // will crash in clang. + clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; + if (func_proto_type && + TypeSystemClang::IsOperator(decl_name.getAsString().c_str(), op_kind)) { + if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount( + false, op_kind, func_proto_type->getNumParams())) + return nullptr; + } + m_decls.push_back(func_decl); + + return func_decl; +} + +clang::NamedDecl *NameSearchContext::AddGenericFunDecl() { + FunctionProtoType::ExtProtoInfo proto_info; + + proto_info.Variadic = true; + + QualType generic_function_type( + GetASTContext().getFunctionType(GetASTContext().UnknownAnyTy, // result + ArrayRef<QualType>(), // argument types + proto_info)); + + return AddFunDecl(m_clang_ts.GetType(generic_function_type), true); +} + +clang::NamedDecl * +NameSearchContext::AddTypeDecl(const CompilerType &clang_type) { + if (ClangUtil::IsClangType(clang_type)) { + QualType qual_type = ClangUtil::GetQualType(clang_type); + + if (const TypedefType *typedef_type = + llvm::dyn_cast<TypedefType>(qual_type)) { + TypedefNameDecl *typedef_name_decl = typedef_type->getDecl(); + + m_decls.push_back(typedef_name_decl); + + return (NamedDecl *)typedef_name_decl; + } else if (const TagType *tag_type = qual_type->getAs<TagType>()) { + TagDecl *tag_decl = tag_type->getDecl(); + + m_decls.push_back(tag_decl); + + return tag_decl; + } else if (const ObjCObjectType *objc_object_type = + qual_type->getAs<ObjCObjectType>()) { + ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface(); + + m_decls.push_back((NamedDecl *)interface_decl); + + return (NamedDecl *)interface_decl; + } + } + return nullptr; +} + +void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) { + for (clang::NamedDecl *decl : result) + m_decls.push_back(decl); +} + +void NameSearchContext::AddNamedDecl(clang::NamedDecl *decl) { + m_decls.push_back(decl); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h new file mode 100644 index 000000000000..dc8621dd6aba --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h @@ -0,0 +1,124 @@ +//===-- NameSearchContext.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_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H + +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "lldb/Symbol/CompilerType.h" +#include "llvm/ADT/SmallSet.h" + +namespace lldb_private { + +/// \class NameSearchContext ClangASTSource.h +/// "lldb/Expression/ClangASTSource.h" Container for all objects relevant to a +/// single name lookup +/// +/// LLDB needs to create Decls for entities it finds. This class communicates +/// what name is being searched for and provides helper functions to construct +/// Decls given appropriate type information. +struct NameSearchContext { + /// The type system of the AST from which the lookup originated. + TypeSystemClang &m_clang_ts; + /// The list of declarations already constructed. + llvm::SmallVectorImpl<clang::NamedDecl *> &m_decls; + /// The mapping of all namespaces found for this request back to their + /// modules. + ClangASTImporter::NamespaceMapSP m_namespace_map; + /// The name being looked for. + const clang::DeclarationName m_decl_name; + /// The DeclContext to put declarations into. + const clang::DeclContext *m_decl_context; + /// All the types of functions that have been reported, so we don't + /// report conflicts. + llvm::SmallSet<CompilerType, 5> m_function_types; + + bool m_found_variable = false; + bool m_found_function_with_type_info = false; + bool m_found_function = false; + bool m_found_local_vars_nsp = false; + bool m_found_type = false; + + /// Constructor + /// + /// Initializes class variables. + /// + /// \param[in] clang_ts + /// The TypeSystemClang from which the request originates. + /// + /// \param[in] decls + /// A reference to a list into which new Decls will be placed. This + /// list is typically empty when the function is called. + /// + /// \param[in] name + /// The name being searched for (always an Identifier). + /// + /// \param[in] dc + /// The DeclContext to register Decls in. + NameSearchContext(TypeSystemClang &clang_ts, + llvm::SmallVectorImpl<clang::NamedDecl *> &decls, + clang::DeclarationName name, const clang::DeclContext *dc) + : m_clang_ts(clang_ts), m_decls(decls), + m_namespace_map(std::make_shared<ClangASTImporter::NamespaceMap>()), + m_decl_name(name), m_decl_context(dc) { + ; + } + + /// Create a VarDecl with the name being searched for and the provided type + /// and register it in the right places. + /// + /// \param[in] type + /// The opaque QualType for the VarDecl being registered. + clang::NamedDecl *AddVarDecl(const CompilerType &type); + + /// Create a FunDecl with the name being searched for and the provided type + /// and register it in the right places. + /// + /// \param[in] type + /// The opaque QualType for the FunDecl being registered. + /// + /// \param[in] extern_c + /// If true, build an extern "C" linkage specification for this. + clang::NamedDecl *AddFunDecl(const CompilerType &type, bool extern_c = false); + + /// Create a FunDecl with the name being searched for and generic type (i.e. + /// intptr_t NAME_GOES_HERE(...)) and register it in the right places. + clang::NamedDecl *AddGenericFunDecl(); + + /// Create a TypeDecl with the name being searched for and the provided type + /// and register it in the right places. + /// + /// \param[in] compiler_type + /// The opaque QualType for the TypeDecl being registered. + clang::NamedDecl *AddTypeDecl(const CompilerType &compiler_type); + + /// Add Decls from the provided DeclContextLookupResult to the list of + /// results. + /// + /// \param[in] result + /// The DeclContextLookupResult, usually returned as the result + /// of querying a DeclContext. + void AddLookupResult(clang::DeclContextLookupResult result); + + /// Add a NamedDecl to the list of results. + /// + /// \param[in] decl + /// The NamedDecl, usually returned as the result + /// of querying a DeclContext. + void AddNamedDecl(clang::NamedDecl *decl); + +private: + clang::ASTContext &GetASTContext() const { + return m_clang_ts.getASTContext(); + } +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index ff142e6f35ff..555912780df9 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -1,4 +1,4 @@ -//===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===// +//===-- EmulateInstructionARM.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -30,6 +30,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM, InstructionARM) + // Convenient macro definitions. #define APSR_C Bit32(m_opcode_cpsr, CPSR_C_POS) #define APSR_V Bit32(m_opcode_cpsr, CPSR_V_POS) @@ -603,9 +605,6 @@ static uint32_t CountITSize(uint32_t ITMask) { // First count the trailing zeros of the IT mask. uint32_t TZ = llvm::countTrailingZeros(ITMask); if (TZ > 3) { -#ifdef LLDB_CONFIGURATION_DEBUG - printf("Encoding error: IT Mask '0000'\n"); -#endif return 0; } return (4 - TZ); @@ -620,15 +619,9 @@ bool ITSession::InitIT(uint32_t bits7_0) { // A8.6.50 IT unsigned short FirstCond = Bits32(bits7_0, 7, 4); if (FirstCond == 0xF) { -#ifdef LLDB_CONFIGURATION_DEBUG - printf("Encoding error: IT FirstCond '1111'\n"); -#endif return false; } if (FirstCond == 0xE && ITCounter != 1) { -#ifdef LLDB_CONFIGURATION_DEBUG - printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n"); -#endif return false; } @@ -7230,7 +7223,7 @@ bool EmulateInstructionARM::EmulateLDRHImmediate(const uint32_t opcode, return true; } -// LDRH (literal) caculates an address from the PC value and an immediate +// LDRH (literal) calculates an address from the PC value and an immediate // offset, loads a halfword from memory, // zero-extends it to form a 32-bit word, and writes it to a register. bool EmulateInstructionARM::EmulateLDRHLiteral(const uint32_t opcode, @@ -8516,7 +8509,7 @@ bool EmulateInstructionARM::EmulateSXTH(const uint32_t opcode, return true; } -// UXTB extracts an 8-bit value from a register, zero-extneds it to 32 bits, and +// UXTB extracts an 8-bit value from a register, zero-extends it to 32 bits, and // writes the result to the destination // register. You can specify a rotation by 0, 8, 16, or 24 bits before // extracting the 8-bit value. @@ -14368,7 +14361,7 @@ bool EmulateInstructionARM::EvaluateInstruction(uint32_t evaluate_options) { if (!success) return false; - if (auto_advance_pc && (after_pc_value == orig_pc_value)) { + if (after_pc_value == orig_pc_value) { after_pc_value += m_opcode.GetByteSize(); EmulateInstruction::Context context; diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index 13d7fc061bea..d15d80c97e38 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_EmulateInstructionARM_h_ -#define lldb_EmulateInstructionARM_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM_EMULATEINSTRUCTIONARM_H +#define LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM_EMULATEINSTRUCTIONARM_H #include "Plugins/Process/Utility/ARMDefines.h" #include "lldb/Core/EmulateInstruction.h" @@ -783,4 +783,4 @@ protected: } // namespace lldb_private -#endif // lldb_EmulateInstructionARM_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM_EMULATEINSTRUCTIONARM_H diff --git a/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp index 11c7677c201a..aef08baa8ae9 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp +++ b/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp @@ -1,4 +1,4 @@ -//===-- EmulationStateARM.cpp -----------------------------------*- C++ -*-===// +//===-- EmulationStateARM.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h b/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h index e5af37a21504..955c7c642058 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h +++ b/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_EmulationStateARM_h_ -#define lldb_EmulationStateARM_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM_EMULATIONSTATEARM_H +#define LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM_EMULATIONSTATEARM_H #include <map> @@ -73,7 +73,8 @@ private: // uint32_t to a data buffer heap // type. - DISALLOW_COPY_AND_ASSIGN(EmulationStateARM); + EmulationStateARM(const EmulationStateARM &) = delete; + const EmulationStateARM &operator=(const EmulationStateARM &) = delete; }; -#endif // lldb_EmulationStateARM_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM_EMULATIONSTATEARM_H diff --git a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp index 3e06fca2504c..9b0c06bcccab 100644 --- a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp +++ b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -1,4 +1,4 @@ -//===-- EmulateInstructionARM64.cpp ------------------------------*- C++-*-===// +//===-- EmulateInstructionARM64.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,8 +8,6 @@ #include "EmulateInstructionARM64.h" -#include <stdlib.h> - #include "lldb/Core/Address.h" #include "lldb/Core/PluginManager.h" #include "lldb/Symbol/UnwindPlan.h" @@ -18,10 +16,14 @@ #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Stream.h" +#include "llvm/Support/CheckedArithmetic.h" + #include "Plugins/Process/Utility/ARMDefines.h" #include "Plugins/Process/Utility/ARMUtils.h" #include "Plugins/Process/Utility/lldb-arm64-register-enums.h" +#include <cstdlib> + #define GPR_OFFSET(idx) ((idx)*8) #define GPR_OFFSET_NAME(reg) 0 #define FPU_OFFSET(idx) ((idx)*16) @@ -47,6 +49,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM64, InstructionARM64) + static bool LLDBTableGetRegisterInfo(uint32_t reg_num, RegisterInfo ®_info) { if (reg_num >= llvm::array_lengthof(g_register_infos_arm64_le)) return false; @@ -83,23 +87,6 @@ static inline uint64_t LSL(uint64_t x, integer shift) { return x << shift; } -// AddWithCarry() -// =============== -static inline uint64_t -AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in, - EmulateInstructionARM64::ProcState &proc_state) { - uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in); - int64_t signed_sum = SInt(x) + SInt(y) + UInt(carry_in); - uint64_t result = unsigned_sum; - if (N < 64) - result = Bits64(result, N - 1, 0); - proc_state.N = Bit64(result, N - 1); - proc_state.Z = IsZero(result); - proc_state.C = UInt(result) == unsigned_sum; - proc_state.V = SInt(result) == signed_sum; - return result; -} - // ConstrainUnpredictable() // ======================== @@ -415,20 +402,12 @@ bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) { if (opcode_data == nullptr) return false; - // printf ("opcode template for 0x%8.8x: %s\n", opcode, opcode_data->name); const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions; bool success = false; - // if (m_opcode_cpsr == 0 || m_ignore_conditions == false) - // { - // m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindLLDB, - // gpr_cpsr_arm64, - // 0, - // &success); - // } // Only return false if we are unable to read the CPSR if we care about // conditions @@ -454,7 +433,7 @@ bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) { if (!success) return false; - if (auto_advance_pc && (new_pc_value == orig_pc_value)) { + if (new_pc_value == orig_pc_value) { EmulateInstruction::Context context; context.type = eContextAdvancePC; context.SetNoArgs(); @@ -588,6 +567,24 @@ bool EmulateInstructionARM64::ConditionHolds(const uint32_t cond) { return result; } +uint64_t EmulateInstructionARM64:: +AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in, + EmulateInstructionARM64::ProcState &proc_state) { + uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in); + llvm::Optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y)); + bool overflow = !signed_sum; + if (!overflow) + overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in)); + uint64_t result = unsigned_sum; + if (N < 64) + result = Bits64(result, N - 1, 0); + proc_state.N = Bit64(result, N - 1); + proc_state.Z = IsZero(result); + proc_state.C = UInt(result) != unsigned_sum; + proc_state.V = overflow; + return result; +} + bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) { // integer d = UInt(Rd); // integer n = UInt(Rn); @@ -783,10 +780,6 @@ bool EmulateInstructionARM64::EmulateLDPSTP(const uint32_t opcode) { RegisterValue data_Rt; RegisterValue data_Rt2; - - // if (vector) - // CheckFPEnabled(false); - RegisterInfo reg_info_base; RegisterInfo reg_info_Rt; RegisterInfo reg_info_Rt2; diff --git a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h index 03a57a2cf92b..11ad8a99b0fc 100644 --- a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h +++ b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef EmulateInstructionARM64_h_ -#define EmulateInstructionARM64_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM64_EMULATEINSTRUCTIONARM64_H +#define LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM64_EMULATEINSTRUCTIONARM64_H #include "Plugins/Process/Utility/ARMDefines.h" #include "lldb/Core/EmulateInstruction.h" @@ -152,6 +152,9 @@ public: } ProcState; protected: + static uint64_t AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bool carry_in, + EmulateInstructionARM64::ProcState &proc_state); + typedef struct { uint32_t mask; uint32_t value; @@ -189,4 +192,4 @@ protected: bool m_ignore_conditions; }; -#endif // EmulateInstructionARM64_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_ARM64_EMULATEINSTRUCTIONARM64_H diff --git a/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp index b55eeb0eaf46..d4cb726fc7e5 100644 --- a/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp +++ b/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp @@ -1,4 +1,4 @@ -//===-- EmulateInstructionMIPS.cpp -------------------------------*- C++-*-===// +//===-- EmulateInstructionMIPS.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -40,6 +40,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionMIPS, InstructionMIPS) + #define UInt(x) ((uint64_t)x) #define integer int64_t @@ -157,8 +159,8 @@ EmulateInstructionMIPS::EmulateInstructionMIPS( target->createMCSubtargetInfo(triple.getTriple(), cpu, features)); assert(m_asm_info.get() && m_subtype_info.get()); - m_context.reset( - new llvm::MCContext(m_asm_info.get(), m_reg_info.get(), nullptr)); + m_context = std::make_unique<llvm::MCContext>(m_asm_info.get(), + m_reg_info.get(), nullptr); assert(m_context.get()); m_disasm.reset(target->createMCDisassembler(*m_subtype_info, *m_context)); diff --git a/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h b/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h index cd447ae4975e..61291c729879 100644 --- a/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h +++ b/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef EmulateInstructionMIPS_h_ -#define EmulateInstructionMIPS_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_MIPS_EMULATEINSTRUCTIONMIPS_H +#define LLDB_SOURCE_PLUGINS_INSTRUCTION_MIPS_EMULATEINSTRUCTIONMIPS_H namespace llvm { class MCDisassembler; @@ -203,7 +203,7 @@ protected: bool nonvolatile_reg_p(uint32_t regnum); - const char *GetRegisterName(unsigned reg_num, bool altnernate_name); + const char *GetRegisterName(unsigned reg_num, bool alternate_name); private: std::unique_ptr<llvm::MCDisassembler> m_disasm; @@ -218,4 +218,4 @@ private: bool m_use_alt_disaasm; }; -#endif // EmulateInstructionMIPS_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_MIPS_EMULATEINSTRUCTIONMIPS_H diff --git a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp index 3baf942bc17f..4ccaf0de0758 100644 --- a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp +++ b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp @@ -1,4 +1,4 @@ -//===-- EmulateInstructionMIPS64.cpp -----------------------------*- C++-*-===// +//===-- EmulateInstructionMIPS64.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -40,6 +40,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionMIPS64, InstructionMIPS64) + #define UInt(x) ((uint64_t)x) #define integer int64_t @@ -161,8 +163,8 @@ EmulateInstructionMIPS64::EmulateInstructionMIPS64( target->createMCSubtargetInfo(triple.getTriple(), cpu, features)); assert(m_asm_info.get() && m_subtype_info.get()); - m_context.reset( - new llvm::MCContext(m_asm_info.get(), m_reg_info.get(), nullptr)); + m_context = std::make_unique<llvm::MCContext>(m_asm_info.get(), + m_reg_info.get(), nullptr); assert(m_context.get()); m_disasm.reset(target->createMCDisassembler(*m_subtype_info, *m_context)); diff --git a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h index 953a0935bd06..c4ae2296c5dd 100644 --- a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h +++ b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef EmulateInstructionMIPS64_h_ -#define EmulateInstructionMIPS64_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_MIPS64_EMULATEINSTRUCTIONMIPS64_H +#define LLDB_SOURCE_PLUGINS_INSTRUCTION_MIPS64_EMULATEINSTRUCTIONMIPS64_H #include "lldb/Core/EmulateInstruction.h" #include "lldb/Interpreter/OptionValue.h" @@ -168,7 +168,7 @@ protected: bool nonvolatile_reg_p(uint64_t regnum); - const char *GetRegisterName(unsigned reg_num, bool altnernate_name); + const char *GetRegisterName(unsigned reg_num, bool alternate_name); private: std::unique_ptr<llvm::MCDisassembler> m_disasm; @@ -179,4 +179,4 @@ private: std::unique_ptr<llvm::MCInstrInfo> m_insn_info; }; -#endif // EmulateInstructionMIPS64_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_MIPS64_EMULATEINSTRUCTIONMIPS64_H diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp index 4b8d8dd2228c..5d97513c0be7 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp @@ -1,4 +1,4 @@ -//===-- EmulateInstructionPPC64.cpp ------------------------------*- C++-*-===// +//===-- EmulateInstructionPPC64.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -25,6 +25,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionPPC64, InstructionPPC64) + EmulateInstructionPPC64::EmulateInstructionPPC64(const ArchSpec &arch) : EmulateInstruction(arch) {} @@ -196,7 +198,7 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { if (!success) return false; - if (auto_advance_pc && (new_pc_value == orig_pc_value)) { + if (new_pc_value == orig_pc_value) { EmulateInstruction::Context context; context.type = eContextAdvancePC; context.SetNoArgs(); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index bf239770b933..02d2bce8f05e 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef EmulateInstructionPPC64_h_ -#define EmulateInstructionPPC64_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_PPC64_EMULATEINSTRUCTIONPPC64_H +#define LLDB_SOURCE_PLUGINS_INSTRUCTION_PPC64_EMULATEINSTRUCTIONPPC64_H #include "lldb/Core/EmulateInstruction.h" #include "lldb/Interpreter/OptionValue.h" @@ -89,4 +89,4 @@ private: } // namespace lldb_private -#endif // EmulateInstructionPPC64_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_PPC64_EMULATEINSTRUCTIONPPC64_H diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp index 2e5dd5989e77..e78ea3a68483 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.cpp @@ -1,4 +1,4 @@ -//===-- ASanRuntime.cpp -----------------------------------------*- C++ -*-===// +//===-- InstrumentationRuntimeASan.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "ASanRuntime.h" +#include "InstrumentationRuntimeASan.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" @@ -30,40 +30,42 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(InstrumentationRuntimeASan) + lldb::InstrumentationRuntimeSP -AddressSanitizerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) { - return InstrumentationRuntimeSP(new AddressSanitizerRuntime(process_sp)); +InstrumentationRuntimeASan::CreateInstance(const lldb::ProcessSP &process_sp) { + return InstrumentationRuntimeSP(new InstrumentationRuntimeASan(process_sp)); } -void AddressSanitizerRuntime::Initialize() { +void InstrumentationRuntimeASan::Initialize() { PluginManager::RegisterPlugin( GetPluginNameStatic(), "AddressSanitizer instrumentation runtime plugin.", CreateInstance, GetTypeStatic); } -void AddressSanitizerRuntime::Terminate() { +void InstrumentationRuntimeASan::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString AddressSanitizerRuntime::GetPluginNameStatic() { +lldb_private::ConstString InstrumentationRuntimeASan::GetPluginNameStatic() { return ConstString("AddressSanitizer"); } -lldb::InstrumentationRuntimeType AddressSanitizerRuntime::GetTypeStatic() { +lldb::InstrumentationRuntimeType InstrumentationRuntimeASan::GetTypeStatic() { return eInstrumentationRuntimeTypeAddressSanitizer; } -AddressSanitizerRuntime::~AddressSanitizerRuntime() { Deactivate(); } +InstrumentationRuntimeASan::~InstrumentationRuntimeASan() { Deactivate(); } const RegularExpression & -AddressSanitizerRuntime::GetPatternForRuntimeLibrary() { +InstrumentationRuntimeASan::GetPatternForRuntimeLibrary() { // FIXME: This shouldn't include the "dylib" suffix. static RegularExpression regex( llvm::StringRef("libclang_rt.asan_(.*)_dynamic\\.dylib")); return regex; } -bool AddressSanitizerRuntime::CheckIfRuntimeIsValid( +bool InstrumentationRuntimeASan::CheckIfRuntimeIsValid( const lldb::ModuleSP module_sp) { const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( ConstString("__asan_get_alloc_stack"), lldb::eSymbolTypeAny); @@ -108,7 +110,7 @@ t.description = __asan_get_report_description(); t )"; -StructuredData::ObjectSP AddressSanitizerRuntime::RetrieveReportData() { +StructuredData::ObjectSP InstrumentationRuntimeASan::RetrieveReportData() { ProcessSP process_sp = GetProcessSP(); if (!process_sp) return StructuredData::ObjectSP(); @@ -189,11 +191,11 @@ StructuredData::ObjectSP AddressSanitizerRuntime::RetrieveReportData() { } std::string -AddressSanitizerRuntime::FormatDescription(StructuredData::ObjectSP report) { - std::string description = report->GetAsDictionary() - ->GetValueForKey("description") - ->GetAsString() - ->GetValue(); +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") @@ -235,15 +237,15 @@ AddressSanitizerRuntime::FormatDescription(StructuredData::ObjectSP report) { .Default("AddressSanitizer detected: " + description); } -bool AddressSanitizerRuntime::NotifyBreakpointHit( +bool InstrumentationRuntimeASan::NotifyBreakpointHit( void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) { assert(baton && "null baton"); if (!baton) return false; - AddressSanitizerRuntime *const instance = - static_cast<AddressSanitizerRuntime *>(baton); + InstrumentationRuntimeASan *const instance = + static_cast<InstrumentationRuntimeASan *>(baton); ProcessSP process_sp = instance->GetProcessSP(); @@ -275,7 +277,7 @@ bool AddressSanitizerRuntime::NotifyBreakpointHit( return false; // Let target run } -void AddressSanitizerRuntime::Activate() { +void InstrumentationRuntimeASan::Activate() { if (IsActive()) return; @@ -305,7 +307,7 @@ void AddressSanitizerRuntime::Activate() { process_sp->GetTarget() .CreateBreakpoint(symbol_address, internal, hardware) .get(); - breakpoint->SetCallback(AddressSanitizerRuntime::NotifyBreakpointHit, this, + breakpoint->SetCallback(InstrumentationRuntimeASan::NotifyBreakpointHit, this, true); breakpoint->SetBreakpointKind("address-sanitizer-report"); SetBreakpointID(breakpoint->GetID()); @@ -313,7 +315,7 @@ void AddressSanitizerRuntime::Activate() { SetActive(true); } -void AddressSanitizerRuntime::Deactivate() { +void InstrumentationRuntimeASan::Deactivate() { if (GetBreakpointID() != LLDB_INVALID_BREAK_ID) { ProcessSP process_sp = GetProcessSP(); if (process_sp) { diff --git a/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h index 0771e624ff6b..cde0a9613350 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h +++ b/lldb/source/Plugins/InstrumentationRuntime/ASan/InstrumentationRuntimeASan.h @@ -1,4 +1,4 @@ -//===-- ASanRuntime.h -------------------------------------------*- C++ -*-===// +//===-- InstrumentationRuntimeASan.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. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_AddressSanitizerRuntime_h_ -#define liblldb_AddressSanitizerRuntime_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMEASAN_H +#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMEASAN_H #include "lldb/Target/InstrumentationRuntime.h" #include "lldb/Target/Process.h" @@ -16,9 +16,9 @@ namespace lldb_private { -class AddressSanitizerRuntime : public lldb_private::InstrumentationRuntime { +class InstrumentationRuntimeASan : public lldb_private::InstrumentationRuntime { public: - ~AddressSanitizerRuntime() override; + ~InstrumentationRuntimeASan() override; static lldb::InstrumentationRuntimeSP CreateInstance(const lldb::ProcessSP &process_sp); @@ -40,7 +40,7 @@ public: uint32_t GetPluginVersion() override { return 1; } private: - AddressSanitizerRuntime(const lldb::ProcessSP &process_sp) + InstrumentationRuntimeASan(const lldb::ProcessSP &process_sp) : lldb_private::InstrumentationRuntime(process_sp) {} const RegularExpression &GetPatternForRuntimeLibrary() override; @@ -63,4 +63,4 @@ private: } // namespace lldb_private -#endif // liblldb_AddressSanitizerRuntime_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_ASAN_INSTRUMENTATIONRUNTIMEASAN_H diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp index b73b6c095368..72d28c347457 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp @@ -1,4 +1,4 @@ -//===-- MainThreadCheckerRuntime.cpp ----------------------------*- C++ -*-===// +//===-- InstrumentationRuntimeMainThreadChecker.cpp -----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "MainThreadCheckerRuntime.h" +#include "InstrumentationRuntimeMainThreadChecker.h" +#include "Plugins/Process/Utility/HistoryThread.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" @@ -22,47 +23,54 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/RegularExpression.h" -#include "Plugins/Process/Utility/HistoryThread.h" #include <memory> using namespace lldb; using namespace lldb_private; -MainThreadCheckerRuntime::~MainThreadCheckerRuntime() { +LLDB_PLUGIN_DEFINE(InstrumentationRuntimeMainThreadChecker) + +InstrumentationRuntimeMainThreadChecker:: + ~InstrumentationRuntimeMainThreadChecker() { Deactivate(); } lldb::InstrumentationRuntimeSP -MainThreadCheckerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) { - return InstrumentationRuntimeSP(new MainThreadCheckerRuntime(process_sp)); +InstrumentationRuntimeMainThreadChecker::CreateInstance( + const lldb::ProcessSP &process_sp) { + return InstrumentationRuntimeSP( + new InstrumentationRuntimeMainThreadChecker(process_sp)); } -void MainThreadCheckerRuntime::Initialize() { +void InstrumentationRuntimeMainThreadChecker::Initialize() { PluginManager::RegisterPlugin( - GetPluginNameStatic(), "MainThreadChecker instrumentation runtime plugin.", - CreateInstance, GetTypeStatic); + GetPluginNameStatic(), + "MainThreadChecker instrumentation runtime plugin.", CreateInstance, + GetTypeStatic); } -void MainThreadCheckerRuntime::Terminate() { +void InstrumentationRuntimeMainThreadChecker::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString MainThreadCheckerRuntime::GetPluginNameStatic() { +lldb_private::ConstString +InstrumentationRuntimeMainThreadChecker::GetPluginNameStatic() { return ConstString("MainThreadChecker"); } -lldb::InstrumentationRuntimeType MainThreadCheckerRuntime::GetTypeStatic() { +lldb::InstrumentationRuntimeType +InstrumentationRuntimeMainThreadChecker::GetTypeStatic() { return eInstrumentationRuntimeTypeMainThreadChecker; } const RegularExpression & -MainThreadCheckerRuntime::GetPatternForRuntimeLibrary() { +InstrumentationRuntimeMainThreadChecker::GetPatternForRuntimeLibrary() { static RegularExpression regex(llvm::StringRef("libMainThreadChecker.dylib")); return regex; } -bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid( +bool InstrumentationRuntimeMainThreadChecker::CheckIfRuntimeIsValid( const lldb::ModuleSP module_sp) { static ConstString test_sym("__main_thread_checker_on_report"); const Symbol *symbol = @@ -71,7 +79,8 @@ bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid( } StructuredData::ObjectSP -MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) { +InstrumentationRuntimeMainThreadChecker::RetrieveReportData( + ExecutionContextRef exe_ctx_ref) { ProcessSP process_sp = GetProcessSP(); if (!process_sp) return StructuredData::ObjectSP(); @@ -148,15 +157,15 @@ MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) { return dict_sp; } -bool MainThreadCheckerRuntime::NotifyBreakpointHit( +bool InstrumentationRuntimeMainThreadChecker::NotifyBreakpointHit( void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) { assert(baton && "null baton"); if (!baton) return false; ///< false => resume execution. - MainThreadCheckerRuntime *const instance = - static_cast<MainThreadCheckerRuntime *>(baton); + InstrumentationRuntimeMainThreadChecker *const instance = + static_cast<InstrumentationRuntimeMainThreadChecker *>(baton); ProcessSP process_sp = instance->GetProcessSP(); ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); @@ -171,10 +180,10 @@ bool MainThreadCheckerRuntime::NotifyBreakpointHit( instance->RetrieveReportData(context->exe_ctx_ref); if (report) { - std::string description = report->GetAsDictionary() - ->GetValueForKey("description") - ->GetAsString() - ->GetValue(); + std::string description = std::string(report->GetAsDictionary() + ->GetValueForKey("description") + ->GetAsString() + ->GetValue()); thread_sp->SetStopInfo( InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData( *thread_sp, description, report)); @@ -184,7 +193,7 @@ bool MainThreadCheckerRuntime::NotifyBreakpointHit( return false; } -void MainThreadCheckerRuntime::Activate() { +void InstrumentationRuntimeMainThreadChecker::Activate() { if (IsActive()) return; @@ -215,15 +224,15 @@ void MainThreadCheckerRuntime::Activate() { .CreateBreakpoint(symbol_address, /*internal=*/true, /*hardware=*/false) .get(); - breakpoint->SetCallback(MainThreadCheckerRuntime::NotifyBreakpointHit, this, - true); + breakpoint->SetCallback( + InstrumentationRuntimeMainThreadChecker::NotifyBreakpointHit, this, true); breakpoint->SetBreakpointKind("main-thread-checker-report"); SetBreakpointID(breakpoint->GetID()); SetActive(true); } -void MainThreadCheckerRuntime::Deactivate() { +void InstrumentationRuntimeMainThreadChecker::Deactivate() { SetActive(false); auto BID = GetBreakpointID(); @@ -237,7 +246,7 @@ void MainThreadCheckerRuntime::Deactivate() { } lldb::ThreadCollectionSP -MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo( +InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP info) { ThreadCollectionSP threads; threads = std::make_shared<ThreadCollection>(); @@ -245,7 +254,7 @@ MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo( ProcessSP process_sp = GetProcessSP(); if (info->GetObjectForDotSeparatedPath("instrumentation_class") - ->GetStringValue() != "MainThreadChecker") + ->GetStringValue() != "MainThreadChecker") return threads; std::vector<lldb::addr_t> PCs; diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.h b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.h new file mode 100644 index 000000000000..1435ae8d367f --- /dev/null +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.h @@ -0,0 +1,68 @@ +//===-- InstrumentationRuntimeMainThreadChecker.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_MAINTHREADCHECKER_INSTRUMENTATIONRUNTIMEMAINTHREADCHECKER_H +#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_MAINTHREADCHECKER_INSTRUMENTATIONRUNTIMEMAINTHREADCHECKER_H + +#include "lldb/Target/ABI.h" +#include "lldb/Target/InstrumentationRuntime.h" +#include "lldb/Utility/StructuredData.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class InstrumentationRuntimeMainThreadChecker + : public lldb_private::InstrumentationRuntime { +public: + ~InstrumentationRuntimeMainThreadChecker() override; + + static lldb::InstrumentationRuntimeSP + CreateInstance(const lldb::ProcessSP &process_sp); + + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static lldb::InstrumentationRuntimeType GetTypeStatic(); + + lldb_private::ConstString GetPluginName() override { + return GetPluginNameStatic(); + } + + virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); } + + uint32_t GetPluginVersion() override { return 1; } + + lldb::ThreadCollectionSP + GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override; + +private: + InstrumentationRuntimeMainThreadChecker(const lldb::ProcessSP &process_sp) + : lldb_private::InstrumentationRuntime(process_sp) {} + + const RegularExpression &GetPatternForRuntimeLibrary() override; + + bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override; + + void Activate() override; + + void Deactivate(); + + static bool NotifyBreakpointHit(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref); +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_MAINTHREADCHECKER_INSTRUMENTATIONRUNTIMEMAINTHREADCHECKER_H diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h deleted file mode 100644 index 1dcbc0f6bc89..000000000000 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h +++ /dev/null @@ -1,67 +0,0 @@ -//===-- MainThreadCheckerRuntime.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_MainThreadCheckerRuntime_h_ -#define liblldb_MainThreadCheckerRuntime_h_ - -#include "lldb/Target/ABI.h" -#include "lldb/Target/InstrumentationRuntime.h" -#include "lldb/Utility/StructuredData.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { - - class MainThreadCheckerRuntime : public lldb_private::InstrumentationRuntime { - public: - ~MainThreadCheckerRuntime() override; - - static lldb::InstrumentationRuntimeSP - CreateInstance(const lldb::ProcessSP &process_sp); - - static void Initialize(); - - static void Terminate(); - - static lldb_private::ConstString GetPluginNameStatic(); - - static lldb::InstrumentationRuntimeType GetTypeStatic(); - - lldb_private::ConstString GetPluginName() override { - return GetPluginNameStatic(); - } - - virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); } - - uint32_t GetPluginVersion() override { return 1; } - - lldb::ThreadCollectionSP - GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override; - - private: - MainThreadCheckerRuntime(const lldb::ProcessSP &process_sp) - : lldb_private::InstrumentationRuntime(process_sp) {} - - const RegularExpression &GetPatternForRuntimeLibrary() override; - - bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override; - - void Activate() override; - - void Deactivate(); - - static bool NotifyBreakpointHit(void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref); - }; - -} // namespace lldb_private - -#endif // liblldb_MainThreadCheckerRuntime_h_ diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index 45a3aeeb204e..50f0faefa0f4 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -1,4 +1,4 @@ -//===-- TSanRuntime.cpp -----------------------------------------*- C++ -*-===// +//===-- InstrumentationRuntimeTSan.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "TSanRuntime.h" +#include "InstrumentationRuntimeTSan.h" #include "Plugins/Process/Utility/HistoryThread.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -35,30 +35,32 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(InstrumentationRuntimeTSan) + lldb::InstrumentationRuntimeSP -ThreadSanitizerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) { - return InstrumentationRuntimeSP(new ThreadSanitizerRuntime(process_sp)); +InstrumentationRuntimeTSan::CreateInstance(const lldb::ProcessSP &process_sp) { + return InstrumentationRuntimeSP(new InstrumentationRuntimeTSan(process_sp)); } -void ThreadSanitizerRuntime::Initialize() { +void InstrumentationRuntimeTSan::Initialize() { PluginManager::RegisterPlugin( GetPluginNameStatic(), "ThreadSanitizer instrumentation runtime plugin.", CreateInstance, GetTypeStatic); } -void ThreadSanitizerRuntime::Terminate() { +void InstrumentationRuntimeTSan::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString ThreadSanitizerRuntime::GetPluginNameStatic() { +lldb_private::ConstString InstrumentationRuntimeTSan::GetPluginNameStatic() { return ConstString("ThreadSanitizer"); } -lldb::InstrumentationRuntimeType ThreadSanitizerRuntime::GetTypeStatic() { +lldb::InstrumentationRuntimeType InstrumentationRuntimeTSan::GetTypeStatic() { return eInstrumentationRuntimeTypeThreadSanitizer; } -ThreadSanitizerRuntime::~ThreadSanitizerRuntime() { Deactivate(); } +InstrumentationRuntimeTSan::~InstrumentationRuntimeTSan() { Deactivate(); } const char *thread_sanitizer_retrieve_report_data_prefix = R"( extern "C" @@ -84,7 +86,7 @@ extern "C" int *running, const char **name, int *parent_tid, void **trace, unsigned long trace_size); int __tsan_get_report_unique_tid(void *report, unsigned long idx, int *tid); - + // TODO: dlsym won't work on Windows. void *dlsym(void* handle, const char* symbol); int (*ptr__tsan_get_report_loc_object_type)(void *report, unsigned long idx, const char **object_type); @@ -97,15 +99,15 @@ struct data { void *report; const char *description; int report_count; - + void *sleep_trace[REPORT_TRACE_SIZE]; - + int stack_count; struct { int idx; void *trace[REPORT_TRACE_SIZE]; } stacks[REPORT_ARRAY_SIZE]; - + int mop_count; struct { int idx; @@ -116,7 +118,7 @@ struct data { void *addr; void *trace[REPORT_TRACE_SIZE]; } mops[REPORT_ARRAY_SIZE]; - + int loc_count; struct { int idx; @@ -130,7 +132,7 @@ struct data { void *trace[REPORT_TRACE_SIZE]; const char *object_type; } locs[REPORT_ARRAY_SIZE]; - + int mutex_count; struct { int idx; @@ -139,7 +141,7 @@ struct data { int destroyed; void *trace[REPORT_TRACE_SIZE]; } mutexes[REPORT_ARRAY_SIZE]; - + int thread_count; struct { int idx; @@ -150,7 +152,7 @@ struct data { int parent_tid; void *trace[REPORT_TRACE_SIZE]; } threads[REPORT_ARRAY_SIZE]; - + int unique_tid_count; struct { int idx; @@ -299,8 +301,8 @@ static user_id_t Renumber(uint64_t id, return IT->second; } -StructuredData::ObjectSP -ThreadSanitizerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) { +StructuredData::ObjectSP InstrumentationRuntimeTSan::RetrieveReportData( + ExecutionContextRef exe_ctx_ref) { ProcessSP process_sp = GetProcessSP(); if (!process_sp) return StructuredData::ObjectSP(); @@ -486,11 +488,11 @@ ThreadSanitizerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) { } std::string -ThreadSanitizerRuntime::FormatDescription(StructuredData::ObjectSP report) { - std::string description = report->GetAsDictionary() - ->GetValueForKey("issue_type") - ->GetAsString() - ->GetValue(); +InstrumentationRuntimeTSan::FormatDescription(StructuredData::ObjectSP report) { + std::string description = std::string(report->GetAsDictionary() + ->GetValueForKey("issue_type") + ->GetAsString() + ->GetValue()); if (description == "data-race") { return "Data race"; @@ -536,7 +538,7 @@ static std::string Sprintf(const char *format, ...) { va_start(args, format); s.PrintfVarArg(format, args); va_end(args); - return s.GetString(); + return std::string(s.GetString()); } static std::string GetSymbolNameFromAddress(ProcessSP process_sp, addr_t addr) { @@ -564,15 +566,14 @@ static void GetSymbolDeclarationFromAddress(ProcessSP process_sp, addr_t addr, if (!symbol) return; - ConstString sym_name = symbol->GetMangled().GetName( - lldb::eLanguageTypeUnknown, Mangled::ePreferMangled); + ConstString sym_name = symbol->GetMangled().GetName(Mangled::ePreferMangled); ModuleSP module = symbol->CalculateSymbolContextModule(); if (!module) return; VariableList var_list; - module->FindGlobalVariables(sym_name, nullptr, 1U, var_list); + module->FindGlobalVariables(sym_name, CompilerDeclContext(), 1U, var_list); if (var_list.GetSize() < 1) return; @@ -580,7 +581,7 @@ static void GetSymbolDeclarationFromAddress(ProcessSP process_sp, addr_t addr, decl = var->GetDeclaration(); } -addr_t ThreadSanitizerRuntime::GetFirstNonInternalFramePc( +addr_t InstrumentationRuntimeTSan::GetFirstNonInternalFramePc( StructuredData::ObjectSP trace, bool skip_one_frame) { ProcessSP process_sp = GetProcessSP(); ModuleSP runtime_module_sp = GetRuntimeModuleSP(); @@ -609,13 +610,13 @@ addr_t ThreadSanitizerRuntime::GetFirstNonInternalFramePc( } std::string -ThreadSanitizerRuntime::GenerateSummary(StructuredData::ObjectSP report) { +InstrumentationRuntimeTSan::GenerateSummary(StructuredData::ObjectSP report) { ProcessSP process_sp = GetProcessSP(); - std::string summary = report->GetAsDictionary() - ->GetValueForKey("description") - ->GetAsString() - ->GetValue(); + std::string summary = std::string(report->GetAsDictionary() + ->GetValueForKey("description") + ->GetAsString() + ->GetValue()); bool skip_one_frame = report->GetObjectForDotSeparatedPath("issue_type")->GetStringValue() == "external-race"; @@ -657,10 +658,10 @@ ThreadSanitizerRuntime::GenerateSummary(StructuredData::ObjectSP report) { ->GetValueForKey("locs") ->GetAsArray() ->GetItemAtIndex(0); - std::string object_type = loc->GetAsDictionary() - ->GetValueForKey("object_type") - ->GetAsString() - ->GetValue(); + std::string object_type = std::string(loc->GetAsDictionary() + ->GetValueForKey("object_type") + ->GetAsString() + ->GetValue()); if (!object_type.empty()) { summary = "Race on " + object_type + " object"; } @@ -695,8 +696,8 @@ ThreadSanitizerRuntime::GenerateSummary(StructuredData::ObjectSP report) { return summary; } -addr_t -ThreadSanitizerRuntime::GetMainRacyAddress(StructuredData::ObjectSP report) { +addr_t InstrumentationRuntimeTSan::GetMainRacyAddress( + StructuredData::ObjectSP report) { addr_t result = (addr_t)-1; report->GetObjectForDotSeparatedPath("mops")->GetAsArray()->ForEach( @@ -711,7 +712,7 @@ ThreadSanitizerRuntime::GetMainRacyAddress(StructuredData::ObjectSP report) { return (result == (addr_t)-1) ? 0 : result; } -std::string ThreadSanitizerRuntime::GetLocationDescription( +std::string InstrumentationRuntimeTSan::GetLocationDescription( StructuredData::ObjectSP report, addr_t &global_addr, std::string &global_name, std::string &filename, uint32_t &line) { std::string result = ""; @@ -726,8 +727,8 @@ std::string ThreadSanitizerRuntime::GetLocationDescription( ->GetValueForKey("locs") ->GetAsArray() ->GetItemAtIndex(0); - std::string type = - loc->GetAsDictionary()->GetValueForKey("type")->GetStringValue(); + std::string type = std::string( + loc->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); if (type == "global") { global_addr = loc->GetAsDictionary() ->GetValueForKey("address") @@ -756,10 +757,10 @@ std::string ThreadSanitizerRuntime::GetLocationDescription( ->GetValueForKey("size") ->GetAsInteger() ->GetValue(); - std::string object_type = loc->GetAsDictionary() - ->GetValueForKey("object_type") - ->GetAsString() - ->GetValue(); + std::string object_type = std::string(loc->GetAsDictionary() + ->GetValueForKey("object_type") + ->GetAsString() + ->GetValue()); if (!object_type.empty()) { result = Sprintf("Location is a %ld-byte %s object at 0x%llx", size, object_type.c_str(), addr); @@ -791,15 +792,15 @@ std::string ThreadSanitizerRuntime::GetLocationDescription( return result; } -bool ThreadSanitizerRuntime::NotifyBreakpointHit( +bool InstrumentationRuntimeTSan::NotifyBreakpointHit( void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) { assert(baton && "null baton"); if (!baton) return false; - ThreadSanitizerRuntime *const instance = - static_cast<ThreadSanitizerRuntime *>(baton); + InstrumentationRuntimeTSan *const instance = + static_cast<InstrumentationRuntimeTSan *>(baton); ProcessSP process_sp = instance->GetProcessSP(); @@ -873,12 +874,13 @@ bool ThreadSanitizerRuntime::NotifyBreakpointHit( return false; // Let target run } -const RegularExpression &ThreadSanitizerRuntime::GetPatternForRuntimeLibrary() { +const RegularExpression & +InstrumentationRuntimeTSan::GetPatternForRuntimeLibrary() { static RegularExpression regex(llvm::StringRef("libclang_rt.tsan_")); return regex; } -bool ThreadSanitizerRuntime::CheckIfRuntimeIsValid( +bool InstrumentationRuntimeTSan::CheckIfRuntimeIsValid( const lldb::ModuleSP module_sp) { static ConstString g_tsan_get_current_report("__tsan_get_current_report"); const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( @@ -886,7 +888,7 @@ bool ThreadSanitizerRuntime::CheckIfRuntimeIsValid( return symbol != nullptr; } -void ThreadSanitizerRuntime::Activate() { +void InstrumentationRuntimeTSan::Activate() { if (IsActive()) return; @@ -916,7 +918,7 @@ void ThreadSanitizerRuntime::Activate() { process_sp->GetTarget() .CreateBreakpoint(symbol_address, internal, hardware) .get(); - breakpoint->SetCallback(ThreadSanitizerRuntime::NotifyBreakpointHit, this, + breakpoint->SetCallback(InstrumentationRuntimeTSan::NotifyBreakpointHit, this, true); breakpoint->SetBreakpointKind("thread-sanitizer-report"); SetBreakpointID(breakpoint->GetID()); @@ -924,7 +926,7 @@ void ThreadSanitizerRuntime::Activate() { SetActive(true); } -void ThreadSanitizerRuntime::Deactivate() { +void InstrumentationRuntimeTSan::Deactivate() { if (GetBreakpointID() != LLDB_INVALID_BREAK_ID) { ProcessSP process_sp = GetProcessSP(); if (process_sp) { @@ -977,8 +979,8 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "locs") { - std::string type = - o->GetAsDictionary()->GetValueForKey("type")->GetStringValue(); + std::string type = std::string( + o->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); int thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue(); int fd = @@ -1043,7 +1045,7 @@ static void AddThreadsForPath(const std::string &path, } lldb::ThreadCollectionSP -ThreadSanitizerRuntime::GetBacktracesFromExtendedStopInfo( +InstrumentationRuntimeTSan::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP info) { ThreadCollectionSP threads; threads = std::make_shared<ThreadCollection>(); diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.h index db8bb1db7996..35a878d90aff 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h +++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.h @@ -1,4 +1,4 @@ -//===-- TSanRuntime.h -------------------------------------------*- C++ -*-===// +//===-- InstrumentationRuntimeTSan.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. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ThreadSanitizerRuntime_h_ -#define liblldb_ThreadSanitizerRuntime_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_TSAN_INSTRUMENTATIONRUNTIMETSAN_H +#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_TSAN_INSTRUMENTATIONRUNTIMETSAN_H #include "lldb/Target/ABI.h" #include "lldb/Target/InstrumentationRuntime.h" @@ -16,9 +16,9 @@ namespace lldb_private { -class ThreadSanitizerRuntime : public lldb_private::InstrumentationRuntime { +class InstrumentationRuntimeTSan : public lldb_private::InstrumentationRuntime { public: - ~ThreadSanitizerRuntime() override; + ~InstrumentationRuntimeTSan() override; static lldb::InstrumentationRuntimeSP CreateInstance(const lldb::ProcessSP &process_sp); @@ -43,7 +43,7 @@ public: GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override; private: - ThreadSanitizerRuntime(const lldb::ProcessSP &process_sp) + InstrumentationRuntimeTSan(const lldb::ProcessSP &process_sp) : lldb_private::InstrumentationRuntime(process_sp) {} const RegularExpression &GetPatternForRuntimeLibrary() override; @@ -78,4 +78,4 @@ private: } // namespace lldb_private -#endif // liblldb_ThreadSanitizerRuntime_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_TSAN_INSTRUMENTATIONRUNTIMETSAN_H diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index 137ecab224bc..b60eb53f3d4a 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -1,4 +1,4 @@ -//===-- UBSanRuntime.cpp ----------------------------------------*- C++ -*-===// +//===-- InstrumentationRuntimeUBSan.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "UBSanRuntime.h" +#include "InstrumentationRuntimeUBSan.h" #include "Plugins/Process/Utility/HistoryThread.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -36,35 +36,31 @@ using namespace lldb; using namespace lldb_private; -UndefinedBehaviorSanitizerRuntime::~UndefinedBehaviorSanitizerRuntime() { - Deactivate(); -} +LLDB_PLUGIN_DEFINE(InstrumentationRuntimeUBSan) + +InstrumentationRuntimeUBSan::~InstrumentationRuntimeUBSan() { Deactivate(); } lldb::InstrumentationRuntimeSP -UndefinedBehaviorSanitizerRuntime::CreateInstance( - const lldb::ProcessSP &process_sp) { - return InstrumentationRuntimeSP( - new UndefinedBehaviorSanitizerRuntime(process_sp)); +InstrumentationRuntimeUBSan::CreateInstance(const lldb::ProcessSP &process_sp) { + return InstrumentationRuntimeSP(new InstrumentationRuntimeUBSan(process_sp)); } -void UndefinedBehaviorSanitizerRuntime::Initialize() { +void InstrumentationRuntimeUBSan::Initialize() { PluginManager::RegisterPlugin( GetPluginNameStatic(), "UndefinedBehaviorSanitizer instrumentation runtime plugin.", CreateInstance, GetTypeStatic); } -void UndefinedBehaviorSanitizerRuntime::Terminate() { +void InstrumentationRuntimeUBSan::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString -UndefinedBehaviorSanitizerRuntime::GetPluginNameStatic() { +lldb_private::ConstString InstrumentationRuntimeUBSan::GetPluginNameStatic() { return ConstString("UndefinedBehaviorSanitizer"); } -lldb::InstrumentationRuntimeType -UndefinedBehaviorSanitizerRuntime::GetTypeStatic() { +lldb::InstrumentationRuntimeType InstrumentationRuntimeUBSan::GetTypeStatic() { return eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer; } @@ -110,7 +106,7 @@ static std::string RetrieveString(ValueObjectSP return_value_sp, return str; } -StructuredData::ObjectSP UndefinedBehaviorSanitizerRuntime::RetrieveReportData( +StructuredData::ObjectSP InstrumentationRuntimeUBSan::RetrieveReportData( ExecutionContextRef exe_ctx_ref) { ProcessSP process_sp = GetProcessSP(); if (!process_sp) @@ -187,9 +183,10 @@ StructuredData::ObjectSP UndefinedBehaviorSanitizerRuntime::RetrieveReportData( static std::string GetStopReasonDescription(StructuredData::ObjectSP report) { llvm::StringRef stop_reason_description_ref; - report->GetAsDictionary()->GetValueForKeyAsString("description", - stop_reason_description_ref); - std::string stop_reason_description = stop_reason_description_ref; + report->GetAsDictionary()->GetValueForKeyAsString( + "description", stop_reason_description_ref); + std::string stop_reason_description = + std::string(stop_reason_description_ref); if (!stop_reason_description.size()) { stop_reason_description = "Undefined behavior detected"; @@ -202,15 +199,15 @@ static std::string GetStopReasonDescription(StructuredData::ObjectSP report) { return stop_reason_description; } -bool UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit( +bool InstrumentationRuntimeUBSan::NotifyBreakpointHit( void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) { assert(baton && "null baton"); if (!baton) return false; ///< false => resume execution. - UndefinedBehaviorSanitizerRuntime *const instance = - static_cast<UndefinedBehaviorSanitizerRuntime *>(baton); + InstrumentationRuntimeUBSan *const instance = + static_cast<InstrumentationRuntimeUBSan *>(baton); ProcessSP process_sp = instance->GetProcessSP(); ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); @@ -235,12 +232,12 @@ bool UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit( } const RegularExpression & -UndefinedBehaviorSanitizerRuntime::GetPatternForRuntimeLibrary() { +InstrumentationRuntimeUBSan::GetPatternForRuntimeLibrary() { static RegularExpression regex(llvm::StringRef("libclang_rt\\.(a|t|ub)san_")); return regex; } -bool UndefinedBehaviorSanitizerRuntime::CheckIfRuntimeIsValid( +bool InstrumentationRuntimeUBSan::CheckIfRuntimeIsValid( const lldb::ModuleSP module_sp) { static ConstString ubsan_test_sym("__ubsan_on_report"); const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( @@ -249,7 +246,7 @@ bool UndefinedBehaviorSanitizerRuntime::CheckIfRuntimeIsValid( } // FIXME: Factor out all the logic we have in common with the {a,t}san plugins. -void UndefinedBehaviorSanitizerRuntime::Activate() { +void InstrumentationRuntimeUBSan::Activate() { if (IsActive()) return; @@ -280,15 +277,15 @@ void UndefinedBehaviorSanitizerRuntime::Activate() { .CreateBreakpoint(symbol_address, /*internal=*/true, /*hardware=*/false) .get(); - breakpoint->SetCallback( - UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit, this, true); + breakpoint->SetCallback(InstrumentationRuntimeUBSan::NotifyBreakpointHit, + this, true); breakpoint->SetBreakpointKind("undefined-behavior-sanitizer-report"); SetBreakpointID(breakpoint->GetID()); SetActive(true); } -void UndefinedBehaviorSanitizerRuntime::Deactivate() { +void InstrumentationRuntimeUBSan::Deactivate() { SetActive(false); auto BID = GetBreakpointID(); @@ -302,7 +299,7 @@ void UndefinedBehaviorSanitizerRuntime::Deactivate() { } lldb::ThreadCollectionSP -UndefinedBehaviorSanitizerRuntime::GetBacktracesFromExtendedStopInfo( +InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP info) { ThreadCollectionSP threads; threads = std::make_shared<ThreadCollection>(); diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.h index 1d854b7bf06f..813c30069600 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.h @@ -1,4 +1,4 @@ -//===-- UBSanRuntime.h ------------------------------------------*- C++ -*-===// +//===-- InstrumentationRuntimeUBSan.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. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_UndefinedBehaviorSanitizerRuntime_h_ -#define liblldb_UndefinedBehaviorSanitizerRuntime_h_ +#ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UBSAN_INSTRUMENTATIONRUNTIMEUBSAN_H +#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UBSAN_INSTRUMENTATIONRUNTIMEUBSAN_H #include "lldb/Target/ABI.h" #include "lldb/Target/InstrumentationRuntime.h" @@ -16,10 +16,10 @@ namespace lldb_private { -class UndefinedBehaviorSanitizerRuntime +class InstrumentationRuntimeUBSan : public lldb_private::InstrumentationRuntime { public: - ~UndefinedBehaviorSanitizerRuntime() override; + ~InstrumentationRuntimeUBSan() override; static lldb::InstrumentationRuntimeSP CreateInstance(const lldb::ProcessSP &process_sp); @@ -44,7 +44,7 @@ public: GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override; private: - UndefinedBehaviorSanitizerRuntime(const lldb::ProcessSP &process_sp) + InstrumentationRuntimeUBSan(const lldb::ProcessSP &process_sp) : lldb_private::InstrumentationRuntime(process_sp) {} const RegularExpression &GetPatternForRuntimeLibrary() override; @@ -65,4 +65,4 @@ private: } // namespace lldb_private -#endif // liblldb_UndefinedBehaviorSanitizerRuntime_h_ +#endif // LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UBSAN_INSTRUMENTATIONRUNTIMEUBSAN_H diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index fff44123539f..cbeef600ba9b 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -1,4 +1,4 @@ -//===-- JITLoaderGDB.cpp ----------------------------------------*- C++ -*-===// +//===-- JITLoaderGDB.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,6 +32,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(JITLoaderGDB) + // Debug Interface Structures enum jit_actions_t { JIT_NOACTION = 0, JIT_REGISTER_FN, JIT_UNREGISTER_FN }; @@ -132,9 +134,9 @@ bool ReadJITEntry(const addr_t from_addr, Process *process, DataExtractor extractor(data.GetBytes(), data.GetByteSize(), process->GetByteOrder(), sizeof(ptr_t)); lldb::offset_t offset = 0; - entry->next_entry = extractor.GetPointer(&offset); - entry->prev_entry = extractor.GetPointer(&offset); - entry->symfile_addr = extractor.GetPointer(&offset); + entry->next_entry = extractor.GetAddress(&offset); + entry->prev_entry = extractor.GetAddress(&offset); + entry->symfile_addr = extractor.GetAddress(&offset); offset = llvm::alignTo(offset, uint64_align_bytes); entry->symfile_size = extractor.GetU64(&offset); diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.h b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.h index 2a2537c3edd4..42377f435293 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.h +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_JITLoaderGDB_h_ -#define liblldb_JITLoaderGDB_h_ +#ifndef LLDB_SOURCE_PLUGINS_JITLOADER_GDB_JITLOADERGDB_H +#define LLDB_SOURCE_PLUGINS_JITLOADER_GDB_JITLOADERGDB_H #include <map> @@ -77,4 +77,4 @@ private: lldb::addr_t m_jit_descriptor_addr; }; -#endif // liblldb_JITLoaderGDB_h_ +#endif // LLDB_SOURCE_PLUGINS_JITLOADER_GDB_JITLOADERGDB_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index 5cfd978774fd..42f6bd9ffb7b 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -1,4 +1,4 @@ -//===-- BlockPointer.cpp ----------------------------------------*- C++ -*-===// +//===-- BlockPointer.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,14 +8,14 @@ #include "BlockPointer.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" - #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" @@ -45,18 +45,24 @@ public: if (auto err = type_system_or_err.takeError()) { LLDB_LOG_ERROR( lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS), - std::move(err), "Failed to get scratch ClangASTContext"); + std::move(err), "Failed to get scratch TypeSystemClang"); return; } - ClangASTContext *clang_ast_context = - llvm::dyn_cast<ClangASTContext>(&type_system_or_err.get()); + TypeSystemClang *clang_ast_context = + llvm::dyn_cast<TypeSystemClang>(&type_system_or_err.get()); if (!clang_ast_context) { return; } - ClangASTImporterSP clang_ast_importer = target_sp->GetClangASTImporter(); + 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; diff --git a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h index 624c17a6a6af..23f3f7b34b4f 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h +++ b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_BlockPointer_h_ -#define liblldb_BlockPointer_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_BLOCKPOINTER_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_BLOCKPOINTER_H #include "lldb/lldb-forward.h" @@ -22,4 +22,4 @@ BlockPointerSyntheticFrontEndCreator(CXXSyntheticChildren *, } // namespace formatters } // namespace lldb_private -#endif // liblldb_BlockPointer_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_BLOCKPOINTER_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 4385a60f5862..08e43ae6b3e8 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1,4 +1,4 @@ -//===-- CPlusPlusLanguage.cpp -----------------------------------*- C++ -*-===// +//===-- CPlusPlusLanguage.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -43,6 +43,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +LLDB_PLUGIN_DEFINE(CPlusPlusLanguage) + void CPlusPlusLanguage::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language", CreateInstance); @@ -68,7 +70,9 @@ uint32_t CPlusPlusLanguage::GetPluginVersion() { return 1; } // Static Functions Language *CPlusPlusLanguage::CreateInstance(lldb::LanguageType language) { - if (Language::LanguageIsCPlusPlus(language)) + // Use plugin for C++ but not for Objective-C++ (which has its own plugin). + if (Language::LanguageIsCPlusPlus(language) && + language != eLanguageTypeObjC_plus_plus) return new CPlusPlusLanguage(); return nullptr; } @@ -125,7 +129,7 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) { return false; // Empty string or "~" if (!std::isalpha(basename[idx]) && basename[idx] != '_') - return false; // First charater (after removing the possible '~'') isn't in + return false; // First character (after removing the possible '~'') isn't in // [A-Za-z_] // Read all characters matching [A-Za-z_0-9] @@ -230,7 +234,7 @@ std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() { if (!m_parsed) Parse(); if (m_context.empty()) - return m_basename; + return std::string(m_basename); std::string res; res += m_context; @@ -609,6 +613,15 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "shared_ptr synthetic children", ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + + ConstString libcxx_std_unique_ptr_regex( + "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$"); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator, + "unique_ptr synthetic children", libcxx_std_unique_ptr_regex, + stl_synth_flags, true); + AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, @@ -713,6 +726,10 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "libc++ std::weak_ptr summary provider", ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxUniquePointerSummaryProvider, + "libc++ std::unique_ptr summary provider", + libcxx_std_unique_ptr_regex, stl_summary_flags, true); AddCXXSynthetic( cpp_category_sp, diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index 4ed45bc904ce..89dea08a2c53 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_CPlusPlusLanguage_h_ -#define liblldb_CPlusPlusLanguage_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSLANGUAGE_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSLANGUAGE_H #include <set> #include <vector> @@ -133,4 +133,4 @@ public: } // namespace lldb_private -#endif // liblldb_CPlusPlusLanguage_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSLANGUAGE_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index 932db17b964a..eca36fff18f8 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -1,4 +1,4 @@ -//===-- CPlusPlusNameParser.cpp ---------------------------------*- C++ -*-===// +//===-- CPlusPlusNameParser.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -329,6 +329,37 @@ bool CPlusPlusNameParser::ConsumeOperator() { } const auto &token = Peek(); + + // When clang generates debug info it adds template parameters to names. + // Since clang doesn't add a space between the name and the template parameter + // in some cases we are not generating valid C++ names e.g.: + // + // operator<<A::B> + // + // In some of these cases we will not parse them correctly. This fixes the + // issue by detecting this case and inserting tok::less in place of + // tok::lessless and returning successfully that we consumed the operator. + if (token.getKind() == tok::lessless) { + // Make sure we have more tokens before attempting to look ahead one more. + if (m_next_token_index + 1 < m_tokens.size()) { + // Look ahead two tokens. + clang::Token n_token = m_tokens[m_next_token_index + 1]; + // If we find ( or < then this is indeed operator<< no need for fix. + if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) { + clang::Token tmp_tok; + tmp_tok.startToken(); + tmp_tok.setLength(1); + tmp_tok.setLocation(token.getLocation().getLocWithOffset(1)); + tmp_tok.setKind(tok::less); + + m_tokens[m_next_token_index] = tmp_tok; + + start_position.Remove(); + return true; + } + } + } + switch (token.getKind()) { case tok::kw_new: case tok::kw_delete: diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h index 414c3a009157..6fe6b12725b0 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h @@ -6,9 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_CPlusPlusNameParser_h_ -#define liblldb_CPlusPlusNameParser_h_ - +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H #include "clang/Lex/Lexer.h" #include "llvm/ADT/Optional.h" @@ -174,4 +173,4 @@ private: } // namespace lldb_private -#endif // liblldb_CPlusPlusNameParser_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp index 3ea7589d8e4a..41bbd2b01a1e 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp @@ -1,4 +1,4 @@ -//===-- CxxStringTypes.cpp --------------------------------------*- C++ -*-===// +//===-- CxxStringTypes.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,13 +10,13 @@ #include "llvm/Support/ConvertUTF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/Host/Time.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h index 35498b3b568f..2713ded45929 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h +++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_CxxStringTypes_h_ -#define liblldb_CxxStringTypes_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -46,4 +46,4 @@ bool WCharSummaryProvider(ValueObject &valobj, Stream &stream, } // namespace formatters } // namespace lldb_private -#endif // liblldb_CxxStringTypes_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index ecadaef7a87e..84dd09a47d8a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -1,4 +1,4 @@ -//===-- LibCxx.cpp ----------------------------------------------*- C++ -*-===// +//===-- LibCxx.cpp --------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,7 +8,6 @@ #include "LibCxx.h" -#include "llvm/ADT/ScopeExit.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/FormatEntity.h" #include "lldb/Core/ValueObject.h" @@ -17,7 +16,6 @@ #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" @@ -27,6 +25,7 @@ #include "lldb/Utility/Stream.h" #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace lldb; using namespace lldb_private; @@ -145,6 +144,43 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( return true; } +bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp( + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + if (!ptr_sp) + return false; + + if (ptr_sp->GetValueAsUnsigned(0) == 0) { + stream.Printf("nullptr"); + return true; + } else { + bool print_pointee = false; + Status error; + ValueObjectSP pointee_sp = ptr_sp->Dereference(error); + if (pointee_sp && error.Success()) { + if (pointee_sp->DumpPrintableRepresentation( + stream, ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::PrintableRepresentationSpecialCases::eDisable, + false)) + print_pointee = true; + } + if (!print_pointee) + stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); + } + + return true; +} + /* (lldb) fr var ibeg --raw --ptr-depth 1 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, @@ -241,8 +277,8 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); m_pair_ptr = nullptr; if (addr && addr != LLDB_INVALID_ADDRESS) { - ClangASTContext *ast_ctx = - llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); + TypeSystemClang *ast_ctx = + llvm::dyn_cast_or_null<TypeSystemClang>(pair_type.GetTypeSystem()); if (!ast_ctx) return false; CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( @@ -450,6 +486,67 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( : nullptr); } +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_compressed_pair_sp() { + if (valobj_sp) + Update(); +} + +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + ~LibcxxUniquePtrSyntheticFrontEnd() = default; + +SyntheticChildrenFrontEnd * +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp) + : nullptr); +} + +size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + CalculateNumChildren() { + return (m_compressed_pair_sp ? 1 : 0); +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex( + size_t idx) { + if (!m_compressed_pair_sp) + return lldb::ValueObjectSP(); + + if (idx != 0) + return lldb::ValueObjectSP(); + + return m_compressed_pair_sp; +} + +bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp( + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + + return false; +} + +bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "__value_") + return 0; + return UINT32_MAX; +} + bool lldb_private::formatters::LibcxxContainerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { if (valobj.IsPointerType()) { @@ -469,22 +566,20 @@ enum LibcxxStringLayoutMode { eLibcxxStringLayoutModeInvalid = 0xffff }; -// this function abstracts away the layout and mode details of a libc++ string -// and returns the address of the data and the size ready for callers to -// consume -static bool ExtractLibcxxStringInfo(ValueObject &valobj, - ValueObjectSP &location_sp, - uint64_t &size) { +/// Determine the size in bytes of \p valobj (a libc++ std::string object) and +/// extract its data payload. Return the size + payload pair. +static llvm::Optional<std::pair<uint64_t, ValueObjectSP>> +ExtractLibcxxStringInfo(ValueObject &valobj) { ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); if (!D) - return false; + return {}; ValueObjectSP layout_decider( D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); // this child should exist if (!layout_decider) - return false; + return {}; ConstString g_data_name("__data_"); ConstString g_size_name("__size_"); @@ -498,13 +593,13 @@ static bool ExtractLibcxxStringInfo(ValueObject &valobj, if (layout == eLibcxxStringLayoutModeDSC) { ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); if (!size_mode) - return false; + return {}; if (size_mode->GetName() != g_size_name) { // we are hitting the padding structure, move along size_mode = D->GetChildAtIndexPath({1, 1, 1}); if (!size_mode) - return false; + return {}; } size_mode_value = (size_mode->GetValueAsUnsigned(0)); @@ -512,7 +607,7 @@ static bool ExtractLibcxxStringInfo(ValueObject &valobj, } else { ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); if (!size_mode) - return false; + return {}; size_mode_value = (size_mode->GetValueAsUnsigned(0)); short_mode = ((size_mode_value & 1) == 0); @@ -521,36 +616,58 @@ static bool ExtractLibcxxStringInfo(ValueObject &valobj, if (short_mode) { ValueObjectSP s(D->GetChildAtIndex(1, true)); if (!s) - return false; - location_sp = s->GetChildAtIndex( + return {}; + ValueObjectSP location_sp = s->GetChildAtIndex( (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); - size = (layout == eLibcxxStringLayoutModeDSC) - ? size_mode_value - : ((size_mode_value >> 1) % 256); - return (location_sp.get() != nullptr); - } else { - ValueObjectSP l(D->GetChildAtIndex(0, true)); - if (!l) - return false; - // we can use the layout_decider object as the data pointer - location_sp = (layout == eLibcxxStringLayoutModeDSC) - ? layout_decider - : l->GetChildAtIndex(2, true); - ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); - if (!size_vo || !location_sp) - return false; - size = size_vo->GetValueAsUnsigned(0); - return true; + const uint64_t size = (layout == eLibcxxStringLayoutModeDSC) + ? size_mode_value + : ((size_mode_value >> 1) % 256); + + // When the small-string optimization takes place, the data must fit in the + // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's + // likely that the string isn't initialized and we're reading garbage. + ExecutionContext exe_ctx(location_sp->GetExecutionContextRef()); + const llvm::Optional<uint64_t> max_bytes = + location_sp->GetCompilerType().GetByteSize( + exe_ctx.GetBestExecutionContextScope()); + if (!max_bytes || size > *max_bytes || !location_sp) + return {}; + + return std::make_pair(size, location_sp); } + + ValueObjectSP l(D->GetChildAtIndex(0, true)); + if (!l) + return {}; + // we can use the layout_decider object as the data pointer + ValueObjectSP location_sp = (layout == eLibcxxStringLayoutModeDSC) + ? layout_decider + : l->GetChildAtIndex(2, true); + ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); + const unsigned capacity_index = + (layout == eLibcxxStringLayoutModeDSC) ? 2 : 0; + ValueObjectSP capacity_vo(l->GetChildAtIndex(capacity_index, true)); + if (!size_vo || !location_sp || !capacity_vo) + return {}; + const uint64_t size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); + const uint64_t capacity = + capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); + if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET || + capacity < size) + return {}; + return std::make_pair(size, location_sp); } bool lldb_private::formatters::LibcxxWStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - uint64_t size = 0; - ValueObjectSP location_sp; - if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) + auto string_info = ExtractLibcxxStringInfo(valobj); + if (!string_info) return false; + uint64_t size; + ValueObjectSP location_sp; + std::tie(size, location_sp) = *string_info; + if (size == 0) { stream.Printf("L\"\""); return true; @@ -558,10 +675,8 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( if (!location_sp) return false; - DataExtractor extractor; StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); - if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); if (size > max_size) { @@ -569,11 +684,15 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( options.SetIsTruncated(true); } } - location_sp->GetPointeeData(extractor, 0, size); + + DataExtractor extractor; + const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); + if (bytes_read < size) + return false; // std::wstring::size() is measured in 'characters', not bytes - ClangASTContext *ast_context = - ClangASTContext::GetScratch(*valobj.GetTargetSP()); + TypeSystemClang *ast_context = + TypeSystemClang::GetScratch(*valobj.GetTargetSP()); if (!ast_context) return false; @@ -591,40 +710,35 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( switch (*wchar_t_size) { case 1: - StringPrinter::ReadBufferAndDumpToStream< + return StringPrinter::ReadBufferAndDumpToStream< lldb_private::formatters::StringPrinter::StringElementType::UTF8>( options); break; case 2: - lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< + return StringPrinter::ReadBufferAndDumpToStream< lldb_private::formatters::StringPrinter::StringElementType::UTF16>( options); break; case 4: - lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< + return StringPrinter::ReadBufferAndDumpToStream< lldb_private::formatters::StringPrinter::StringElementType::UTF32>( options); - break; - - default: - stream.Printf("size for wchar_t is not valid"); - return true; } - - return true; + return false; } template <StringPrinter::StringElementType element_type> bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, - std::string prefix_token = "") { - uint64_t size = 0; - ValueObjectSP location_sp; - - if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) + std::string prefix_token) { + auto string_info = ExtractLibcxxStringInfo(valobj); + if (!string_info) return false; + uint64_t size; + ValueObjectSP location_sp; + std::tie(size, location_sp) = *string_info; if (size == 0) { stream.Printf("\"\""); @@ -636,7 +750,6 @@ bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); - DataExtractor extractor; if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); if (size > max_size) { @@ -644,41 +757,55 @@ bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, options.SetIsTruncated(true); } } - location_sp->GetPointeeData(extractor, 0, size); + + DataExtractor extractor; + const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); + if (bytes_read < size) + return false; options.SetData(extractor); options.SetStream(&stream); - if (prefix_token.empty()) options.SetPrefixToken(nullptr); else options.SetPrefixToken(prefix_token); - options.SetQuote('"'); options.SetSourceSize(size); options.SetBinaryZeroIsTerminator(false); - StringPrinter::ReadBufferAndDumpToStream<element_type>(options); + return StringPrinter::ReadBufferAndDumpToStream<element_type>(options); +} +template <StringPrinter::StringElementType element_type> +static bool formatStringImpl(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token) { + StreamString scratch_stream; + const bool success = LibcxxStringSummaryProvider<element_type>( + valobj, scratch_stream, summary_options, prefix_token); + if (success) + stream << scratch_stream.GetData(); + else + stream << "Summary Unavailable"; return true; } bool lldb_private::formatters::LibcxxStringSummaryProviderASCII( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - return LibcxxStringSummaryProvider<StringPrinter::StringElementType::ASCII>( - valobj, stream, summary_options); + return formatStringImpl<StringPrinter::StringElementType::ASCII>( + valobj, stream, summary_options, ""); } bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF16>( + return formatStringImpl<StringPrinter::StringElementType::UTF16>( valobj, stream, summary_options, "u"); } bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF32>( + return formatStringImpl<StringPrinter::StringElementType::UTF32>( valobj, stream, summary_options, "U"); } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index 214f5512e4a5..ea5a7c178178 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_LibCxx_h_ -#define liblldb_LibCxx_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXX_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXX_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -43,6 +43,10 @@ bool LibcxxSmartPointerSummaryProvider( const TypeSummaryOptions &options); // libc++ std::shared_ptr<> and std::weak_ptr<> +// libc++ std::unique_ptr<> +bool LibcxxUniquePointerSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + bool LibcxxFunctionSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::function<> @@ -107,6 +111,26 @@ private: lldb::ByteOrder m_byte_order; }; +class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + + ~LibcxxUniquePtrSyntheticFrontEnd() override; + +private: + lldb::ValueObjectSP m_compressed_pair_sp; +}; + SyntheticChildrenFrontEnd * LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -116,6 +140,10 @@ LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); SyntheticChildrenFrontEnd * +LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + +SyntheticChildrenFrontEnd * LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -156,4 +184,4 @@ LibcxxVariantFrontEndCreator(CXXSyntheticChildren *, } // namespace formatters } // namespace lldb_private -#endif // liblldb_LibCxx_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXX_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp index b4e7a1703e46..45d4322e93d7 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp @@ -1,5 +1,4 @@ -//===-- LibCxxAtomic.cpp ------------------------------------------*- C++ -//-*-===// +//===-- LibCxxAtomic.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "LibCxxAtomic.h" +#include "lldb/DataFormatters/FormattersHelpers.h" using namespace lldb; using namespace lldb_private; @@ -101,8 +101,6 @@ public: size_t GetIndexOfChildWithName(ConstString name) override; - lldb::ValueObjectSP GetSyntheticValue() override; - private: ValueObject *m_real_child; }; @@ -128,26 +126,20 @@ bool lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: size_t lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: CalculateNumChildren() { - return m_real_child ? m_real_child->GetNumChildren() : 0; + return m_real_child ? 1 : 0; } lldb::ValueObjectSP lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::GetChildAtIndex( size_t idx) { - return m_real_child ? m_real_child->GetChildAtIndex(idx, true) : nullptr; + if (idx == 0) + return m_real_child->GetSP()->Clone(ConstString("Value")); + return nullptr; } size_t lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { - return m_real_child ? m_real_child->GetIndexOfChildWithName(name) - : UINT32_MAX; -} - -lldb::ValueObjectSP lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: - GetSyntheticValue() { - if (m_real_child && m_real_child->CanProvideValue()) - return m_real_child->GetSP(); - return nullptr; + return formatters::ExtractIndexFromString(name.GetCString()); } SyntheticChildrenFrontEnd * diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h index 8be833dd82f6..6fcceb645c7b 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_LibCxxAtomic_h_ -#define liblldb_LibCxxAtomic_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXATOMIC_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXATOMIC_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -30,4 +30,4 @@ LibcxxAtomicSyntheticFrontEndCreator(CXXSyntheticChildren *, } // namespace formatters } // namespace lldb_private -#endif // liblldb_LibCxxAtomic_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXATOMIC_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp index 78c453cd1b3c..6de4637a6a4a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxBitset.cpp ----------------------------------------*- C++ -*-===// +//===-- LibCxxBitset.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" using namespace lldb; diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp index 79c7434f617f..65e88d114fcc 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxInitializerList.cpp -------------------------------*- C++ -*-===// +//===-- LibCxxInitializerList.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index f5281f2ce532..0d5ae16a0b29 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxList.cpp ------------------------------------------*- C++ -*-===// +//===-- LibCxxList.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" @@ -290,15 +290,6 @@ ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) { m_element_type); } -static ValueObjectSP GetValueOfCompressedPair(ValueObject &pair) { - ValueObjectSP value = pair.GetChildMemberWithName(ConstString("__value_"), true); - if (! value) { - // pre-r300140 member name - value = pair.GetChildMemberWithName(ConstString("__first_"), true); - } - return value; -} - bool ForwardListFrontEnd::Update() { AbstractListFrontEnd::Update(); @@ -311,7 +302,7 @@ bool ForwardListFrontEnd::Update() { m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true)); if (!impl_sp) return false; - impl_sp = GetValueOfCompressedPair(*impl_sp); + impl_sp = GetValueOfLibCXXCompressedPair(*impl_sp); if (!impl_sp) return false; m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); @@ -332,7 +323,7 @@ size_t ListFrontEnd::CalculateNumChildren() { ValueObjectSP size_alloc( m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true)); if (size_alloc) { - ValueObjectSP value = GetValueOfCompressedPair(*size_alloc); + ValueObjectSP value = GetValueOfLibCXXCompressedPair(*size_alloc); if (value) { m_count = value->GetValueAsUnsigned(UINT32_MAX); } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index f6d8d4d9a7eb..64a199e24e4a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxMap.cpp -------------------------------------------*- C++ -*-===// +//===-- LibCxxMap.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" @@ -298,8 +298,8 @@ void lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset( UINT32_MAX) { m_skip_size = bit_offset / 8u; } else { - ClangASTContext *ast_ctx = - llvm::dyn_cast_or_null<ClangASTContext>(node_type.GetTypeSystem()); + TypeSystemClang *ast_ctx = + llvm::dyn_cast_or_null<TypeSystemClang>(node_type.GetTypeSystem()); if (!ast_ctx) return; CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp index b1ad171d0b0c..c0c819632851 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxOptional.cpp --------------------------------------*- C++ -*-===// +//===-- LibCxxOptional.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -26,11 +26,12 @@ public: bool MightHaveChildren() override { return true; } bool Update() override; - size_t CalculateNumChildren() override { return m_size; } + size_t CalculateNumChildren() override { return m_has_value ? 1U : 0U; } ValueObjectSP GetChildAtIndex(size_t idx) override; private: - size_t m_size = 0; + /// True iff the option contains a value. + bool m_has_value = false; }; } // namespace @@ -44,13 +45,13 @@ bool OptionalFrontEnd::Update() { // __engaged_ is a bool flag and is true if the optional contains a value. // Converting it to unsigned gives us a size of 1 if it contains a value // and 0 if not. - m_size = engaged_sp->GetValueAsUnsigned(0); + m_has_value = engaged_sp->GetValueAsUnsigned(0) == 1; return false; } ValueObjectSP OptionalFrontEnd::GetChildAtIndex(size_t idx) { - if (idx >= m_size) + if (!m_has_value) return ValueObjectSP(); // __val_ contains the underlying value of an optional if it has one. @@ -71,7 +72,7 @@ ValueObjectSP OptionalFrontEnd::GetChildAtIndex(size_t idx) { if (!holder_type) return ValueObjectSP(); - return val_sp->Clone(ConstString(llvm::formatv("Value").str())); + return val_sp->Clone(ConstString("Value")); } SyntheticChildrenFrontEnd * diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp index 2f06d684f953..616ffdca107d 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxQueue.cpp -----------------------------------------*- C++ -*-===// +//===-- LibCxxQueue.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp index 45294e25f0f5..a113fe98c6b6 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxTuple.cpp -----------------------------------------*- C++ -*-===// +//===-- LibCxxTuple.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index b2c38c915c81..3a441973fc73 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxUnorderedMap.cpp ----------------------------------*- C++ -*-===// +//===-- LibCxxUnorderedMap.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp index 62945bd3ce80..951bf2896fb0 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxVariant.cpp --------------------------------------*- C++ -*-===// +//===-- LibCxxVariant.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -60,10 +60,10 @@ using namespace lldb_private; namespace { // libc++ std::variant index could have one of three states -// 1) VALID, we can obtain it and its not variant_npos -// 2) INVALID, we can't obtain it or it is not a type we expect -// 3) NPOS, its value is variant_npos which means the variant has no value -enum class LibcxxVariantIndexValidity { VALID, INVALID, NPOS }; +// 1) Valid, we can obtain it and its not variant_npos +// 2) Invalid, we can't obtain it or it is not a type we expect +// 3) NPos, its value is variant_npos which means the variant has no value +enum class LibcxxVariantIndexValidity { Valid, Invalid, NPos }; LibcxxVariantIndexValidity LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) { @@ -71,14 +71,14 @@ LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) { impl_sp->GetChildMemberWithName(ConstString("__index"), true)); if (!index_sp) - return LibcxxVariantIndexValidity::INVALID; + return LibcxxVariantIndexValidity::Invalid; int64_t index_value = index_sp->GetValueAsSigned(0); if (index_value == -1) - return LibcxxVariantIndexValidity::NPOS; + return LibcxxVariantIndexValidity::NPos; - return LibcxxVariantIndexValidity::VALID; + return LibcxxVariantIndexValidity::Valid; } llvm::Optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) { @@ -129,10 +129,10 @@ bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream, LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp); - if (validity == LibcxxVariantIndexValidity::INVALID) + if (validity == LibcxxVariantIndexValidity::Invalid) return false; - if (validity == LibcxxVariantIndexValidity::NPOS) { + if (validity == LibcxxVariantIndexValidity::NPos) { stream.Printf(" No Value"); return true; } @@ -159,7 +159,7 @@ bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream, if (!template_type) return false; - stream.Printf(" Active Type = %s ", template_type.GetTypeName().GetCString()); + stream << " Active Type = " << template_type.GetDisplayTypeName() << " "; return true; } @@ -196,10 +196,10 @@ bool VariantFrontEnd::Update() { LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp); - if (validity == LibcxxVariantIndexValidity::INVALID) + if (validity == LibcxxVariantIndexValidity::Invalid) return false; - if (validity == LibcxxVariantIndexValidity::NPOS) + if (validity == LibcxxVariantIndexValidity::NPos) return true; m_size = 1; @@ -242,7 +242,7 @@ ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) { if (!head_value) return ValueObjectSP(); - return head_value->Clone(ConstString(ConstString("Value").AsCString())); + return head_value->Clone(ConstString("Value")); } SyntheticChildrenFrontEnd * diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h index 65db5aeaa99d..b4c27ccb9d77 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_LibCxxVariant_h_ -#define liblldb_LibCxxVariant_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXVARIANT_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXVARIANT_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -27,4 +27,4 @@ SyntheticChildrenFrontEnd *LibcxxVariantFrontEndCreator(CXXSyntheticChildren *, } // namespace formatters } // namespace lldb_private -#endif // liblldb_LibCxxVariant_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXVARIANT_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp index bcd7442bc669..43f76b0df810 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp @@ -1,4 +1,4 @@ -//===-- LibCxxVector.cpp ----------------------------------------*- C++ -*-===// +//===-- LibCxxVector.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index 0e0f6663c924..b4af67ecee0d 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -1,4 +1,4 @@ -//===-- LibStdcpp.cpp -------------------------------------------*- C++ -*-===// +//===-- LibStdcpp.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,11 +8,11 @@ #include "LibStdcpp.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" @@ -259,6 +259,7 @@ bool lldb_private::formatters::LibStdcppStringSummaryProvider( if (error.Fail()) return false; options.SetSourceSize(size_of_data); + options.SetHasSourceSize(true); if (!StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF8>(options)) { @@ -319,6 +320,7 @@ bool lldb_private::formatters::LibStdcppWStringSummaryProvider( if (error.Fail()) return false; options.SetSourceSize(size_of_data); + options.SetHasSourceSize(true); options.SetPrefixToken("L"); switch (wchar_size) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h index e7f88d667c14..9e41aa0ffc01 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_LibStdCpp_h_ -#define liblldb_LibStdCpp_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBSTDCPP_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBSTDCPP_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -56,4 +56,4 @@ LibStdcppUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *, } // namespace formatters } // namespace lldb_private -#endif // liblldb_LibStdCpp_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBSTDCPP_H diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp index 0ac7b8f8e02b..7ba59ff9d1ad 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp @@ -1,4 +1,4 @@ -//===-- LibStdcppTuple.cpp --------------------------------------*- C++ -*-===// +//===-- LibStdcppTuple.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp index cceb511cdc46..0b34b4e2fc89 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp @@ -1,4 +1,4 @@ -//===-- LibStdcppUniquePointer.cpp ------------------------------*- C++ -*-===// +//===-- LibStdcppUniquePointer.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp index 248c51acea42..b24bcc1344e2 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp @@ -1,4 +1,4 @@ -//===-- MSVCUndecoratedNameParser.cpp ---------------------------*- C++ -*-===// +//===-- MSVCUndecoratedNameParser.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h b/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h index 6e20877cae1b..e5b60a0a1d5b 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h +++ b/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_MSVCUndecoratedNameParser_h_ -#define liblldb_MSVCUndecoratedNameParser_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCUNDECORATEDNAMEPARSER_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCUNDECORATEDNAMEPARSER_H #include <vector> diff --git a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp index 3e77b1646739..aaf578c6f728 100644 --- a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp +++ b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp @@ -1,4 +1,4 @@ -//===-- ClangHighlighter.cpp ------------------------------------*- C++ -*-===// +//===-- ClangHighlighter.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,6 +13,7 @@ #include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/StreamString.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/StringSet.h" diff --git a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h index f459f9424697..5257c728ca5c 100644 --- a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h +++ b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangHighlighter_h_ -#define liblldb_ClangHighlighter_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CLANGCOMMON_CLANGHIGHLIGHTER_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CLANGCOMMON_CLANGHIGHLIGHTER_H #include "lldb/Utility/Stream.h" #include "llvm/ADT/StringSet.h" @@ -34,4 +34,4 @@ public: } // namespace lldb_private -#endif // liblldb_ClangHighlighter_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CLANGCOMMON_CLANGHIGHLIGHTER_H diff --git a/lldb/source/Plugins/Language/ObjC/CF.cpp b/lldb/source/Plugins/Language/ObjC/CF.cpp index 5bca260616ea..2610468b17fd 100644 --- a/lldb/source/Plugins/Language/ObjC/CF.cpp +++ b/lldb/source/Plugins/Language/ObjC/CF.cpp @@ -1,5 +1,4 @@ -//===-- CF.cpp ----------------------------------------------------*- C++ -//-*-===// +//===-- CF.cpp ------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,10 +8,10 @@ #include "CF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" @@ -30,7 +29,7 @@ using namespace lldb_private::formatters; bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { time_t epoch = GetOSXEpoch(); - epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0); + epoch = epoch + (time_t)valobj.GetValueAsSigned(0); tm *tm_date = localtime(&epoch); if (!tm_date) return false; diff --git a/lldb/source/Plugins/Language/ObjC/CF.h b/lldb/source/Plugins/Language/ObjC/CF.h index 2abb56d407eb..6165e1c235bc 100644 --- a/lldb/source/Plugins/Language/ObjC/CF.h +++ b/lldb/source/Plugins/Language/ObjC/CF.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_CF_h_ -#define liblldb_CF_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CF_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CF_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -29,4 +29,4 @@ bool CFAbsoluteTimeSummaryProvider(ValueObject &valobj, Stream &stream, } // namespace formatters } // namespace lldb_private -#endif // liblldb_CF_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CF_H diff --git a/lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp b/lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp new file mode 100644 index 000000000000..42cda0146f2e --- /dev/null +++ b/lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp @@ -0,0 +1,114 @@ +#include "CFBasicHash.h" + +#include "lldb/Utility/Endian.h" + +using namespace lldb; +using namespace lldb_private; + +bool CFBasicHash::IsValid() const { + if (m_address != LLDB_INVALID_ADDRESS) { + if (m_ptr_size == 4 && m_ht_32) + return true; + else if (m_ptr_size == 8 && m_ht_64) + return true; + else + return false; + } + return false; +} + +bool CFBasicHash::Update(addr_t addr, ExecutionContextRef exe_ctx_rf) { + if (addr == LLDB_INVALID_ADDRESS || !addr) + return false; + + m_address = addr; + m_exe_ctx_ref = exe_ctx_rf; + m_ptr_size = + m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetAddressByteSize(); + m_byte_order = m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetByteOrder(); + + if (m_ptr_size == 4) + return UpdateFor(m_ht_32); + else if (m_ptr_size == 8) + return UpdateFor(m_ht_64); + return false; + + llvm_unreachable( + "Unsupported architecture. Only 32bits and 64bits supported."); +} + +template <typename T> +bool CFBasicHash::UpdateFor(std::unique_ptr<__CFBasicHash<T>> &m_ht) { + if (m_byte_order != endian::InlHostByteOrder()) + return false; + + Status error; + Target *target = m_exe_ctx_ref.GetTargetSP().get(); + addr_t addr = m_address.GetLoadAddress(target); + size_t size = sizeof(typename __CFBasicHash<T>::RuntimeBase) + + sizeof(typename __CFBasicHash<T>::Bits); + + m_ht = std::make_unique<__CFBasicHash<T>>(); + m_exe_ctx_ref.GetProcessSP()->ReadMemory(addr, m_ht.get(), + size, error); + if (error.Fail()) + return false; + + m_mutable = !(m_ht->base.cfinfoa & (1 << 6)); + m_multi = m_ht->bits.counts_offset; + m_type = static_cast<HashType>(m_ht->bits.keys_offset); + addr_t ptr_offset = addr + size; + size_t ptr_count = GetPointerCount(); + size = ptr_count * sizeof(T); + + m_exe_ctx_ref.GetProcessSP()->ReadMemory(ptr_offset, m_ht->pointers, size, + error); + + if (error.Fail()) { + m_ht = nullptr; + return false; + } + + return true; +} + +size_t CFBasicHash::GetCount() const { + if (!IsValid()) + return 0; + + if (!m_multi) + return (m_ptr_size == 4) ? m_ht_32->bits.used_buckets + : m_ht_64->bits.used_buckets; + + // FIXME: Add support for multi + return 0; +} + +size_t CFBasicHash::GetPointerCount() const { + if (!IsValid()) + return 0; + + if (m_multi) + return 3; // Bits::counts_offset; + return (m_type == HashType::dict) + 1; +} + +addr_t CFBasicHash::GetKeyPointer() const { + if (!IsValid()) + return LLDB_INVALID_ADDRESS; + + if (m_ptr_size == 4) + return m_ht_32->pointers[m_ht_32->bits.keys_offset]; + + return m_ht_64->pointers[m_ht_64->bits.keys_offset]; +} + +addr_t CFBasicHash::GetValuePointer() const { + if (!IsValid()) + return LLDB_INVALID_ADDRESS; + + if (m_ptr_size == 4) + return m_ht_32->pointers[0]; + + return m_ht_64->pointers[0]; +} diff --git a/lldb/source/Plugins/Language/ObjC/CFBasicHash.h b/lldb/source/Plugins/Language/ObjC/CFBasicHash.h new file mode 100644 index 000000000000..fd30f5f7845f --- /dev/null +++ b/lldb/source/Plugins/Language/ObjC/CFBasicHash.h @@ -0,0 +1,76 @@ +//===-- CFBasicHash.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_LANGUAGE_OBJC_CFBASICHASH_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CFBASICHASH_H + +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +namespace lldb_private { + +class CFBasicHash { +public: + enum class HashType { set = 0, dict }; + + CFBasicHash() = default; + ~CFBasicHash() = default; + + bool Update(lldb::addr_t addr, ExecutionContextRef exe_ctx_rf); + + bool IsValid() const; + + bool IsMutable() const { return m_mutable; }; + bool IsMultiVariant() const { return m_multi; } + HashType GetType() const { return m_type; } + + size_t GetCount() const; + lldb::addr_t GetKeyPointer() const; + lldb::addr_t GetValuePointer() const; + +private: + template <typename T> struct __CFBasicHash { + struct RuntimeBase { + T cfisa; + T cfinfoa; + } base; + + struct Bits { + uint16_t __reserved0; + uint16_t __reserved1 : 2; + uint16_t keys_offset : 1; + uint16_t counts_offset : 2; + uint16_t counts_width : 2; + uint16_t __reserved2 : 9; + uint32_t used_buckets; // number of used buckets + uint64_t deleted : 16; // number of elements deleted + uint64_t num_buckets_idx : 8; // index to number of buckets + uint64_t __reserved3 : 40; + uint64_t __reserved4; + } bits; + + T pointers[3]; + }; + template <typename T> bool UpdateFor(std::unique_ptr<__CFBasicHash<T>> &m_ht); + + size_t GetPointerCount() const; + + uint32_t m_ptr_size = UINT32_MAX; + lldb::ByteOrder m_byte_order = lldb::eByteOrderInvalid; + Address m_address = LLDB_INVALID_ADDRESS; + std::unique_ptr<__CFBasicHash<uint32_t>> m_ht_32 = nullptr; + std::unique_ptr<__CFBasicHash<uint64_t>> m_ht_64 = nullptr; + ExecutionContextRef m_exe_ctx_ref; + bool m_mutable = true; + bool m_multi = false; + HashType m_type; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CFBASICHASH_H diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 8a81abbaedbe..648fc4adf24f 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1,4 +1,4 @@ -//===-- Cocoa.cpp -----------------------------------------------*- C++ -*-===// +//===-- Cocoa.cpp ---------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,6 +8,7 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Mangled.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" @@ -15,7 +16,6 @@ #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/Host/Time.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessStructReader.h" @@ -818,13 +818,14 @@ bool lldb_private::formatters::NSDateSummaryProvider( static const ConstString g___NSDate("__NSDate"); static const ConstString g___NSTaggedDate("__NSTaggedDate"); static const ConstString g_NSCalendarDate("NSCalendarDate"); + static const ConstString g_NSConstantDate("NSConstantDate"); if (class_name.IsEmpty()) return false; uint64_t info_bits = 0, value_bits = 0; if ((class_name == g_NSDate) || (class_name == g___NSDate) || - (class_name == g___NSTaggedDate)) { + (class_name == g___NSTaggedDate) || (class_name == g_NSConstantDate)) { if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits)) { date_value_bits = ((value_bits << 8) | (info_bits << 4)); memcpy(&date_value, &date_value_bits, sizeof(date_value_bits)); @@ -850,8 +851,14 @@ bool lldb_private::formatters::NSDateSummaryProvider( } else return false; - if (date_value == -63114076800) { - stream.Printf("0001-12-30 00:00:00 +0000"); + // FIXME: It seems old dates are not formatted according to NSDate's calendar + // so we hardcode distantPast's value so that it looks like LLDB is doing + // the right thing. + + // The relative time in seconds from Cocoa Epoch to [NSDate distantPast]. + const double RelSecondsFromCocoaEpochToNSDateDistantPast = -63114076800; + if (date_value == RelSecondsFromCocoaEpochToNSDateDistantPast) { + stream.Printf("0001-01-01 00:00:00 UTC"); return true; } @@ -867,7 +874,7 @@ bool lldb_private::formatters::NSDateSummaryProvider( // is generally true and POSIXly happy, but might break if a library vendor // decides to get creative time_t epoch = GetOSXEpoch(); - epoch = epoch + (time_t)date_value; + epoch = epoch + static_cast<time_t>(std::floor(date_value)); tm *tm_date = gmtime(&epoch); if (!tm_date) return false; @@ -902,8 +909,7 @@ bool lldb_private::formatters::ObjCClassSummaryProvider( if (class_name.IsEmpty()) return false; - if (ConstString cs = - Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown)) + if (ConstString cs = Mangled(class_name).GetDemangledName()) class_name = cs; stream.Printf("%s", class_name.AsCString("<unknown class>")); diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.h b/lldb/source/Plugins/Language/ObjC/Cocoa.h index 388e6f03aa0f..a195d622ce58 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.h +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_Cocoa_h_ -#define liblldb_Cocoa_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COCOA_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COCOA_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -113,4 +113,4 @@ public: } // namespace formatters } // namespace lldb_private -#endif // liblldb_Cocoa_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COCOA_H diff --git a/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp b/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp index 247429da1b06..ac2f45b8354f 100644 --- a/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp +++ b/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp @@ -1,5 +1,4 @@ -//===-- CoreMedia.cpp --------------------------------------------*- C++ -//-*-===// +//===-- CoreMedia.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Language/ObjC/CoreMedia.h b/lldb/source/Plugins/Language/ObjC/CoreMedia.h index 79abb67b9d7e..7fd8560d20e1 100644 --- a/lldb/source/Plugins/Language/ObjC/CoreMedia.h +++ b/lldb/source/Plugins/Language/ObjC/CoreMedia.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_CoreMedia_h_ -#define liblldb_CoreMedia_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COREMEDIA_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COREMEDIA_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -22,4 +22,4 @@ bool CMTimeSummaryProvider(ValueObject &valobj, Stream &stream, } // namespace formatters } // namespace lldb_private -#endif // liblldb_CF_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COREMEDIA_H diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp index 73335aff2fd7..8d648d8a0861 100644 --- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -1,4 +1,4 @@ -//===-- NSArray.cpp ---------------------------------------------*- C++ -*-===// +//===-- NSArray.cpp -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,16 +7,17 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/Basic/TargetInfo.h" #include "Cocoa.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Expression/FunctionCaller.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" @@ -97,42 +98,46 @@ private: }; namespace Foundation1010 { - struct DataDescriptor_32 { - uint32_t _used; - uint32_t _offset; - uint32_t _size : 28; - uint64_t _priv1 : 4; - uint32_t _priv2; - uint32_t _data; - }; - - struct DataDescriptor_64 { - uint64_t _used; - uint64_t _offset; - uint64_t _size : 60; - uint64_t _priv1 : 4; - uint32_t _priv2; - uint64_t _data; - }; + namespace { + struct DataDescriptor_32 { + uint32_t _used; + uint32_t _offset; + uint32_t _size : 28; + uint64_t _priv1 : 4; + uint32_t _priv2; + uint32_t _data; + }; + + struct DataDescriptor_64 { + uint64_t _used; + uint64_t _offset; + uint64_t _size : 60; + uint64_t _priv1 : 4; + uint32_t _priv2; + uint64_t _data; + }; + } using NSArrayMSyntheticFrontEnd = GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; } namespace Foundation1428 { - struct DataDescriptor_32 { - uint32_t _used; - uint32_t _offset; - uint32_t _size; - uint32_t _data; - }; - - struct DataDescriptor_64 { - uint64_t _used; - uint64_t _offset; - uint64_t _size; - uint64_t _data; - }; + namespace { + struct DataDescriptor_32 { + uint32_t _used; + uint32_t _offset; + uint32_t _size; + uint32_t _data; + }; + + struct DataDescriptor_64 { + uint64_t _used; + uint64_t _offset; + uint64_t _size; + uint64_t _data; + }; + } using NSArrayMSyntheticFrontEnd = GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; @@ -436,7 +441,7 @@ lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontE : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), m_id_type() { if (valobj_sp) { - auto *clang_ast_context = ClangASTContext::GetScratch( + auto *clang_ast_context = TypeSystemClang::GetScratch( *valobj_sp->GetExecutionContextRef().GetTargetSP()); if (clang_ast_context) m_id_type = CompilerType( @@ -528,7 +533,7 @@ lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName template <typename D32, typename D64> lldb_private::formatters:: GenericNSArrayMSyntheticFrontEnd<D32, D64>:: - ~GenericNSArrayMSyntheticFrontEnd() { + ~GenericNSArrayMSyntheticFrontEnd<D32, D64>() { delete m_data_32; m_data_32 = nullptr; delete m_data_64; @@ -584,7 +589,7 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: if (valobj_sp) { CompilerType type = valobj_sp->GetCompilerType(); if (type) { - auto *clang_ast_context = ClangASTContext::GetScratch( + auto *clang_ast_context = TypeSystemClang::GetScratch( *valobj_sp->GetExecutionContextRef().GetTargetSP()); if (clang_ast_context) m_id_type = clang_ast_context->GetType( @@ -595,7 +600,7 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: template <typename D32, typename D64, bool Inline> lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: - ~GenericNSArrayISyntheticFrontEnd() { + ~GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>() { delete m_data_32; m_data_32 = nullptr; delete m_data_64; @@ -753,7 +758,7 @@ lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex( if (idx == 0) { auto *clang_ast_context = - ClangASTContext::GetScratch(*m_backend.GetTargetSP()); + TypeSystemClang::GetScratch(*m_backend.GetTargetSP()); if (clang_ast_context) { CompilerType id_type( clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID)); diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index ae00674c49f3..3dc07678f92f 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -1,4 +1,4 @@ -//===-- NSDictionary.cpp ----------------------------------------*- C++ -*-===// +//===-- NSDictionary.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,14 +10,15 @@ #include "clang/AST/DeclCXX.h" +#include "CFBasicHash.h" #include "NSDictionary.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" @@ -65,7 +66,7 @@ NSDictionary_Additionals::GetAdditionalSynthetics() { static CompilerType GetLLDBNSPairType(TargetSP target_sp) { CompilerType compiler_type; - ClangASTContext *target_ast_context = ClangASTContext::GetScratch(*target_sp); + TypeSystemClang *target_ast_context = TypeSystemClang::GetScratch(*target_sp); if (target_ast_context) { ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair"); @@ -76,18 +77,19 @@ static CompilerType GetLLDBNSPairType(TargetSP target_sp) { if (!compiler_type) { compiler_type = target_ast_context->CreateRecordType( - nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), - clang::TTK_Struct, lldb::eLanguageTypeC); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, + g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, + lldb::eLanguageTypeC); if (compiler_type) { - ClangASTContext::StartTagDeclarationDefinition(compiler_type); + TypeSystemClang::StartTagDeclarationDefinition(compiler_type); CompilerType id_compiler_type = target_ast_context->GetBasicType(eBasicTypeObjCID); - ClangASTContext::AddFieldToRecordType( + TypeSystemClang::AddFieldToRecordType( compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0); - ClangASTContext::AddFieldToRecordType( + TypeSystemClang::AddFieldToRecordType( compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0); - ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); + TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type); } } } @@ -139,6 +141,37 @@ private: std::vector<DictionaryItemDescriptor> m_children; }; +class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + +private: + struct DictionaryItemDescriptor { + lldb::addr_t key_ptr; + lldb::addr_t val_ptr; + lldb::ValueObjectSP valobj_sp; + }; + + ExecutionContextRef m_exe_ctx_ref; + uint8_t m_ptr_size; + lldb::ByteOrder m_order; + + CFBasicHash m_hashtable; + + CompilerType m_pair_type; + std::vector<DictionaryItemDescriptor> m_children; +}; + class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); @@ -245,64 +278,67 @@ namespace Foundation1100 { } namespace Foundation1428 { - struct DataDescriptor_32 { - uint32_t _used : 26; - uint32_t _kvo : 1; - uint32_t _size; - uint32_t _buffer; - uint64_t GetSize() { return _size; } - }; - - struct DataDescriptor_64 { - uint64_t _used : 58; - uint32_t _kvo : 1; - uint64_t _size; - uint64_t _buffer; - uint64_t GetSize() { return _size; } - }; - - - + namespace { + struct DataDescriptor_32 { + uint32_t _used : 26; + uint32_t _kvo : 1; + uint32_t _size; + uint32_t _buffer; + uint64_t GetSize() { return _size; } + }; + + struct DataDescriptor_64 { + uint64_t _used : 58; + uint32_t _kvo : 1; + uint64_t _size; + uint64_t _buffer; + uint64_t GetSize() { return _size; } + }; + } + using NSDictionaryMSyntheticFrontEnd = GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; } namespace Foundation1437 { - static const uint64_t NSDictionaryCapacities[] = { - 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723, - 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607, - 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119, - 6221311, 10066421, 16287743, 26354171, 42641881, 68996069, - 111638519, 180634607, 292272623, 472907251 - }; - - static const size_t NSDictionaryNumSizeBuckets = sizeof(NSDictionaryCapacities) / sizeof(uint64_t); - - struct DataDescriptor_32 { - uint32_t _buffer; - uint32_t _muts; - uint32_t _used : 25; - uint32_t _kvo : 1; - uint32_t _szidx : 6; + namespace { + static const uint64_t NSDictionaryCapacities[] = { + 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723, + 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607, + 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119, + 6221311, 10066421, 16287743, 26354171, 42641881, 68996069, + 111638519, 180634607, 292272623, 472907251 + }; + + static const size_t NSDictionaryNumSizeBuckets = + sizeof(NSDictionaryCapacities) / sizeof(uint64_t); + + struct DataDescriptor_32 { + uint32_t _buffer; + uint32_t _muts; + uint32_t _used : 25; + uint32_t _kvo : 1; + uint32_t _szidx : 6; - uint64_t GetSize() { - return (_szidx) >= NSDictionaryNumSizeBuckets ? - 0 : NSDictionaryCapacities[_szidx]; - } - }; - - struct DataDescriptor_64 { - uint64_t _buffer; - uint32_t _muts; - uint32_t _used : 25; - uint32_t _kvo : 1; - uint32_t _szidx : 6; + uint64_t GetSize() { + return (_szidx) >= NSDictionaryNumSizeBuckets ? + 0 : NSDictionaryCapacities[_szidx]; + } + }; + + struct DataDescriptor_64 { + uint64_t _buffer; + uint32_t _muts; + uint32_t _used : 25; + uint32_t _kvo : 1; + uint32_t _szidx : 6; - uint64_t GetSize() { - return (_szidx) >= NSDictionaryNumSizeBuckets ? - 0 : NSDictionaryCapacities[_szidx]; - } - }; + uint64_t GetSize() { + return (_szidx) >= NSDictionaryNumSizeBuckets ? + 0 : NSDictionaryCapacities[_szidx]; + } + }; + } using NSDictionaryMSyntheticFrontEnd = GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; @@ -375,7 +411,9 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable"); static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); static const ConstString g_Dictionary0("__NSDictionary0"); - static const ConstString g_DictionaryCF("__NSCFDictionary"); + static const ConstString g_DictionaryCF("__CFDictionary"); + static const ConstString g_DictionaryNSCF("__NSCFDictionary"); + static const ConstString g_DictionaryCFRef("CFDictionaryRef"); if (class_name.IsEmpty()) return false; @@ -386,9 +424,9 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( ptr_size, 0, error); if (error.Fail()) return false; + value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); - } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy || - class_name == g_DictionaryCF) { + } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) { AppleObjCRuntime *apple_runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); Status error; @@ -406,8 +444,15 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( value = 1; } else if (class_name == g_Dictionary0) { value = 0; - } - else { + } else if (class_name == g_DictionaryCF || + class_name == g_DictionaryNSCF || + class_name == g_DictionaryCFRef) { + ExecutionContext exe_ctx(process_sp); + CFBasicHash cfbh; + if (!cfbh.Update(valobj_addr, exe_ctx)) + return false; + value = cfbh.GetCount(); + } else { auto &map(NSDictionary_Additionals::GetAdditionalSummaries()); for (auto &candidate : map) { if (candidate.first && candidate.first->Match(class_name)) @@ -465,6 +510,9 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable"); static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); static const ConstString g_Dictionary0("__NSDictionary0"); + static const ConstString g_DictionaryCF("__CFDictionary"); + static const ConstString g_DictionaryNSCF("__NSCFDictionary"); + static const ConstString g_DictionaryCFRef("CFDictionaryRef"); if (class_name.IsEmpty()) return nullptr; @@ -483,6 +531,10 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp)); } else if (class_name == g_Dictionary1) { return (new NSDictionary1SyntheticFrontEnd(valobj_sp)); + } else if (class_name == g_DictionaryCF || + class_name == g_DictionaryNSCF || + class_name == g_DictionaryCFRef) { + return (new NSCFDictionarySyntheticFrontEnd(valobj_sp)); } else { auto &map(NSDictionary_Additionals::GetAdditionalSynthetics()); for (auto &candidate : map) { @@ -640,6 +692,140 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex( return dict_item.valobj_sp; } +lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: + NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), + m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {} + +size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + const char *item_name = name.GetCString(); + const uint32_t idx = ExtractIndexFromString(item_name); + if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + return UINT32_MAX; + return idx; +} + +size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: + CalculateNumChildren() { + if (!m_hashtable.IsValid()) + return 0; + return m_hashtable.GetCount(); +} + +bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() { + m_children.clear(); + ValueObjectSP valobj_sp = m_backend.GetSP(); + m_ptr_size = 0; + if (!valobj_sp) + return false; + m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); + + lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); + if (!process_sp) + return false; + m_ptr_size = process_sp->GetAddressByteSize(); + m_order = process_sp->GetByteOrder(); + return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); +} + +bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +lldb::ValueObjectSP +lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex( + size_t idx) { + lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer(); + lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); + + const uint32_t num_children = CalculateNumChildren(); + + if (idx >= num_children) + return lldb::ValueObjectSP(); + + if (m_children.empty()) { + ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + + Status error; + lldb::addr_t key_at_idx = 0, val_at_idx = 0; + + uint32_t tries = 0; + uint32_t test_idx = 0; + + // Iterate over inferior memory, reading key/value pointers by shifting each + // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read + // fails, otherwise, continue until the number of tries matches the number + // of childen. + while (tries < num_children) { + key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); + val_at_idx = m_values_ptr + (test_idx * m_ptr_size); + + key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); + if (error.Fail()) + return lldb::ValueObjectSP(); + val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); + if (error.Fail()) + return lldb::ValueObjectSP(); + + test_idx++; + + if (!key_at_idx || !val_at_idx) + continue; + tries++; + + DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, + lldb::ValueObjectSP()}; + + m_children.push_back(descriptor); + } + } + + if (idx >= m_children.size()) // should never happen + return lldb::ValueObjectSP(); + + DictionaryItemDescriptor &dict_item = m_children[idx]; + if (!dict_item.valobj_sp) { + if (!m_pair_type.IsValid()) { + TargetSP target_sp(m_backend.GetTargetSP()); + if (!target_sp) + return ValueObjectSP(); + m_pair_type = GetLLDBNSPairType(target_sp); + } + if (!m_pair_type.IsValid()) + return ValueObjectSP(); + + DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); + + switch (m_ptr_size) { + case 0: // architecture has no clue - fail + return lldb::ValueObjectSP(); + case 4: { + uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()); + *data_ptr = dict_item.key_ptr; + *(data_ptr + 1) = dict_item.val_ptr; + } break; + case 8: { + uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()); + *data_ptr = dict_item.key_ptr; + *(data_ptr + 1) = dict_item.val_ptr; + } break; + default: + lldbassert(false && "pointer size is not 4 nor 8"); + } + + StreamString idx_name; + idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); + DataExtractor data(buffer_sp, m_order, m_ptr_size); + dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, + m_exe_ctx_ref, m_pair_type); + } + return dict_item.valobj_sp; +} + lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {} @@ -724,7 +910,7 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: template <typename D32, typename D64> lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: - ~GenericNSDictionaryMSyntheticFrontEnd() { + ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() { delete m_data_32; m_data_32 = nullptr; delete m_data_64; @@ -732,8 +918,8 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: } template <typename D32, typename D64> -size_t -lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: GetIndexOfChildWithName(ConstString name) { +size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< + D32, D64>::GetIndexOfChildWithName(ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); if (idx < UINT32_MAX && idx >= CalculateNumChildren()) @@ -782,7 +968,7 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: } if (error.Fail()) return false; - return false; + return true; } template <typename D32, typename D64> @@ -794,9 +980,8 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: template <typename D32, typename D64> lldb::ValueObjectSP -lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: - GetChildAtIndex( - size_t idx) { +lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< + D32, D64>::GetChildAtIndex(size_t idx) { lldb::addr_t m_keys_ptr; lldb::addr_t m_values_ptr; if (m_data_32) { @@ -884,7 +1069,6 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: return dict_item.valobj_sp; } - lldb_private::formatters::Foundation1100:: NSDictionaryMSyntheticFrontEnd:: NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.h b/lldb/source/Plugins/Language/ObjC/NSDictionary.h index 44d56f9c2c68..57dacd6759d2 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.h +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.h @@ -1,5 +1,4 @@ -//===-- NSDictionary.h ---------------------------------------------------*- C++ -//-*-===// +//===-- NSDictionary.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. @@ -7,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_NSDictionary_h_ -#define liblldb_NSDictionary_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSDICTIONARY_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSDICTIONARY_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -91,4 +90,4 @@ public: } // namespace formatters } // namespace lldb_private -#endif // liblldb_NSDictionary_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSDICTIONARY_H diff --git a/lldb/source/Plugins/Language/ObjC/NSError.cpp b/lldb/source/Plugins/Language/ObjC/NSError.cpp index 94a97c8ad039..aa1103cb342c 100644 --- a/lldb/source/Plugins/Language/ObjC/NSError.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSError.cpp @@ -1,4 +1,4 @@ -//===-- NSError.cpp ---------------------------------------------*- C++ -*-===// +//===-- NSError.cpp -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,10 +10,10 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" @@ -87,7 +87,7 @@ bool lldb_private::formatters::NSError_SummaryProvider( ValueObjectSP domain_str_sp = ValueObject::CreateValueObjectFromData( "domain_str", isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), - ClangASTContext::GetScratch(process_sp->GetTarget()) + TypeSystemClang::GetScratch(process_sp->GetTarget()) ->GetBasicType(lldb::eBasicTypeVoid) .GetPointerType()); @@ -156,7 +156,7 @@ public: m_child_sp = CreateValueObjectFromData( "_userInfo", isw.GetAsData(process_sp->GetByteOrder()), m_backend.GetExecutionContextRef(), - ClangASTContext::GetScratch(process_sp->GetTarget()) + TypeSystemClang::GetScratch(process_sp->GetTarget()) ->GetBasicType(lldb::eBasicTypeObjCID)); return false; } diff --git a/lldb/source/Plugins/Language/ObjC/NSException.cpp b/lldb/source/Plugins/Language/ObjC/NSException.cpp index 9150787361c5..c6bae5e1c008 100644 --- a/lldb/source/Plugins/Language/ObjC/NSException.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSException.cpp @@ -1,4 +1,4 @@ -//===-- NSException.cpp -----------------------------------------*- C++ -*-===// +//===-- NSException.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,7 +13,6 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" @@ -23,6 +22,7 @@ #include "Plugins/Language/ObjC/NSString.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace lldb; using namespace lldb_private; @@ -69,7 +69,7 @@ static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp, InferiorSizedWord userinfo_isw(userinfo, *process_sp); InferiorSizedWord reserved_isw(reserved, *process_sp); - auto *clang_ast_context = ClangASTContext::GetScratch(process_sp->GetTarget()); + auto *clang_ast_context = TypeSystemClang::GetScratch(process_sp->GetTarget()); if (!clang_ast_context) return false; diff --git a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp index 587dd13870a0..d962f39611b6 100644 --- a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp @@ -1,4 +1,4 @@ -//===-- NSIndexPath.cpp -----------------------------------------*- C++ -*-===// +//===-- NSIndexPath.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,11 +8,11 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/TypeSynthetic.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -53,7 +53,7 @@ public: if (!type_system) return false; - ClangASTContext *ast = ClangASTContext::GetScratch( + TypeSystemClang *ast = TypeSystemClang::GetScratch( *m_backend.GetExecutionContextRef().GetTargetSP()); if (!ast) return false; diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp index ebaa990fb74b..4dbbe6fbddff 100644 --- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -1,4 +1,4 @@ -//===-- NSSet.cpp -----------------------------------------------*- C++ -*-===// +//===-- NSSet.cpp ---------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,12 +7,13 @@ //===----------------------------------------------------------------------===// #include "NSSet.h" +#include "CFBasicHash.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" @@ -79,6 +80,36 @@ private: std::vector<SetItemDescriptor> m_children; }; +class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + +private: + struct SetItemDescriptor { + lldb::addr_t item_ptr; + lldb::ValueObjectSP valobj_sp; + }; + + ExecutionContextRef m_exe_ctx_ref; + uint8_t m_ptr_size; + lldb::ByteOrder m_order; + + CFBasicHash m_hashtable; + + CompilerType m_pair_type; + std::vector<SetItemDescriptor> m_children; +}; + template <typename D32, typename D64> class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: @@ -245,21 +276,25 @@ bool lldb_private::formatters::NSSetSummaryProvider( uint64_t value = 0; - ConstString class_name_cs = descriptor->GetClassName(); - const char *class_name = class_name_cs.GetCString(); + ConstString class_name(descriptor->GetClassName()); - if (!class_name || !*class_name) + static const ConstString g_SetI("__NSSetI"); + static const ConstString g_OrderedSetI("__NSOrderedSetI"); + static const ConstString g_SetM("__NSSetM"); + static const ConstString g_SetCF("__NSCFSet"); + static const ConstString g_SetCFRef("CFSetRef"); + + if (class_name.IsEmpty()) return false; - if (!strcmp(class_name, "__NSSetI") || - !strcmp(class_name, "__NSOrderedSetI")) { + if (class_name == g_SetI || class_name == g_OrderedSetI) { Status error; value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); if (error.Fail()) return false; value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); - } else if (!strcmp(class_name, "__NSSetM")) { + } else if (class_name == g_SetM) { AppleObjCRuntime *apple_runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); Status error; @@ -272,9 +307,15 @@ bool lldb_private::formatters::NSSetSummaryProvider( } if (error.Fail()) return false; + } else if (class_name == g_SetCF || class_name == g_SetCFRef) { + ExecutionContext exe_ctx(process_sp); + CFBasicHash cfbh; + if (!cfbh.Update(valobj_addr, exe_ctx)) + return false; + value = cfbh.GetCount(); } else { auto &map(NSSet_Additionals::GetAdditionalSummaries()); - auto iter = map.find(class_name_cs), end = map.end(); + auto iter = map.find(class_name), end = map.end(); if (iter != end) return iter->second(valobj, stream, options); else @@ -321,16 +362,20 @@ lldb_private::formatters::NSSetSyntheticFrontEndCreator( if (!descriptor || !descriptor->IsValid()) return nullptr; - ConstString class_name_cs = descriptor->GetClassName(); - const char *class_name = class_name_cs.GetCString(); + ConstString class_name = descriptor->GetClassName(); - if (!class_name || !*class_name) + static const ConstString g_SetI("__NSSetI"); + static const ConstString g_OrderedSetI("__NSOrderedSetI"); + static const ConstString g_SetM("__NSSetM"); + static const ConstString g_SetCF("__NSCFSet"); + static const ConstString g_SetCFRef("CFSetRef"); + + if (class_name.IsEmpty()) return nullptr; - if (!strcmp(class_name, "__NSSetI") || - !strcmp(class_name, "__NSOrderedSetI")) { + if (class_name == g_SetI || class_name == g_OrderedSetI) { return (new NSSetISyntheticFrontEnd(valobj_sp)); - } else if (!strcmp(class_name, "__NSSetM")) { + } else if (class_name == g_SetM) { AppleObjCRuntime *apple_runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); if (apple_runtime) { @@ -343,9 +388,11 @@ lldb_private::formatters::NSSetSyntheticFrontEndCreator( } else { return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp)); } + } else if (class_name == g_SetCF || class_name == g_SetCFRef) { + return (new NSCFSetSyntheticFrontEnd(valobj_sp)); } else { auto &map(NSSet_Additionals::GetAdditionalSynthetics()); - auto iter = map.find(class_name_cs), end = map.end(); + auto iter = map.find(class_name), end = map.end(); if (iter != end) return iter->second(synth, valobj_sp); return nullptr; @@ -475,16 +522,18 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) { auto ptr_size = process_sp->GetAddressByteSize(); DataBufferHeap buffer(ptr_size, 0); switch (ptr_size) { - case 0: // architecture has no clue?? - fail + case 0: // architecture has no clue - fail return lldb::ValueObjectSP(); case 4: - *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; + *reinterpret_cast<uint32_t *>(buffer.GetBytes()) = + static_cast<uint32_t>(set_item.item_ptr); break; case 8: - *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; + *reinterpret_cast<uint64_t *>(buffer.GetBytes()) = + static_cast<uint64_t>(set_item.item_ptr); break; default: - assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); + lldbassert(false && "pointer size is not 4 nor 8"); } StreamString idx_name; idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); @@ -501,6 +550,128 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) { return set_item.valobj_sp; } +lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd( + lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), + m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {} + +size_t +lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName( + ConstString name) { + const char *item_name = name.GetCString(); + const uint32_t idx = ExtractIndexFromString(item_name); + if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + return UINT32_MAX; + return idx; +} + +size_t +lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() { + if (!m_hashtable.IsValid()) + return 0; + return m_hashtable.GetCount(); +} + +bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() { + m_children.clear(); + ValueObjectSP valobj_sp = m_backend.GetSP(); + m_ptr_size = 0; + if (!valobj_sp) + return false; + m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); + + lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); + if (!process_sp) + return false; + m_ptr_size = process_sp->GetAddressByteSize(); + m_order = process_sp->GetByteOrder(); + return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); +} + +bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() { + return true; +} + +lldb::ValueObjectSP +lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex( + size_t idx) { + lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); + + const uint32_t num_children = CalculateNumChildren(); + + if (idx >= num_children) + return lldb::ValueObjectSP(); + + if (m_children.empty()) { + ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + + Status error; + lldb::addr_t val_at_idx = 0; + + uint32_t tries = 0; + uint32_t test_idx = 0; + + // Iterate over inferior memory, reading value pointers by shifting the + // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read + // fails, otherwise, continue until the number of tries matches the number + // of childen. + while (tries < num_children) { + val_at_idx = m_values_ptr + (test_idx * m_ptr_size); + + val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); + if (error.Fail()) + return lldb::ValueObjectSP(); + + test_idx++; + + if (!val_at_idx) + continue; + tries++; + + SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()}; + + m_children.push_back(descriptor); + } + } + + if (idx >= m_children.size()) // should never happen + return lldb::ValueObjectSP(); + + SetItemDescriptor &set_item = m_children[idx]; + if (!set_item.valobj_sp) { + + DataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0)); + + switch (m_ptr_size) { + case 0: // architecture has no clue - fail + return lldb::ValueObjectSP(); + case 4: + *reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) = + static_cast<uint32_t>(set_item.item_ptr); + break; + case 8: + *reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) = + static_cast<uint64_t>(set_item.item_ptr); + break; + default: + lldbassert(false && "pointer size is not 4 nor 8"); + } + StreamString idx_name; + idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); + + DataExtractor data(buffer_sp, m_order, m_ptr_size); + + set_item.valobj_sp = CreateValueObjectFromData( + idx_name.GetString(), data, m_exe_ctx_ref, + m_backend.GetCompilerType().GetBasicTypeFromAST( + lldb::eBasicTypeObjCID)); + } + + return set_item.valobj_sp; +} + template <typename D32, typename D64> lldb_private::formatters:: GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd( @@ -513,7 +684,7 @@ lldb_private::formatters:: template <typename D32, typename D64> lldb_private::formatters:: - GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd() { + GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd<D32, D64>() { delete m_data_32; m_data_32 = nullptr; delete m_data_64; diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.h b/lldb/source/Plugins/Language/ObjC/NSSet.h index f11b6d406dec..3ad1f694befe 100644 --- a/lldb/source/Plugins/Language/ObjC/NSSet.h +++ b/lldb/source/Plugins/Language/ObjC/NSSet.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_NSSet_h_ -#define liblldb_NSSet_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSET_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSET_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -36,4 +36,4 @@ public: } // namespace formatters } // namespace lldb_private -#endif // liblldb_NSSet_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSET_H diff --git a/lldb/source/Plugins/Language/ObjC/NSString.cpp b/lldb/source/Plugins/Language/ObjC/NSString.cpp index ce54d657374b..b9d0d73cbc2e 100644 --- a/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -1,5 +1,4 @@ -//===-- NSString.cpp ----------------------------------------------*- C++ -//-*-===// +//===-- NSString.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,11 +8,11 @@ #include "NSString.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" @@ -35,7 +34,7 @@ NSString_Additionals::GetAdditionalSummaries() { static CompilerType GetNSPathStore2Type(Target &target) { static ConstString g_type_name("__lldb_autogen_nspathstore2"); - ClangASTContext *ast_ctx = ClangASTContext::GetScratch(target); + TypeSystemClang *ast_ctx = TypeSystemClang::GetScratch(target); if (!ast_ctx) return CompilerType(); @@ -171,11 +170,11 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(false); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetBinaryZeroIsTerminator(false); - options.SetLanguage(summary_options.GetLanguage()); return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF16>(options); } else { @@ -183,11 +182,11 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(false); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetBinaryZeroIsTerminator(false); - options.SetLanguage(summary_options.GetLanguage()); return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::ASCII>(options); } @@ -200,9 +199,9 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); - options.SetLanguage(summary_options.GetLanguage()); return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::ASCII>(options); } else if (is_unicode) { @@ -222,11 +221,11 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetBinaryZeroIsTerminator(!has_explicit_length); - options.SetLanguage(summary_options.GetLanguage()); return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF16>(options); } else if (is_path_store) { @@ -242,11 +241,11 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetBinaryZeroIsTerminator(!has_explicit_length); - options.SetLanguage(summary_options.GetLanguage()); return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF16>(options); } else if (is_inline) { @@ -264,11 +263,11 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetBinaryZeroIsTerminator(!has_explicit_length); - options.SetLanguage(summary_options.GetLanguage()); if (has_explicit_length) return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF8>(options); @@ -287,9 +286,9 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); - options.SetLanguage(summary_options.GetLanguage()); return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::ASCII>(options); } diff --git a/lldb/source/Plugins/Language/ObjC/NSString.h b/lldb/source/Plugins/Language/ObjC/NSString.h index 699d8eb36f88..a68cc6c056b0 100644 --- a/lldb/source/Plugins/Language/ObjC/NSString.h +++ b/lldb/source/Plugins/Language/ObjC/NSString.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_NSString_h_ -#define liblldb_NSString_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSTRING_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSTRING_H #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" @@ -39,4 +39,4 @@ public: } // namespace formatters } // namespace lldb_private -#endif // liblldb_CF_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSTRING_H diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp index 3be548ad4144..29391daaab93 100644 --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -1,4 +1,4 @@ -//===-- ObjCLanguage.cpp ----------------------------------------*- C++ -*-===// +//===-- ObjCLanguage.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,12 +10,12 @@ #include "ObjCLanguage.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" @@ -37,6 +37,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +LLDB_PLUGIN_DEFINE(ObjCLanguage) + void ObjCLanguage::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), "Objective-C Language", CreateInstance); @@ -446,6 +448,10 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider<true>, + "NSDictionary summary provider", ConstString("__CFDictionary"), + appkit_flags); + AddCXXSummary(objc_category_sp, + lldb_private::formatters::NSDictionarySummaryProvider<true>, "NSDictionary summary provider", ConstString("CFMutableDictionaryRef"), appkit_flags); @@ -466,6 +472,9 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { "__NSCFSet summary", ConstString("__NSCFSet"), appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, + "__CFSet summary", ConstString("__CFSet"), appkit_flags); + AddCXXSummary(objc_category_sp, + lldb_private::formatters::NSSetSummaryProvider<false>, "__NSSetI summary", ConstString("__NSSetI"), appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, @@ -582,6 +591,11 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("CFMutableDictionaryRef"), ScriptedSyntheticChildren::Flags()); + AddCXXSynthetic( + objc_category_sp, + lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, + "NSDictionary synthetic children", ConstString("__CFDictionary"), + ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSErrorSyntheticFrontEndCreator, @@ -604,6 +618,15 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSSetM synthetic children", ConstString("__NSSetM"), ScriptedSyntheticChildren::Flags()); + AddCXXSynthetic(objc_category_sp, + lldb_private::formatters::NSSetSyntheticFrontEndCreator, + "__NSCFSet synthetic children", ConstString("__NSCFSet"), + ScriptedSyntheticChildren::Flags()); + AddCXXSynthetic(objc_category_sp, + lldb_private::formatters::NSSetSyntheticFrontEndCreator, + "CFSetRef synthetic children", ConstString("CFSetRef"), + ScriptedSyntheticChildren::Flags()); + AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "NSMutableSet synthetic children", ConstString("NSMutableSet"), @@ -620,6 +643,10 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSOrderedSetM synthetic children", ConstString("__NSOrderedSetM"), ScriptedSyntheticChildren::Flags()); + AddCXXSynthetic(objc_category_sp, + lldb_private::formatters::NSSetSyntheticFrontEndCreator, + "__CFSet synthetic children", ConstString("__CFSet"), + ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSIndexPathSyntheticFrontEndCreator, diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h index 3e2cc0972993..bed62a5c447a 100644 --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ObjCLanguage_h_ -#define liblldb_ObjCLanguage_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H #include <cstring> #include <vector> @@ -160,4 +160,4 @@ public: } // namespace lldb_private -#endif // liblldb_ObjCLanguage_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H diff --git a/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp index 81b3c5807c41..0a4017eda434 100644 --- a/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp @@ -1,5 +1,4 @@ -//===-- ObjCPlusPlusLanguage.cpp --------------------------------------*- C++ -//-*-===// +//===-- ObjCPlusPlusLanguage.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -15,6 +14,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ObjCPlusPlusLanguage) + bool ObjCPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const { const auto suffixes = {".h", ".mm"}; for (auto suffix : suffixes) { diff --git a/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h b/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h index 6224a3f47b3b..4b3d23653347 100644 --- a/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h +++ b/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ObjCPlusPlusLanguage_h_ -#define liblldb_ObjCPlusPlusLanguage_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJCPLUSPLUS_OBJCPLUSPLUSLANGUAGE_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJCPLUSPLUS_OBJCPLUSPLUSLANGUAGE_H #include "Plugins/Language/ClangCommon/ClangHighlighter.h" #include "lldb/Target/Language.h" @@ -48,4 +48,4 @@ public: } // namespace lldb_private -#endif // liblldb_CPlusPlusLanguage_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJCPLUSPLUS_OBJCPLUSPLUSLANGUAGE_H diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index d556aae1c458..8aa803a8553e 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -1,4 +1,4 @@ -//===-- CPPLanguageRuntime.cpp +//===-- CPPLanguageRuntime.cpp---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -20,7 +20,6 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/UniqueCStringMap.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" @@ -44,7 +43,7 @@ CPPLanguageRuntime::~CPPLanguageRuntime() {} CPPLanguageRuntime::CPPLanguageRuntime(Process *process) : LanguageRuntime(process) {} -bool CPPLanguageRuntime::IsWhitelistedRuntimeValue(ConstString name) { +bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { return name == g_this; } diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h index abdd79fcd7b9..5b00590e6301 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_CPPLanguageRuntime_h_ -#define liblldb_CPPLanguageRuntime_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_CPPLANGUAGERUNTIME_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_CPPLANGUAGERUNTIME_H #include <vector> @@ -69,7 +69,7 @@ public: /// Obtain a ThreadPlan to get us into C++ constructs such as std::function. /// /// \param[in] thread - /// Curent thrad of execution. + /// Current thrad of execution. /// /// \param[in] stop_others /// True if other threads should pause during execution. @@ -79,7 +79,7 @@ public: lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, bool stop_others) override; - bool IsWhitelistedRuntimeValue(ConstString name) override; + bool IsAllowedRuntimeValue(ConstString name) override; protected: // Classes that inherit from CPPLanguageRuntime can see and modify these CPPLanguageRuntime(Process *process); @@ -90,9 +90,10 @@ private: OperatorStringToCallableInfoMap CallableLookupCache; - DISALLOW_COPY_AND_ASSIGN(CPPLanguageRuntime); + CPPLanguageRuntime(const CPPLanguageRuntime &) = delete; + const CPPLanguageRuntime &operator=(const CPPLanguageRuntime &) = delete; }; } // namespace lldb_private -#endif // liblldb_CPPLanguageRuntime_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_CPPLANGUAGERUNTIME_H diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 9efb021caa83..3ab32641d9c1 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -1,5 +1,4 @@ -//===-- ItaniumABILanguageRuntime.cpp --------------------------------------*- -//C++ -*-===// +//===-- ItaniumABILanguageRuntime.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,6 +8,7 @@ #include "ItaniumABILanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Mangled.h" #include "lldb/Core/Module.h" @@ -21,7 +21,6 @@ #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeList.h" @@ -41,6 +40,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(ItaniumABILanguageRuntime, CXXItaniumABI) + static const char *vtable_demangled_prefix = "vtable for "; char ItaniumABILanguageRuntime::ID = 0; @@ -73,9 +74,7 @@ TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( Symbol *symbol = sc.symbol; if (symbol != nullptr) { const char *name = - symbol->GetMangled() - .GetDemangledName(lldb::eLanguageTypeC_plus_plus) - .AsCString(); + symbol->GetMangled().GetDemangledName().AsCString(); if (name && strstr(name, vtable_demangled_prefix) == name) { Log *log( lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); @@ -118,7 +117,7 @@ TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( if (class_types.GetSize() == 1) { type_sp = class_types.GetTypeAtIndex(0); if (type_sp) { - if (ClangASTContext::IsCXXClassType( + if (TypeSystemClang::IsCXXClassType( type_sp->GetForwardCompilerType())) { LLDB_LOGF( log, @@ -150,7 +149,7 @@ TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( for (i = 0; i < class_types.GetSize(); i++) { type_sp = class_types.GetTypeAtIndex(i); if (type_sp) { - if (ClangASTContext::IsCXXClassType( + if (TypeSystemClang::IsCXXClassType( type_sp->GetForwardCompilerType())) { LLDB_LOGF( log, @@ -238,7 +237,7 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( if (!type) return true; - if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), type)) { + if (TypeSystemClang::AreTypesSame(in_value.GetCompilerType(), type)) { // The dynamic type we found was the same type, so we don't have a // dynamic type here... return false; @@ -358,8 +357,7 @@ protected: Mangled mangled(name); if (mangled.GuessLanguage() == lldb::eLanguageTypeC_plus_plus) { - ConstString demangled( - mangled.GetDisplayDemangledName(lldb::eLanguageTypeC_plus_plus)); + ConstString demangled(mangled.GetDisplayDemangledName()); demangled_any = true; result.AppendMessageWithFormat("%s ---> %s\n", entry.c_str(), demangled.GetCString()); @@ -420,12 +418,13 @@ lldb_private::ConstString ItaniumABILanguageRuntime::GetPluginName() { uint32_t ItaniumABILanguageRuntime::GetPluginVersion() { return 1; } BreakpointResolverSP ItaniumABILanguageRuntime::CreateExceptionResolver( - Breakpoint *bkpt, bool catch_bp, bool throw_bp) { + const BreakpointSP &bkpt, bool catch_bp, bool throw_bp) { return CreateExceptionResolver(bkpt, catch_bp, throw_bp, false); } BreakpointResolverSP ItaniumABILanguageRuntime::CreateExceptionResolver( - Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions) { + const BreakpointSP &bkpt, bool catch_bp, bool throw_bp, + bool for_expressions) { // One complication here is that most users DON'T want to stop at // __cxa_allocate_expression, but until we can do anything better with // predicting unwinding the expression parser does. So we have two forms of @@ -536,8 +535,8 @@ ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( if (!thread_sp->SafeToCallFunctions()) return {}; - ClangASTContext *clang_ast_context = - ClangASTContext::GetScratch(m_process->GetTarget()); + TypeSystemClang *clang_ast_context = + TypeSystemClang::GetScratch(m_process->GetTarget()); if (!clang_ast_context) return {}; diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h index 97cc81b8681f..d591527d9257 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ItaniumABILanguageRuntime_h_ -#define liblldb_ItaniumABILanguageRuntime_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_ITANIUMABI_ITANIUMABILANGUAGERUNTIME_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_ITANIUMABI_ITANIUMABILANGUAGERUNTIME_H #include <map> #include <mutex> @@ -66,9 +66,9 @@ public: bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; - lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, - bool catch_bp, - bool throw_bp) override; + lldb::BreakpointResolverSP + CreateExceptionResolver(const lldb::BreakpointSP &bkpt, + bool catch_bp, bool throw_bp) override; lldb::SearchFilterSP CreateExceptionSearchFilter() override; @@ -81,10 +81,9 @@ public: uint32_t GetPluginVersion() override; protected: - lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, - bool catch_bp, - bool throw_bp, - bool for_expressions); + lldb::BreakpointResolverSP + CreateExceptionResolver(const lldb::BreakpointSP &bkpt, + bool catch_bp, bool throw_bp, bool for_expressions); lldb::BreakpointSP CreateExceptionBreakpoint(bool catch_bp, bool throw_bp, bool for_expressions, @@ -114,4 +113,4 @@ private: } // namespace lldb_private -#endif // liblldb_ItaniumABILanguageRuntime_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_ITANIUMABI_ITANIUMABILANGUAGERUNTIME_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp index 859b693477a9..bdd5c29db848 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -1,5 +1,4 @@ -//===-- AppleObjCClassDescriptorV2.cpp -----------------------------*- C++ -//-*-===// +//===-- AppleObjCClassDescriptorV2.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -17,7 +16,7 @@ using namespace lldb_private; bool ClassDescriptorV2::Read_objc_class( Process *process, std::unique_ptr<objc_class_t> &objc_class) const { - objc_class.reset(new objc_class_t); + objc_class = std::make_unique<objc_class_t>(); bool ret = objc_class->Read(process, m_objc_class_ptr); @@ -198,14 +197,14 @@ bool ClassDescriptorV2::Read_class_row( return false; if (class_row_t_flags & RW_REALIZED) { - class_rw.reset(new class_rw_t); + class_rw = std::make_unique<class_rw_t>(); if (!class_rw->Read(process, objc_class.m_data_ptr)) { class_rw.reset(); return false; } - class_ro.reset(new class_ro_t); + class_ro = std::make_unique<class_ro_t>(); if (!class_ro->Read(process, class_rw->m_ro_ptr)) { class_rw.reset(); @@ -213,7 +212,7 @@ bool ClassDescriptorV2::Read_class_row( return false; } } else { - class_ro.reset(new class_ro_t); + class_ro = std::make_unique<class_ro_t>(); if (!class_ro->Read(process, objc_class.m_data_ptr)) { class_ro.reset(); @@ -242,15 +241,20 @@ bool ClassDescriptorV2::method_list_t::Read(Process *process, lldb::offset_t cursor = 0; - m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3; + uint32_t entsize = extractor.GetU32_unchecked(&cursor); + m_is_small = (entsize & 0x80000000) != 0; + m_has_direct_selector = (entsize & 0x40000000) != 0; + m_entsize = entsize & 0xfffc; m_count = extractor.GetU32_unchecked(&cursor); m_first_ptr = addr + cursor; return true; } -bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) { - size_t size = GetSize(process); +bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr, + bool is_small, bool has_direct_sel) { + size_t ptr_size = process->GetAddressByteSize(); + size_t size = GetSize(process, is_small); DataBufferHeap buffer(size, '\0'); Status error; @@ -261,13 +265,30 @@ bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) { } DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), - process->GetAddressByteSize()); - + ptr_size); lldb::offset_t cursor = 0; - m_name_ptr = extractor.GetAddress_unchecked(&cursor); - m_types_ptr = extractor.GetAddress_unchecked(&cursor); - m_imp_ptr = extractor.GetAddress_unchecked(&cursor); + if (is_small) { + uint32_t nameref_offset = extractor.GetU32_unchecked(&cursor); + uint32_t types_offset = extractor.GetU32_unchecked(&cursor); + uint32_t imp_offset = extractor.GetU32_unchecked(&cursor); + + m_name_ptr = addr + nameref_offset; + + if (!has_direct_sel) { + // The SEL offset points to a SELRef. We need to dereference twice. + m_name_ptr = process->ReadUnsignedIntegerFromMemory(m_name_ptr, ptr_size, + 0, error); + if (!error.Success()) + return false; + } + m_types_ptr = addr + 4 + types_offset; + m_imp_ptr = addr + 8 + imp_offset; + } else { + m_name_ptr = extractor.GetAddress_unchecked(&cursor); + m_types_ptr = extractor.GetAddress_unchecked(&cursor); + m_imp_ptr = extractor.GetAddress_unchecked(&cursor); + } process->ReadCStringFromMemory(m_name_ptr, m_name, error); if (error.Fail()) { @@ -358,19 +379,24 @@ bool ClassDescriptorV2::Describe( if (instance_method_func) { std::unique_ptr<method_list_t> base_method_list; - base_method_list.reset(new method_list_t); + base_method_list = std::make_unique<method_list_t>(); if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr)) return false; - if (base_method_list->m_entsize != method_t::GetSize(process)) + bool is_small = base_method_list->m_is_small; + bool has_direct_selector = base_method_list->m_has_direct_selector; + + if (base_method_list->m_entsize != method_t::GetSize(process, is_small)) return false; std::unique_ptr<method_t> method; - method.reset(new method_t); + method = std::make_unique<method_t>(); for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) { - method->Read(process, base_method_list->m_first_ptr + - (i * base_method_list->m_entsize)); + method->Read(process, + base_method_list->m_first_ptr + + (i * base_method_list->m_entsize), + is_small, has_direct_selector); if (instance_method_func(method->m_name.c_str(), method->m_types.c_str())) break; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h index b8ba9dbb65f4..9ef21c6e7208 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_AppleObjCClassDescriptorV2_h_ -#define liblldb_AppleObjCClassDescriptorV2_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H #include <mutex> @@ -133,7 +133,9 @@ private: }; struct method_list_t { - uint32_t m_entsize; + uint16_t m_entsize; + bool m_is_small; + bool m_has_direct_selector; uint32_t m_count; lldb::addr_t m_first_ptr; @@ -148,15 +150,19 @@ private: std::string m_name; std::string m_types; - static size_t GetSize(Process *process) { - size_t ptr_size = process->GetAddressByteSize(); + static size_t GetSize(Process *process, bool is_small) { + size_t field_size; + if (is_small) + field_size = 4; // uint32_t relative indirect fields + else + field_size = process->GetAddressByteSize(); - return ptr_size // SEL name; - + ptr_size // const char *types; - + ptr_size; // IMP imp; + return field_size // SEL name; + + field_size // const char *types; + + field_size; // IMP imp; } - bool Read(Process *process, lldb::addr_t addr); + bool Read(Process *process, lldb::addr_t addr, bool, bool); }; struct ivar_list_t { @@ -328,4 +334,4 @@ private: } // namespace lldb_private -#endif // liblldb_AppleObjCClassDescriptorV2_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index 73843063606c..7b331307c0f7 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -1,4 +1,4 @@ -//===-- AppleObjCDeclVendor.cpp ---------------------------------*- C++ -*-===// +//===-- AppleObjCDeclVendor.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,10 +8,10 @@ #include "AppleObjCDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Log.h" @@ -30,17 +30,14 @@ public: bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx, clang::DeclarationName name) override { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; Log *log(GetLogIfAllCategoriesSet( LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? if (log) { LLDB_LOGF(log, - "AppleObjCExternalASTSource::FindExternalVisibleDeclsByName[%" - "u] on (ASTContext*)%p Looking for %s in (%sDecl*)%p", - current_id, + "AppleObjCExternalASTSource::FindExternalVisibleDeclsByName" + " on (ASTContext*)%p Looking for %s in (%sDecl*)%p", static_cast<void *>(&decl_ctx->getParentASTContext()), name.getAsString().c_str(), decl_ctx->getDeclKindName(), static_cast<const void *>(decl_ctx)); @@ -70,44 +67,37 @@ public: } void CompleteType(clang::TagDecl *tag_decl) override { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; Log *log(GetLogIfAllCategoriesSet( LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? LLDB_LOGF(log, - "AppleObjCExternalASTSource::CompleteType[%u] on " + "AppleObjCExternalASTSource::CompleteType on " "(ASTContext*)%p Completing (TagDecl*)%p named %s", - current_id, static_cast<void *>(&tag_decl->getASTContext()), + static_cast<void *>(&tag_decl->getASTContext()), static_cast<void *>(tag_decl), tag_decl->getName().str().c_str()); - LLDB_LOG(log, " AOEAS::CT[{0}] Before:\n{1}", current_id, - ClangUtil::DumpDecl(tag_decl)); + LLDB_LOG(log, " AOEAS::CT Before:\n{1}", ClangUtil::DumpDecl(tag_decl)); - LLDB_LOG(log, " AOEAS::CT[{1}] After:{1}", current_id, - ClangUtil::DumpDecl(tag_decl)); + LLDB_LOG(log, " AOEAS::CT After:{1}", ClangUtil::DumpDecl(tag_decl)); return; } void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; Log *log(GetLogIfAllCategoriesSet( LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? if (log) { LLDB_LOGF(log, - "AppleObjCExternalASTSource::CompleteType[%u] on " + "AppleObjCExternalASTSource::CompleteType on " "(ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s", - current_id, static_cast<void *>(&interface_decl->getASTContext()), static_cast<void *>(interface_decl), interface_decl->getName().str().c_str()); - LLDB_LOGF(log, " AOEAS::CT[%u] Before:", current_id); + LLDB_LOGF(log, " AOEAS::CT Before:"); LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl)); } @@ -143,10 +133,9 @@ private: AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime) : ClangDeclVendor(eAppleObjCDeclVendor), m_runtime(runtime), - m_ast_ctx(runtime.GetProcess() - ->GetTarget() - .GetArchitecture() - .GetTriple()), + m_ast_ctx( + "AppleObjCDeclVendor AST", + runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple()), m_type_realizer_sp(m_runtime.GetEncodingToType()) { m_external_source = new AppleObjCExternalASTSource(*this); llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr( @@ -309,7 +298,7 @@ public: } clang::ObjCMethodDecl * - BuildMethod(ClangASTContext &clang_ast_ctxt, + BuildMethod(TypeSystemClang &clang_ast_ctxt, clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance, ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) { @@ -538,15 +527,13 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector<CompilerDecl> &decls) { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; Log *log(GetLogIfAllCategoriesSet( LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? - LLDB_LOGF(log, "AppleObjCDeclVendor::FindDecls [%u] ('%s', %s, %u, )", - current_id, (const char *)name.AsCString(), - append ? "true" : "false", max_matches); + LLDB_LOGF(log, "AppleObjCDeclVendor::FindDecls ('%s', %s, %u, )", + (const char *)name.AsCString(), append ? "true" : "false", + max_matches); if (!append) decls.clear(); @@ -579,24 +566,21 @@ uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append, isa_value = metadata->GetISAPtr(); LLDB_LOG(log, - "AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 - ") in the ASTContext", - current_id, result_iface_type.getAsString(), isa_value); + "AOCTV::FT Found %s (isa 0x%" PRIx64 ") in the ASTContext", + result_iface_type.getAsString(), isa_value); } - decls.push_back(CompilerDecl(&m_ast_ctx, result_iface_decl)); + decls.push_back(m_ast_ctx.GetCompilerDecl(result_iface_decl)); ret++; break; } else { - LLDB_LOGF(log, - "AOCTV::FT [%u] There's something in the ASTContext, but " - "it's not something we know about", - current_id); + LLDB_LOGF(log, "AOCTV::FT There's something in the ASTContext, but " + "it's not something we know about"); break; } } else if (log) { - LLDB_LOGF(log, "AOCTV::FT [%u] Couldn't find %s in the ASTContext", - current_id, name.AsCString()); + LLDB_LOGF(log, "AOCTV::FT Couldn't find %s in the ASTContext", + name.AsCString()); } // It's not. If it exists, we have to put it into our ASTContext. @@ -604,7 +588,7 @@ uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append, ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name); if (!isa) { - LLDB_LOGF(log, "AOCTV::FT [%u] Couldn't find the isa", current_id); + LLDB_LOGF(log, "AOCTV::FT Couldn't find the isa"); break; } @@ -613,9 +597,9 @@ uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append, if (!iface_decl) { LLDB_LOGF(log, - "AOCTV::FT [%u] Couldn't get the Objective-C interface for " + "AOCTV::FT Couldn't get the Objective-C interface for " "isa 0x%" PRIx64, - current_id, (uint64_t)isa); + (uint64_t)isa); break; } @@ -623,11 +607,11 @@ uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append, if (log) { clang::QualType new_iface_type = ast_ctx.getObjCInterfaceType(iface_decl); - LLDB_LOG(log, "AOCTV::FT [{0}] Created {1} (isa 0x{2:x})", current_id, + LLDB_LOG(log, "AOCTV::FT Created {1} (isa 0x{2:x})", new_iface_type.getAsString(), (uint64_t)isa); } - decls.push_back(CompilerDecl(&m_ast_ctx, iface_decl)); + decls.push_back(m_ast_ctx.GetCompilerDecl(iface_decl)); ret++; break; } while (false); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h index f49ca3540c2c..c1201b985814 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_AppleObjCDeclVendor_h_ -#define liblldb_AppleObjCDeclVendor_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCDECLVENDOR_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCDECLVENDOR_H -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/lldb-private.h" #include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" namespace lldb_private { @@ -37,7 +37,7 @@ private: bool FinishDecl(clang::ObjCInterfaceDecl *decl); ObjCLanguageRuntime &m_runtime; - ClangASTContext m_ast_ctx; + TypeSystemClang m_ast_ctx; ObjCLanguageRuntime::EncodingToTypeSP m_type_realizer_sp; AppleObjCExternalASTSource *m_external_source; @@ -50,4 +50,4 @@ private: } // namespace lldb_private -#endif // liblldb_AppleObjCDeclVendor_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCDECLVENDOR_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 7076959bee97..22ea83a57beb 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -1,5 +1,4 @@ -//===-- AppleObjCRuntime.cpp -------------------------------------*- C++ -//-*-===// +//===-- AppleObjCRuntime.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,10 +7,12 @@ //===----------------------------------------------------------------------===// #include "AppleObjCRuntime.h" +#include "AppleObjCRuntimeV1.h" +#include "AppleObjCRuntimeV2.h" #include "AppleObjCTrampolineHandler.h" - -#include "clang/AST/Type.h" - +#include "Plugins/Language/ObjC/NSString.h" +#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/Process/Utility/HistoryThread.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -22,7 +23,6 @@ #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" @@ -35,16 +35,17 @@ #include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" +#include "clang/AST/Type.h" -#include "Plugins/Process/Utility/HistoryThread.h" -#include "Plugins/Language/ObjC/NSString.h" -#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include <vector> using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(AppleObjCRuntime) + char AppleObjCRuntime::ID = 0; AppleObjCRuntime::~AppleObjCRuntime() {} @@ -55,6 +56,16 @@ AppleObjCRuntime::AppleObjCRuntime(Process *process) ReadObjCLibraryIfNeeded(process->GetTarget().GetImages()); } +void AppleObjCRuntime::Initialize() { + AppleObjCRuntimeV2::Initialize(); + AppleObjCRuntimeV1::Initialize(); +} + +void AppleObjCRuntime::Terminate() { + AppleObjCRuntimeV2::Terminate(); + AppleObjCRuntimeV1::Terminate(); +} + bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) { CompilerType compiler_type(valobj.GetCompilerType()); bool is_signed; @@ -105,13 +116,13 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, Target *target = exe_ctx.GetTargetPtr(); CompilerType compiler_type = value.GetCompilerType(); if (compiler_type) { - if (!ClangASTContext::IsObjCObjectPointerType(compiler_type)) { + if (!TypeSystemClang::IsObjCObjectPointerType(compiler_type)) { strm.Printf("Value doesn't point to an ObjC object.\n"); return false; } } else { // If it is not a pointer, see if we can make it into a pointer. - ClangASTContext *ast_context = ClangASTContext::GetScratch(*target); + TypeSystemClang *ast_context = TypeSystemClang::GetScratch(*target); if (!ast_context) return false; @@ -126,7 +137,7 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, arg_value_list.PushValue(value); // This is the return value: - ClangASTContext *ast_context = ClangASTContext::GetScratch(*target); + TypeSystemClang *ast_context = TypeSystemClang::GetScratch(*target); if (!ast_context) return false; @@ -239,7 +250,8 @@ Address *AppleObjCRuntime::GetPrintForDebuggerAddr() { contexts.GetContextAtIndex(0, context); - m_PrintForDebugger_addr.reset(new Address(context.symbol->GetAddress())); + m_PrintForDebugger_addr = + std::make_unique<Address>(context.symbol->GetAddress()); } return m_PrintForDebugger_addr.get(); @@ -335,8 +347,8 @@ bool AppleObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) { // Maybe check here and if we have a handler already, and the UUID of this // module is the same as the one in the current module, then we don't have to // reread it? - m_objc_trampoline_handler_up.reset( - new AppleObjCTrampolineHandler(m_process->shared_from_this(), module_sp)); + m_objc_trampoline_handler_up = std::make_unique<AppleObjCTrampolineHandler>( + m_process->shared_from_this(), module_sp); if (m_objc_trampoline_handler_up != nullptr) { m_read_objc_library = true; return true; @@ -479,7 +491,7 @@ ValueObjectSP AppleObjCRuntime::GetExceptionObjectForThread( auto descriptor = GetClassDescriptor(*cpp_exception); if (!descriptor || !descriptor->IsValid()) return ValueObjectSP(); - + while (descriptor) { ConstString class_name(descriptor->GetClassName()); if (class_name == "NSException") @@ -490,19 +502,32 @@ ValueObjectSP AppleObjCRuntime::GetExceptionObjectForThread( return ValueObjectSP(); } +/// Utility method for error handling in GetBacktraceThreadFromException. +/// \param msg The message to add to the log. +/// \return An invalid ThreadSP to be returned from +/// GetBacktraceThreadFromException. +LLVM_NODISCARD +static ThreadSP FailExceptionParsing(llvm::StringRef msg) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + LLDB_LOG(log, "Failed getting backtrace from exception: {0}", msg); + return ThreadSP(); +} + ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( lldb::ValueObjectSP exception_sp) { ValueObjectSP reserved_dict = exception_sp->GetChildMemberWithName(ConstString("reserved"), true); - if (!reserved_dict) return ThreadSP(); + if (!reserved_dict) + return FailExceptionParsing("Failed to get 'reserved' member."); reserved_dict = reserved_dict->GetSyntheticValue(); - if (!reserved_dict) return ThreadSP(); + if (!reserved_dict) + return FailExceptionParsing("Failed to get synthetic value."); - ClangASTContext *clang_ast_context = - ClangASTContext::GetScratch(*exception_sp->GetTargetSP()); + TypeSystemClang *clang_ast_context = + TypeSystemClang::GetScratch(*exception_sp->GetTargetSP()); if (!clang_ast_context) - return ThreadSP(); + return FailExceptionParsing("Failed to get scratch AST."); CompilerType objc_id = clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID); ValueObjectSP return_addresses; @@ -527,8 +552,8 @@ ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( if (error.Fail()) return ThreadSP(); lldb::offset_t data_offset = 0; - auto dict_entry_key = data.GetPointer(&data_offset); - auto dict_entry_value = data.GetPointer(&data_offset); + auto dict_entry_key = data.GetAddress(&data_offset); + auto dict_entry_value = data.GetAddress(&data_offset); auto key_nsstring = objc_object_from_address(dict_entry_key, "key"); StreamString key_summary; @@ -543,15 +568,22 @@ ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( } } - if (!return_addresses) return ThreadSP(); + if (!return_addresses) + return FailExceptionParsing("Failed to get return addresses."); auto frames_value = return_addresses->GetChildMemberWithName(ConstString("_frames"), true); + if (!frames_value) + return FailExceptionParsing("Failed to get frames_value."); addr_t frames_addr = frames_value->GetValueAsUnsigned(0); auto count_value = return_addresses->GetChildMemberWithName(ConstString("_cnt"), true); + if (!count_value) + return FailExceptionParsing("Failed to get count_value."); size_t count = count_value->GetValueAsUnsigned(0); auto ignore_value = return_addresses->GetChildMemberWithName(ConstString("_ignore"), true); + if (!ignore_value) + return FailExceptionParsing("Failed to get ignore_value."); size_t ignore = ignore_value->GetValueAsUnsigned(0); size_t ptr_size = m_process->GetAddressByteSize(); @@ -563,7 +595,8 @@ ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( pcs.push_back(pc); } - if (pcs.empty()) return ThreadSP(); + if (pcs.empty()) + return FailExceptionParsing("Failed to get PC list."); ThreadSP new_thread_sp(new HistoryThread(*m_process, 0, pcs)); m_process->GetExtendedThreadList().AddThread(new_thread_sp); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h index 79ac53e1e440..e9790871e8c4 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_AppleObjCRuntime_h_ -#define liblldb_AppleObjCRuntime_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIME_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIME_H #include "llvm/ADT/Optional.h" @@ -31,6 +31,10 @@ public: static char ID; + static void Initialize(); + + static void Terminate(); + bool isA(const void *ClassID) const override { return ClassID == &ID || ObjCLanguageRuntime::isA(ClassID); } @@ -84,7 +88,7 @@ public: bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; lldb::SearchFilterSP CreateExceptionSearchFilter() override; - + static std::tuple<FileSpec, ConstString> GetExceptionThrowLocation(); lldb::ValueObjectSP GetExceptionObjectForThread( @@ -97,7 +101,7 @@ public: virtual void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, lldb::addr_t &cf_false); - + virtual bool IsTaggedPointer (lldb::addr_t addr) { return false; } protected: @@ -128,4 +132,4 @@ protected: } // namespace lldb_private -#endif // liblldb_AppleObjCRuntime_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIME_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 88bfe2ce0203..8202686597ae 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -1,5 +1,4 @@ -//===-- AppleObjCRuntimeV1.cpp --------------------------------------*- C++ -//-*-===// +//===-- AppleObjCRuntimeV1.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,12 +12,12 @@ #include "clang/AST/Type.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" @@ -106,8 +105,8 @@ ConstString AppleObjCRuntimeV1::GetPluginName() { uint32_t AppleObjCRuntimeV1::GetPluginVersion() { return 1; } BreakpointResolverSP -AppleObjCRuntimeV1::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, - bool throw_bp) { +AppleObjCRuntimeV1::CreateExceptionResolver(const BreakpointSP &bkpt, + bool catch_bp, bool throw_bp) { BreakpointResolverSP resolver_sp; if (throw_bp) @@ -363,7 +362,7 @@ void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() { lldb::offset_t offset = addr_size; // Skip prototype const uint32_t count = data.GetU32(&offset); const uint32_t num_buckets = data.GetU32(&offset); - const addr_t buckets_ptr = data.GetPointer(&offset); + const addr_t buckets_ptr = data.GetAddress(&offset); if (m_hash_signature.NeedsUpdate(count, num_buckets, buckets_ptr)) { m_hash_signature.UpdateSignature(count, num_buckets, buckets_ptr); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index 6fdae63d4126..d8725d0f57ce 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_AppleObjCRuntimeV1_h_ -#define liblldb_AppleObjCRuntimeV1_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV1_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV1_H #include "AppleObjCRuntime.h" #include "lldb/lldb-private.h" @@ -113,9 +113,9 @@ public: DeclVendor *GetDeclVendor() override; protected: - lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, - bool catch_bp, - bool throw_bp) override; + lldb::BreakpointResolverSP + CreateExceptionResolver(const lldb::BreakpointSP &bkpt, + bool catch_bp, bool throw_bp) override; class HashTableSignature { public: @@ -153,4 +153,4 @@ private: } // namespace lldb_private -#endif // liblldb_AppleObjCRuntimeV1_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV1_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 4015f10c4966..ac9a09394021 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -1,4 +1,4 @@ -//===-- AppleObjCRuntimeV2.cpp ----------------------------------*- C++ -*-===// +//===-- AppleObjCRuntimeV2.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -15,12 +15,11 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Host/OptionParser.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/lldb-enumerations.h" -#include "lldb/Core/ClangForward.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" @@ -35,7 +34,6 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionValueBoolean.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/TypeList.h" @@ -64,6 +62,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/Basic/TargetInfo.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" @@ -582,8 +581,8 @@ protected: case 0: break; case 1: { - regex_up.reset(new RegularExpression( - llvm::StringRef::withNullAsEmpty(command.GetArgumentAtIndex(0)))); + regex_up = std::make_unique<RegularExpression>( + llvm::StringRef::withNullAsEmpty(command.GetArgumentAtIndex(0))); if (!regex_up->IsValid()) { result.AppendError( "invalid argument - please provide a valid regular expression"); @@ -826,8 +825,8 @@ lldb_private::ConstString AppleObjCRuntimeV2::GetPluginName() { uint32_t AppleObjCRuntimeV2::GetPluginVersion() { return 1; } BreakpointResolverSP -AppleObjCRuntimeV2::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, - bool throw_bp) { +AppleObjCRuntimeV2::CreateExceptionResolver(const BreakpointSP &bkpt, + bool catch_bp, bool throw_bp) { BreakpointResolverSP resolver_sp; if (throw_bp) @@ -897,12 +896,12 @@ size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type, const char *ivar_name) { uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET; - const char *class_name = parent_ast_type.GetConstTypeName().AsCString(); - if (class_name && class_name[0] && ivar_name && ivar_name[0]) { + ConstString class_name = parent_ast_type.GetTypeName(); + if (!class_name.IsEmpty() && ivar_name && ivar_name[0]) { // Make the objective C V2 mangled name for the ivar offset from the class // name and ivar name std::string buffer("OBJC_IVAR_$_"); - buffer.append(class_name); + buffer.append(class_name.AsCString()); buffer.push_back('.'); buffer.append(ivar_name); ConstString ivar_const_str(buffer.c_str()); @@ -1176,6 +1175,28 @@ AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) { return class_descriptor_sp; } +static std::pair<bool, ConstString> ObjCGetClassNameRaw( + AppleObjCRuntime::ObjCISA isa, + Process *process) { + StreamString expr_string; + std::string input = std::to_string(isa); + expr_string.Printf("(const char *)objc_debug_class_getNameRaw(%s)", + input.c_str()); + + ValueObjectSP result_sp; + EvaluateExpressionOptions eval_options; + eval_options.SetLanguage(lldb::eLanguageTypeObjC); + eval_options.SetResultIsInternal(true); + eval_options.SetGenerateDebugInfo(true); + eval_options.SetTimeout(process->GetUtilityExpressionTimeout()); + auto eval_result = process->GetTarget().EvaluateExpression( + expr_string.GetData(), + process->GetThreadList().GetSelectedThread()->GetSelectedFrame().get(), + result_sp, eval_options); + ConstString type_name(result_sp->GetSummaryAsCString()); + return std::make_pair(eval_result == eExpressionCompleted, type_name); +} + ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { ClassDescriptorSP objc_class_sp; @@ -1192,32 +1213,43 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { // if we get an invalid VO (which might still happen when playing around with // pointers returned by the expression parser, don't consider this a valid // ObjC object) - if (valobj.GetCompilerType().IsValid()) { - addr_t isa_pointer = valobj.GetPointerValue(); + if (!valobj.GetCompilerType().IsValid()) + return objc_class_sp; + addr_t isa_pointer = valobj.GetPointerValue(); - // tagged pointer - if (IsTaggedPointer(isa_pointer)) { - return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer); - } else { - ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + // tagged pointer + if (IsTaggedPointer(isa_pointer)) + return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer); + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process) { - Status error; - ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); - if (isa != LLDB_INVALID_ADDRESS) { - objc_class_sp = GetClassDescriptorFromISA(isa); - if (isa && !objc_class_sp) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - LLDB_LOGF(log, - "0x%" PRIx64 - ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " - "not in class descriptor cache 0x%" PRIx64, - isa_pointer, isa); - } - } - } - } + Process *process = exe_ctx.GetProcessPtr(); + if (!process) + return objc_class_sp; + + Status error; + ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); + if (isa == LLDB_INVALID_ADDRESS) + return objc_class_sp; + + objc_class_sp = GetClassDescriptorFromISA(isa); + + if (objc_class_sp) + return objc_class_sp; + else { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | + LIBLLDB_LOG_TYPES)); + LLDB_LOGF(log, + "0x%" PRIx64 + ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " + "not in class descriptor cache 0x%" PRIx64, + isa_pointer, isa); + } + + ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, nullptr)); + auto resolved = ObjCGetClassNameRaw(isa, process); + if (resolved.first == true) { + AddClass(isa, descriptor_sp, resolved.second.AsCString()); + objc_class_sp = descriptor_sp; } return objc_class_sp; } @@ -1301,7 +1333,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( return DescriptorMapUpdateResult::Fail(); thread_sp->CalculateExecutionContext(exe_ctx); - ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); + TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); if (!ast) return DescriptorMapUpdateResult::Fail(); @@ -1434,8 +1466,6 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( Value return_value; return_value.SetValueType(Value::eValueTypeScalar); - // return_value.SetContext (Value::eContextTypeClangType, - // clang_uint32_t_type); return_value.SetCompilerType(clang_uint32_t_type); return_value.GetScalar() = 0; @@ -1499,7 +1529,7 @@ uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data, // Iterate through all ClassInfo structures lldb::offset_t offset = 0; for (uint32_t i = 0; i < num_class_infos; ++i) { - ObjCISA isa = data.GetPointer(&offset); + ObjCISA isa = data.GetAddress(&offset); if (isa == 0) { if (should_log) @@ -1563,7 +1593,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { return DescriptorMapUpdateResult::Fail(); thread_sp->CalculateExecutionContext(exe_ctx); - ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); + TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); if (!ast) return DescriptorMapUpdateResult::Fail(); @@ -1660,13 +1690,11 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { // Next make the function caller for our implementation utility function. Value value; value.SetValueType(Value::eValueTypeScalar); - // value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type); value.SetCompilerType(clang_void_pointer_type); arguments.PushValue(value); arguments.PushValue(value); value.SetValueType(Value::eValueTypeScalar); - // value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); value.SetCompilerType(clang_uint32_t_type); arguments.PushValue(value); arguments.PushValue(value); @@ -1732,8 +1760,6 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { Value return_value; return_value.SetValueType(Value::eValueTypeScalar); - // return_value.SetContext (Value::eContextTypeClangType, - // clang_uint32_t_type); return_value.SetCompilerType(clang_uint32_t_type); return_value.GetScalar() = 0; @@ -1980,7 +2006,7 @@ void AppleObjCRuntimeV2::WarnIfNoClassesCached( DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() { if (!m_decl_vendor_up) - m_decl_vendor_up.reset(new AppleObjCDeclVendor(*this)); + m_decl_vendor_up = std::make_unique<AppleObjCDeclVendor>(*this); return m_decl_vendor_up.get(); } @@ -2477,7 +2503,7 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( ObjCISA isa, ObjCISA &ret_isa) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES)); - LLDB_LOGF(log, "AOCRT::NPI Evalulate(isa = 0x%" PRIx64 ")", (uint64_t)isa); + LLDB_LOGF(log, "AOCRT::NPI Evaluate(isa = 0x%" PRIx64 ")", (uint64_t)isa); if ((isa & ~m_objc_debug_isa_class_mask) == 0) return false; @@ -2550,7 +2576,7 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( lldb::offset_t offset = 0; for (unsigned i = 0; i != num_new_classes; ++i) - m_indexed_isa_cache.push_back(data.GetPointer(&offset)); + m_indexed_isa_cache.push_back(data.GetAddress(&offset)); } } @@ -2558,7 +2584,7 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( if (index > m_indexed_isa_cache.size()) return false; - LLDB_LOGF(log, "AOCRT::NPI Evalulate(ret_isa = 0x%" PRIx64 ")", + LLDB_LOGF(log, "AOCRT::NPI Evaluate(ret_isa = 0x%" PRIx64 ")", (uint64_t)m_indexed_isa_cache[index]); ret_isa = m_indexed_isa_cache[index]; @@ -2642,8 +2668,8 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { const lldb::ABISP &abi = process_sp->GetABI(); if (!abi) return; - ClangASTContext *clang_ast_context = - ClangASTContext::GetScratch(process_sp->GetTarget()); + TypeSystemClang *clang_ast_context = + TypeSystemClang::GetScratch(process_sp->GetTarget()); if (!clang_ast_context) return; CompilerType voidstar = @@ -2668,6 +2694,8 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { m_arguments = ValueObjectListSP(new ValueObjectList()); m_arguments->Append(exception); + + m_stop_desc = "hit Objective-C exception"; } ValueObjectSP exception; @@ -2689,8 +2717,10 @@ static void RegisterObjCExceptionRecognizer() { FileSpec module; ConstString function; std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); + std::vector<ConstString> symbols = {function}; StackFrameRecognizerManager::AddRecognizer( StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), - module.GetFilename(), function, /*first_instruction_only*/ true); + module.GetFilename(), symbols, + /*first_instruction_only*/ true); }); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 785bb3938d2c..99264d556da5 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_AppleObjCRuntimeV2_h_ -#define liblldb_AppleObjCRuntimeV2_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H #include <map> #include <memory> @@ -103,9 +103,9 @@ public: static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; protected: - lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, - bool catch_bp, - bool throw_bp) override; + lldb::BreakpointResolverSP + CreateExceptionResolver(const lldb::BreakpointSP &bkpt, + bool catch_bp, bool throw_bp) override; private: class HashTableSignature { @@ -162,7 +162,8 @@ private: friend class AppleObjCRuntimeV2; - DISALLOW_COPY_AND_ASSIGN(NonPointerISACache); + NonPointerISACache(const NonPointerISACache &) = delete; + const NonPointerISACache &operator=(const NonPointerISACache &) = delete; }; class TaggedPointerVendorV2 @@ -181,7 +182,9 @@ private: : TaggedPointerVendor(), m_runtime(runtime) {} private: - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorV2); + TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete; + const TaggedPointerVendorV2 & + operator=(const TaggedPointerVendorV2 &) = delete; }; class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 { @@ -212,7 +215,10 @@ private: friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorRuntimeAssisted); + TaggedPointerVendorRuntimeAssisted( + const TaggedPointerVendorRuntimeAssisted &) = delete; + const TaggedPointerVendorRuntimeAssisted & + operator=(const TaggedPointerVendorRuntimeAssisted &) = delete; }; class TaggedPointerVendorExtended @@ -250,7 +256,9 @@ private: friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorExtended); + TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete; + const TaggedPointerVendorExtended & + operator=(const TaggedPointerVendorExtended &) = delete; }; class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 { @@ -266,7 +274,9 @@ private: friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorLegacy); + TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete; + const TaggedPointerVendorLegacy & + operator=(const TaggedPointerVendorLegacy &) = delete; }; struct DescriptorMapUpdateResult { @@ -337,4 +347,4 @@ private: } // namespace lldb_private -#endif // liblldb_AppleObjCRuntimeV2_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index 36f95c063b81..c96768c9f585 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -1,5 +1,4 @@ -//===-- AppleObjCTrampolineHandler.cpp ----------------------------*- C++ -//-*-===// +//===-- AppleObjCTrampolineHandler.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,6 +9,7 @@ #include "AppleObjCTrampolineHandler.h" #include "AppleThreadPlanStepThroughObjCTrampoline.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -19,7 +19,6 @@ #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UserExpression.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" @@ -319,7 +318,7 @@ void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion() { const uint16_t descriptor_size = data.GetU16(&offset); const size_t num_descriptors = data.GetU32(&offset); - m_next_region = data.GetPointer(&offset); + m_next_region = data.GetAddress(&offset); // If the header size is 0, that means we've come in too early before this // data is set up. @@ -521,8 +520,8 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines( Process *process = exe_ctx.GetProcessPtr(); const ABI *abi = process->GetABI().get(); - ClangASTContext *clang_ast_context = - ClangASTContext::GetScratch(process->GetTarget()); + TypeSystemClang *clang_ast_context = + TypeSystemClang::GetScratch(process->GetTarget()); if (!clang_ast_context) return false; @@ -548,7 +547,7 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines( error = argument_values.GetValueAtIndex(0)->GetValueAsData(&exe_ctx, data, nullptr); lldb::offset_t offset = 0; - lldb::addr_t region_addr = data.GetPointer(&offset); + lldb::addr_t region_addr = data.GetAddress(&offset); if (region_addr != 0) vtable_handler->ReadRegions(region_addr); @@ -657,6 +656,27 @@ const AppleObjCTrampolineHandler::DispatchFunction DispatchFunction::eFixUpFixed}, }; +// This is the table of ObjC "accelerated dispatch" functions. They are a set +// of objc methods that are "seldom overridden" and so the compiler replaces the +// objc_msgSend with a call to one of the dispatch functions. That will check +// whether the method has been overridden, and directly call the Foundation +// implementation if not. +// This table is supposed to be complete. If ones get added in the future, we +// will have to add them to the table. +const char *AppleObjCTrampolineHandler::g_opt_dispatch_names[] = { + "objc_alloc", + "objc_autorelease", + "objc_release", + "objc_retain", + "objc_alloc_init", + "objc_allocWithZone", + "objc_opt_class", + "objc_opt_isKindOfClass", + "objc_opt_new", + "objc_opt_respondsToSelector", + "objc_opt_self", +}; + AppleObjCTrampolineHandler::AppleObjCTrampolineHandler( const ProcessSP &process_sp, const ModuleSP &objc_module_sp) : m_process_wp(), m_objc_module_sp(objc_module_sp), @@ -751,9 +771,24 @@ AppleObjCTrampolineHandler::AppleObjCTrampolineHandler( m_msgSend_map.insert(std::pair<lldb::addr_t, int>(sym_addr, i)); } } + + // Similarly, cache the addresses of the "optimized dispatch" function. + for (size_t i = 0; i != llvm::array_lengthof(g_opt_dispatch_names); i++) { + ConstString name_const_str(g_opt_dispatch_names[i]); + const Symbol *msgSend_symbol = + m_objc_module_sp->FindFirstSymbolWithNameAndType(name_const_str, + eSymbolTypeCode); + if (msgSend_symbol && msgSend_symbol->ValueIsAddress()) { + lldb::addr_t sym_addr = + msgSend_symbol->GetAddressRef().GetOpcodeLoadAddress(target); + + m_opt_dispatch_map.emplace(sym_addr, i); + } + } // Build our vtable dispatch handler here: - m_vtables_up.reset(new AppleObjCVTables(process_sp, m_objc_module_sp)); + m_vtables_up = + std::make_unique<AppleObjCVTables>(process_sp, m_objc_module_sp); if (m_vtables_up) m_vtables_up->ReadRegions(); } @@ -804,8 +839,8 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, } // Next make the runner function for our implementation utility function. - ClangASTContext *clang_ast_context = - ClangASTContext::GetScratch(thread.GetProcess()->GetTarget()); + TypeSystemClang *clang_ast_context = + TypeSystemClang::GetScratch(thread.GetProcess()->GetTarget()); if (!clang_ast_context) return LLDB_INVALID_ADDRESS; @@ -846,45 +881,53 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, return args_addr; } +const AppleObjCTrampolineHandler::DispatchFunction * +AppleObjCTrampolineHandler::FindDispatchFunction(lldb::addr_t addr) { + MsgsendMap::iterator pos; + pos = m_msgSend_map.find(addr); + if (pos != m_msgSend_map.end()) { + return &g_dispatch_functions[(*pos).second]; + } + return nullptr; +} + +void +AppleObjCTrampolineHandler::ForEachDispatchFunction( + std::function<void(lldb::addr_t, + const DispatchFunction &)> callback) { + for (auto elem : m_msgSend_map) { + callback(elem.first, g_dispatch_functions[elem.second]); + } +} + ThreadPlanSP AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, bool stop_others) { ThreadPlanSP ret_plan_sp; lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); - DispatchFunction this_dispatch; - bool found_it = false; + DispatchFunction vtable_dispatch + = {"vtable", 0, false, false, DispatchFunction::eFixUpFixed}; // First step is to look and see if we are in one of the known ObjC // dispatch functions. We've already compiled a table of same, so // consult it. - MsgsendMap::iterator pos; - pos = m_msgSend_map.find(curr_pc); - if (pos != m_msgSend_map.end()) { - this_dispatch = g_dispatch_functions[(*pos).second]; - found_it = true; - } - + const DispatchFunction *this_dispatch = FindDispatchFunction(curr_pc); + // Next check to see if we are in a vtable region: - if (!found_it) { + if (!this_dispatch && m_vtables_up) { uint32_t flags; - if (m_vtables_up) { - found_it = m_vtables_up->IsAddressInVTables(curr_pc, flags); - if (found_it) { - this_dispatch.name = "vtable"; - this_dispatch.stret_return = - (flags & AppleObjCVTables::eOBJC_TRAMPOLINE_STRET) == - AppleObjCVTables::eOBJC_TRAMPOLINE_STRET; - this_dispatch.is_super = false; - this_dispatch.is_super2 = false; - this_dispatch.fixedup = DispatchFunction::eFixUpFixed; - } + if (m_vtables_up->IsAddressInVTables(curr_pc, flags)) { + vtable_dispatch.stret_return = + (flags & AppleObjCVTables::eOBJC_TRAMPOLINE_STRET) == + AppleObjCVTables::eOBJC_TRAMPOLINE_STRET; + this_dispatch = &vtable_dispatch; } } - if (found_it) { + if (this_dispatch) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); // We are decoding a method dispatch. First job is to pull the @@ -901,7 +944,7 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, TargetSP target_sp(thread.CalculateTarget()); - ClangASTContext *clang_ast_context = ClangASTContext::GetScratch(*target_sp); + TypeSystemClang *clang_ast_context = TypeSystemClang::GetScratch(*target_sp); if (!clang_ast_context) return ret_plan_sp; @@ -921,7 +964,7 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, // the return struct pointer, and the object is the second, and // the selector is the third. Otherwise the object is the first // and the selector the second. - if (this_dispatch.stret_return) { + if (this_dispatch->stret_return) { obj_index = 1; sel_index = 2; argument_values.PushValue(void_ptr_value); @@ -963,8 +1006,8 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, // run-to-address plan directly. Otherwise we have to figure out // where the implementation lives. - if (this_dispatch.is_super) { - if (this_dispatch.is_super2) { + if (this_dispatch->is_super) { + if (this_dispatch->is_super2) { // In the objc_msgSendSuper2 case, we don't get the object // directly, we get a structure containing the object and the // class to which the super message is being sent. So we need @@ -1087,25 +1130,25 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, // flag_value.SetContext (Value::eContextTypeClangType, clang_int_type); flag_value.SetCompilerType(clang_int_type); - if (this_dispatch.stret_return) + if (this_dispatch->stret_return) flag_value.GetScalar() = 1; else flag_value.GetScalar() = 0; dispatch_values.PushValue(flag_value); - if (this_dispatch.is_super) + if (this_dispatch->is_super) flag_value.GetScalar() = 1; else flag_value.GetScalar() = 0; dispatch_values.PushValue(flag_value); - if (this_dispatch.is_super2) + if (this_dispatch->is_super2) flag_value.GetScalar() = 1; else flag_value.GetScalar() = 0; dispatch_values.PushValue(flag_value); - switch (this_dispatch.fixedup) { + switch (this_dispatch->fixedup) { case DispatchFunction::eFixUpNone: flag_value.GetScalar() = 0; dispatch_values.PushValue(flag_value); @@ -1135,7 +1178,7 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, // stop_others value passed in to us here: const bool trampoline_stop_others = false; ret_plan_sp = std::make_shared<AppleThreadPlanStepThroughObjCTrampoline>( - thread, this, dispatch_values, isa_addr, sel_addr, + thread, *this, dispatch_values, isa_addr, sel_addr, trampoline_stop_others); if (log) { StreamString s; @@ -1144,6 +1187,26 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, } } } + + // Finally, check if we have hit an "optimized dispatch" function. This will + // either directly call the base implementation or dispatch an objc_msgSend + // if the method has been overridden. So we just do a "step in/step out", + // setting a breakpoint on objc_msgSend, and if we hit the msgSend, we + // will automatically step in again. That's the job of the + // AppleThreadPlanStepThroughDirectDispatch. + if (!this_dispatch && !ret_plan_sp) { + MsgsendMap::iterator pos; + pos = m_opt_dispatch_map.find(curr_pc); + if (pos != m_opt_dispatch_map.end()) { + + const char *opt_name = g_opt_dispatch_names[(*pos).second]; + + bool trampoline_stop_others = false; + LazyBool step_in_should_stop = eLazyBoolCalculate; + ret_plan_sp = std::make_shared<AppleThreadPlanStepThroughDirectDispatch> ( + thread, *this, opt_name, trampoline_stop_others, step_in_should_stop); + } + } return ret_plan_sp; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h index d120d671eeb3..27aebd8594df 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_AppleObjCTrampolineHandler_h_ -#define lldb_AppleObjCTrampolineHandler_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H #include <map> #include <mutex> @@ -47,6 +47,9 @@ public: lldb::addr_t SetupDispatchFunction(Thread &thread, ValueList &dispatch_values); + const DispatchFunction *FindDispatchFunction(lldb::addr_t addr); + void ForEachDispatchFunction(std::function<void(lldb::addr_t, + const DispatchFunction &)>); private: static const char *g_lookup_implementation_function_name; @@ -96,7 +99,6 @@ private: void Dump(Stream &s); - public: bool m_valid; AppleObjCVTables *m_owner; lldb::addr_t m_header_addr; @@ -136,11 +138,13 @@ private: }; static const DispatchFunction g_dispatch_functions[]; + static const char *g_opt_dispatch_names[]; - typedef std::map<lldb::addr_t, int> MsgsendMap; // This table maps an dispatch + using MsgsendMap = std::map<lldb::addr_t, int>; // This table maps an dispatch // fn address to the index in // g_dispatch_functions MsgsendMap m_msgSend_map; + MsgsendMap m_opt_dispatch_map; lldb::ProcessWP m_process_wp; lldb::ModuleSP m_objc_module_sp; const char *m_lookup_implementation_function_code; @@ -155,4 +159,4 @@ private: } // namespace lldb_private -#endif // lldb_AppleObjCTrampolineHandler_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index 66f04bef6cbd..b19d3d90d4b7 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -1,4 +1,4 @@ -//===-- AppleObjCTypeEncodingParser.cpp -------------------------*- C++ -*-===// +//===-- AppleObjCTypeEncodingParser.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,13 +8,15 @@ #include "AppleObjCTypeEncodingParser.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/StringLexer.h" +#include "clang/Basic/TargetInfo.h" + #include <vector> using namespace lldb_private; @@ -23,17 +25,16 @@ AppleObjCTypeEncodingParser::AppleObjCTypeEncodingParser( ObjCLanguageRuntime &runtime) : ObjCLanguageRuntime::EncodingToType(), m_runtime(runtime) { if (!m_scratch_ast_ctx_up) - m_scratch_ast_ctx_up.reset(new ClangASTContext(runtime.GetProcess() - ->GetTarget() - .GetArchitecture() - .GetTriple())); + m_scratch_ast_ctx_up = std::make_unique<TypeSystemClang>( + "AppleObjCTypeEncodingParser ASTContext", + runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple()); } std::string AppleObjCTypeEncodingParser::ReadStructName(StringLexer &type) { StreamString buffer; while (type.HasAtLeast(1) && type.Peek() != '=') buffer.Printf("%c", type.Next()); - return buffer.GetString(); + return std::string(buffer.GetString()); } std::string AppleObjCTypeEncodingParser::ReadQuotedString(StringLexer &type) { @@ -43,7 +44,7 @@ std::string AppleObjCTypeEncodingParser::ReadQuotedString(StringLexer &type) { StringLexer::Character next = type.Next(); UNUSED_IF_ASSERT_DISABLED(next); assert(next == '"'); - return buffer.GetString(); + return std::string(buffer.GetString()); } uint32_t AppleObjCTypeEncodingParser::ReadNumber(StringLexer &type) { @@ -61,7 +62,7 @@ AppleObjCTypeEncodingParser::StructElement::StructElement() : name(""), type(clang::QualType()), bitfield(0) {} AppleObjCTypeEncodingParser::StructElement -AppleObjCTypeEncodingParser::ReadStructElement(ClangASTContext &ast_ctx, +AppleObjCTypeEncodingParser::ReadStructElement(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) { StructElement retval; @@ -76,19 +77,19 @@ AppleObjCTypeEncodingParser::ReadStructElement(ClangASTContext &ast_ctx, } clang::QualType AppleObjCTypeEncodingParser::BuildStruct( - ClangASTContext &ast_ctx, StringLexer &type, bool for_expression) { + TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) { return BuildAggregate(ast_ctx, type, for_expression, '{', '}', clang::TTK_Struct); } clang::QualType AppleObjCTypeEncodingParser::BuildUnion( - ClangASTContext &ast_ctx, StringLexer &type, bool for_expression) { + TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) { return BuildAggregate(ast_ctx, type, for_expression, '(', ')', clang::TTK_Union); } clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( - ClangASTContext &ast_ctx, StringLexer &type, bool for_expression, + TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression, char opener, char closer, uint32_t kind) { if (!type.NextIf(opener)) return clang::QualType(); @@ -123,29 +124,30 @@ clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( return clang::QualType(); // This is where we bail out. Sorry! CompilerType union_type(ast_ctx.CreateRecordType( - nullptr, lldb::eAccessPublic, name, kind, lldb::eLanguageTypeC)); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, name, kind, + lldb::eLanguageTypeC)); if (union_type) { - ClangASTContext::StartTagDeclarationDefinition(union_type); + TypeSystemClang::StartTagDeclarationDefinition(union_type); unsigned int count = 0; for (auto element : elements) { if (element.name.empty()) { StreamString elem_name; elem_name.Printf("__unnamed_%u", count); - element.name = elem_name.GetString(); + element.name = std::string(elem_name.GetString()); } - ClangASTContext::AddFieldToRecordType( + TypeSystemClang::AddFieldToRecordType( union_type, element.name.c_str(), ast_ctx.GetType(element.type), lldb::eAccessPublic, element.bitfield); ++count; } - ClangASTContext::CompleteTagDeclarationDefinition(union_type); + TypeSystemClang::CompleteTagDeclarationDefinition(union_type); } return ClangUtil::GetQualType(union_type); } clang::QualType AppleObjCTypeEncodingParser::BuildArray( - ClangASTContext &ast_ctx, StringLexer &type, bool for_expression) { + TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) { if (!type.NextIf('[')) return clang::QualType(); uint32_t size = ReadNumber(type); @@ -163,7 +165,7 @@ clang::QualType AppleObjCTypeEncodingParser::BuildArray( // consume but ignore the type info and always return an 'id'; if anything, // dynamic typing will resolve things for us anyway clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( - ClangASTContext &clang_ast_ctx, StringLexer &type, bool for_expression) { + TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression) { if (!type.NextIf('@')) return clang::QualType(); @@ -247,7 +249,7 @@ clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( } clang::QualType -AppleObjCTypeEncodingParser::BuildType(ClangASTContext &clang_ast_ctx, +AppleObjCTypeEncodingParser::BuildType(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression, uint32_t *bitfield_bit_size) { if (!type.HasAtLeast(1)) @@ -353,7 +355,7 @@ AppleObjCTypeEncodingParser::BuildType(ClangASTContext &clang_ast_ctx, } } -CompilerType AppleObjCTypeEncodingParser::RealizeType(ClangASTContext &ast_ctx, +CompilerType AppleObjCTypeEncodingParser::RealizeType(TypeSystemClang &ast_ctx, const char *name, bool for_expression) { if (name && name[0]) { diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h index e43711bf4ee4..9a108967e1ab 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_AppleObjCTypeEncodingParser_h_ -#define liblldb_AppleObjCTypeEncodingParser_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTYPEENCODINGPARSER_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTYPEENCODINGPARSER_H #include "clang/AST/ASTContext.h" @@ -22,7 +22,7 @@ public: AppleObjCTypeEncodingParser(ObjCLanguageRuntime &runtime); ~AppleObjCTypeEncodingParser() override = default; - CompilerType RealizeType(ClangASTContext &ast_ctx, const char *name, + CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name, bool for_expression) override; private: @@ -35,29 +35,29 @@ private: ~StructElement() = default; }; - clang::QualType BuildType(ClangASTContext &clang_ast_ctx, StringLexer &type, + clang::QualType BuildType(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression, uint32_t *bitfield_bit_size = nullptr); - clang::QualType BuildStruct(ClangASTContext &ast_ctx, StringLexer &type, + clang::QualType BuildStruct(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression); - clang::QualType BuildAggregate(ClangASTContext &clang_ast_ctx, + clang::QualType BuildAggregate(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression, char opener, char closer, uint32_t kind); - clang::QualType BuildUnion(ClangASTContext &ast_ctx, StringLexer &type, + clang::QualType BuildUnion(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression); - clang::QualType BuildArray(ClangASTContext &ast_ctx, StringLexer &type, + clang::QualType BuildArray(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression); std::string ReadStructName(StringLexer &type); - StructElement ReadStructElement(ClangASTContext &ast_ctx, StringLexer &type, + StructElement ReadStructElement(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression); - clang::QualType BuildObjCObjectPointerType(ClangASTContext &clang_ast_ctx, + clang::QualType BuildObjCObjectPointerType(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression); @@ -70,4 +70,4 @@ private: } // namespace lldb_private -#endif // liblldb_AppleObjCTypeEncodingParser_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTYPEENCODINGPARSER_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index af630eee7265..653e007c7b5f 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -1,4 +1,4 @@ -//===-- AppleThreadPlanStepThroughObjCTrampoline.cpp +//===-- AppleThreadPlanStepThroughObjCTrampoline.cpp-----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -29,7 +29,7 @@ using namespace lldb_private; // ThreadPlanStepThroughObjCTrampoline constructor AppleThreadPlanStepThroughObjCTrampoline:: AppleThreadPlanStepThroughObjCTrampoline( - Thread &thread, AppleObjCTrampolineHandler *trampoline_handler, + Thread &thread, AppleObjCTrampolineHandler &trampoline_handler, ValueList &input_values, lldb::addr_t isa_addr, lldb::addr_t sel_addr, bool stop_others) : ThreadPlan(ThreadPlan::eKindGeneric, @@ -48,31 +48,30 @@ void AppleThreadPlanStepThroughObjCTrampoline::DidPush() { // Setting up the memory space for the called function text might require // allocations, i.e. a nested function call. This needs to be done as a // PreResumeAction. - m_thread.GetProcess()->AddPreResumeAction(PreResumeInitializeFunctionCaller, - (void *)this); + m_process.AddPreResumeAction(PreResumeInitializeFunctionCaller, (void *)this); } bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() { if (!m_func_sp) { DiagnosticManager diagnostics; m_args_addr = - m_trampoline_handler->SetupDispatchFunction(m_thread, m_input_values); + m_trampoline_handler.SetupDispatchFunction(GetThread(), m_input_values); if (m_args_addr == LLDB_INVALID_ADDRESS) { return false; } m_impl_function = - m_trampoline_handler->GetLookupImplementationFunctionCaller(); + m_trampoline_handler.GetLookupImplementationFunctionCaller(); ExecutionContext exc_ctx; EvaluateExpressionOptions options; options.SetUnwindOnError(true); options.SetIgnoreBreakpoints(true); options.SetStopOthers(m_stop_others); - m_thread.CalculateExecutionContext(exc_ctx); + GetThread().CalculateExecutionContext(exc_ctx); m_func_sp = m_impl_function->GetThreadPlanToCallFunction( exc_ctx, m_args_addr, options, diagnostics); m_func_sp->SetOkayToDiscard(true); - m_thread.QueueThreadPlan(m_func_sp, false); + PushPlan(m_func_sp); } return true; } @@ -132,7 +131,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { if (!m_run_to_sp) { Value target_addr_value; ExecutionContext exc_ctx; - m_thread.CalculateExecutionContext(exc_ctx); + GetThread().CalculateExecutionContext(exc_ctx); m_impl_function->FetchFunctionResults(exc_ctx, m_args_addr, target_addr_value); m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr); @@ -145,19 +144,19 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { SetPlanComplete(); return true; } - if (m_trampoline_handler->AddrIsMsgForward(target_addr)) { + if (m_trampoline_handler.AddrIsMsgForward(target_addr)) { LLDB_LOGF(log, "Implementation lookup returned msgForward function: 0x%" PRIx64 ", stopping.", target_addr); - SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext( + SymbolContext sc = GetThread().GetStackFrameAtIndex(0)->GetSymbolContext( eSymbolContextEverything); Status status; const bool abort_other_plans = false; const bool first_insn = true; const uint32_t frame_idx = 0; - m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( + m_run_to_sp = GetThread().QueueThreadPlanForStepOutNoShouldStop( abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion, eVoteNoOpinion, frame_idx, status); if (m_run_to_sp && status.Success()) @@ -180,11 +179,10 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { // Extract the target address from the value: m_run_to_sp = std::make_shared<ThreadPlanRunToAddress>( - m_thread, target_so_addr, m_stop_others); - m_thread.QueueThreadPlan(m_run_to_sp, false); - m_run_to_sp->SetPrivate(true); + GetThread(), target_so_addr, m_stop_others); + PushPlan(m_run_to_sp); return false; - } else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) { + } else if (GetThread().IsThreadPlanDone(m_run_to_sp.get())) { // Third stage, work the run to target plan. SetPlanComplete(); return true; @@ -199,3 +197,227 @@ bool AppleThreadPlanStepThroughObjCTrampoline::MischiefManaged() { } bool AppleThreadPlanStepThroughObjCTrampoline::WillStop() { return true; } + +// Objective-C uses optimized dispatch functions for some common and seldom +// overridden methods. For instance +// [object respondsToSelector:]; +// will get compiled to: +// objc_opt_respondsToSelector(object); +// This checks whether the selector has been overridden, directly calling the +// implementation if it hasn't and calling objc_msgSend if it has. +// +// We need to get into the overridden implementation. We'll do that by +// setting a breakpoint on objc_msgSend, and doing a "step out". If we stop +// at objc_msgSend, we can step through to the target of the send, and see if +// that's a place we want to stop. +// +// A couple of complexities. The checking code might call some other method, +// so we might see objc_msgSend more than once. Also, these optimized dispatch +// functions might dispatch more than one message at a time (e.g. alloc followed +// by init.) So we can't give up at the first objc_msgSend. +// That means among other things that we have to handle the "ShouldStopHere" - +// since we can't just return control to the plan that's controlling us on the +// first step. + +AppleThreadPlanStepThroughDirectDispatch :: + AppleThreadPlanStepThroughDirectDispatch( + Thread &thread, AppleObjCTrampolineHandler &handler, + llvm::StringRef dispatch_func_name, bool stop_others, + LazyBool step_in_avoids_code_without_debug_info) + : ThreadPlanStepOut(thread, nullptr, true /* first instruction */, + stop_others, eVoteNoOpinion, eVoteNoOpinion, + 0 /* Step out of zeroth frame */, + eLazyBoolNo /* Our parent plan will decide this + when we are done */ + , + true /* Run to branch for inline step out */, + false /* Don't gather the return value */), + m_trampoline_handler(handler), + m_dispatch_func_name(std::string(dispatch_func_name)), + m_at_msg_send(false), m_stop_others(stop_others) { + // Set breakpoints on the dispatch functions: + auto bkpt_callback = [&] (lldb::addr_t addr, + const AppleObjCTrampolineHandler + ::DispatchFunction &dispatch) { + m_msgSend_bkpts.push_back(GetTarget().CreateBreakpoint(addr, + true /* internal */, + false /* hard */)); + m_msgSend_bkpts.back()->SetThreadID(GetThread().GetID()); + }; + handler.ForEachDispatchFunction(bkpt_callback); + + // We'll set the step-out plan in the DidPush so it gets queued in the right + // order. + + bool avoid_nodebug = true; + + switch (step_in_avoids_code_without_debug_info) { + case eLazyBoolYes: + avoid_nodebug = true; + break; + case eLazyBoolNo: + avoid_nodebug = false; + break; + case eLazyBoolCalculate: + avoid_nodebug = GetThread().GetStepInAvoidsNoDebug(); + break; + } + if (avoid_nodebug) + GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); + else + GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); + // We only care about step in. Our parent plan will figure out what to + // do when we've stepped out again. + GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); +} + +AppleThreadPlanStepThroughDirectDispatch:: + ~AppleThreadPlanStepThroughDirectDispatch() { + for (BreakpointSP bkpt_sp : m_msgSend_bkpts) { + GetTarget().RemoveBreakpointByID(bkpt_sp->GetID()); + } +} + +void AppleThreadPlanStepThroughDirectDispatch::GetDescription( + Stream *s, lldb::DescriptionLevel level) { + switch (level) { + case lldb::eDescriptionLevelBrief: + s->PutCString("Step through ObjC direct dispatch function."); + break; + default: + s->Printf("Step through ObjC direct dispatch '%s' using breakpoints: ", + m_dispatch_func_name.c_str()); + bool first = true; + for (auto bkpt_sp : m_msgSend_bkpts) { + if (!first) { + s->PutCString(", "); + } + first = false; + s->Printf("%d", bkpt_sp->GetID()); + } + (*s) << "."; + break; + } +} + +bool +AppleThreadPlanStepThroughDirectDispatch::DoPlanExplainsStop(Event *event_ptr) { + if (ThreadPlanStepOut::DoPlanExplainsStop(event_ptr)) + return true; + + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + + // Check if the breakpoint is one of ours msgSend dispatch breakpoints. + + StopReason stop_reason = eStopReasonNone; + if (stop_info_sp) + stop_reason = stop_info_sp->GetStopReason(); + + // See if this is one of our msgSend breakpoints: + if (stop_reason == eStopReasonBreakpoint) { + ProcessSP process_sp = GetThread().GetProcess(); + uint64_t break_site_id = stop_info_sp->GetValue(); + BreakpointSiteSP site_sp + = process_sp->GetBreakpointSiteList().FindByID(break_site_id); + // Some other plan might have deleted the site's last owner before this + // got to us. In which case, it wasn't our breakpoint... + if (!site_sp) + return false; + + for (BreakpointSP break_sp : m_msgSend_bkpts) { + 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) { + SetPlanComplete(true); + return false; + } + m_at_msg_send = true; + return true; + } + } + } + + // We're done here. If one of our sub-plans explained the stop, they + // would have already answered true to PlanExplainsStop, and if they were + // done, we'll get called to figure out what to do in ShouldStop... + return false; +} + +bool AppleThreadPlanStepThroughDirectDispatch + ::DoWillResume(lldb::StateType resume_state, bool current_plan) { + ThreadPlanStepOut::DoWillResume(resume_state, current_plan); + m_at_msg_send = false; + return true; +} + +bool AppleThreadPlanStepThroughDirectDispatch::ShouldStop(Event *event_ptr) { + // If step out plan finished, that means we didn't find our way into a method + // implementation. Either we went directly to the default implementation, + // of the overridden implementation didn't have debug info. + // So we should mark ourselves as done. + const bool step_out_should_stop = ThreadPlanStepOut::ShouldStop(event_ptr); + if (step_out_should_stop) { + SetPlanComplete(true); + return true; + } + + // If we have a step through plan, then w're in the process of getting + // through an ObjC msgSend. If we arrived at the target function, then + // check whether we have debug info, and if we do, stop. + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + if (m_objc_step_through_sp && m_objc_step_through_sp->IsPlanComplete()) { + // If the plan failed for some reason, we should probably just let the + // step over plan get us out of here... We don't need to do anything about + // the step through plan, it is done and will get popped when we continue. + if (!m_objc_step_through_sp->PlanSucceeded()) { + LLDB_LOGF(log, "ObjC Step through plan failed. Stepping out."); + } + Status error; + if (InvokeShouldStopHereCallback(eFrameCompareYounger, error)) { + SetPlanComplete(true); + return true; + } + // If we didn't want to stop at this msgSend, there might be another so + // we should just continue on with the step out and see if our breakpoint + // triggers again. + m_objc_step_through_sp.reset(); + for (BreakpointSP bkpt_sp : m_msgSend_bkpts) { + bkpt_sp->SetEnabled(true); + } + return false; + } + + // If we hit an msgSend breakpoint, then we should queue the step through + // plan: + + if (m_at_msg_send) { + LanguageRuntime *objc_runtime + = GetThread().GetProcess()->GetLanguageRuntime(eLanguageTypeObjC); + // There's no way we could have gotten here without an ObjC language + // runtime. + assert(objc_runtime); + m_objc_step_through_sp + = objc_runtime->GetStepThroughTrampolinePlan(GetThread(), m_stop_others); + // If we failed to find the target for this dispatch, just keep going and + // let the step out complete. + if (!m_objc_step_through_sp) { + LLDB_LOG(log, "Couldn't find target for message dispatch, continuing."); + return false; + } + // Otherwise push the step through plan and continue. + GetThread().QueueThreadPlan(m_objc_step_through_sp, false); + for (BreakpointSP bkpt_sp : m_msgSend_bkpts) { + bkpt_sp->SetEnabled(false); + } + return false; + } + return true; +} + +bool AppleThreadPlanStepThroughDirectDispatch::MischiefManaged() { + if (IsPlanComplete()) + return true; + return ThreadPlanStepOut::MischiefManaged(); +} diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h index 96f37851a35f..89aed89f1ab1 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h @@ -6,12 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_AppleThreadPlanStepThroughObjCTrampoline_h_ -#define lldb_AppleThreadPlanStepThroughObjCTrampoline_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLETHREADPLANSTEPTHROUGHOBJCTRAMPOLINE_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLETHREADPLANSTEPTHROUGHOBJCTRAMPOLINE_H #include "AppleObjCTrampolineHandler.h" #include "lldb/Core/Value.h" #include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanStepInRange.h" +#include "lldb/Target/ThreadPlanStepOut.h" +#include "lldb/Target/ThreadPlanShouldStopHere.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-types.h" @@ -20,7 +23,7 @@ namespace lldb_private { class AppleThreadPlanStepThroughObjCTrampoline : public ThreadPlan { public: AppleThreadPlanStepThroughObjCTrampoline( - Thread &thread, AppleObjCTrampolineHandler *trampoline_handler, + Thread &thread, AppleObjCTrampolineHandler &trampoline_handler, ValueList &values, lldb::addr_t isa_addr, lldb::addr_t sel_addr, bool stop_others); @@ -52,25 +55,62 @@ protected: private: bool InitializeFunctionCaller(); - AppleObjCTrampolineHandler *m_trampoline_handler; // FIXME - ensure this - // doesn't go away on us? - // SP maybe? - lldb::addr_t m_args_addr; // Stores the address for our step through function - // result structure. - // lldb::addr_t m_object_addr; // This is only for Description. + AppleObjCTrampolineHandler &m_trampoline_handler; /// The handler itself. + lldb::addr_t m_args_addr; /// Stores the address for our step through function + /// result structure. ValueList m_input_values; - lldb::addr_t m_isa_addr; // isa_addr and sel_addr are the keys we will use to - // cache the implementation. + lldb::addr_t m_isa_addr; /// isa_addr and sel_addr are the keys we will use to + /// cache the implementation. lldb::addr_t m_sel_addr; - lldb::ThreadPlanSP m_func_sp; // This is the function call plan. We fill it - // at start, then set it - // to NULL when this plan is done. That way we know to go to: - lldb::ThreadPlanSP m_run_to_sp; // The plan that runs to the target. - FunctionCaller *m_impl_function; // This is a pointer to a impl function that - // is owned by the client that pushes this plan. - bool m_stop_others; + lldb::ThreadPlanSP m_func_sp; /// This is the function call plan. We fill it + /// at start, then set it to NULL when this plan + /// is done. That way we know to go on to: + lldb::ThreadPlanSP m_run_to_sp; /// The plan that runs to the target. + FunctionCaller *m_impl_function; /// This is a pointer to a impl function that + /// is owned by the client that pushes this + /// plan. + bool m_stop_others; /// Whether we should stop other threads. +}; + +class AppleThreadPlanStepThroughDirectDispatch: public ThreadPlanStepOut { +public: + AppleThreadPlanStepThroughDirectDispatch( + Thread &thread, AppleObjCTrampolineHandler &handler, + llvm::StringRef dispatch_func_name, bool stop_others, + LazyBool step_in_avoids_code_without_debug_info); + + ~AppleThreadPlanStepThroughDirectDispatch() override; + + void GetDescription(Stream *s, lldb::DescriptionLevel level) override; + + bool ShouldStop(Event *event_ptr) override; + + bool StopOthers() override { return m_stop_others; } + + bool MischiefManaged() override; + + bool DoWillResume(lldb::StateType resume_state, bool current_plan) override; + + void SetFlagsToDefault() override { + GetFlags().Set(ThreadPlanStepInRange::GetDefaultFlagsValue()); + } + +protected: + bool DoPlanExplainsStop(Event *event_ptr) override; + + AppleObjCTrampolineHandler &m_trampoline_handler; + std::string m_dispatch_func_name; /// Which dispatch function we're stepping + /// through. + lldb::ThreadPlanSP m_objc_step_through_sp; /// When we hit an objc_msgSend, + /// we'll use this plan to get to + /// its target. + std::vector<lldb::BreakpointSP> m_msgSend_bkpts; /// Breakpoints on the objc + /// dispatch functions. + bool m_at_msg_send; /// Are we currently handling an msg_send + bool m_stop_others; /// Whether we should stop other threads. + }; } // namespace lldb_private -#endif // lldb_AppleThreadPlanStepThroughObjCTrampoline_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLETHREADPLANSTEPTHROUGHOBJCTRAMPOLINE_H diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index 9eb493f83c84..2ccf9b33f9d8 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -1,4 +1,4 @@ -//===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===// +//===-- ObjCLanguageRuntime.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,11 +9,11 @@ #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" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/Type.h" @@ -41,7 +41,7 @@ ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process) m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(), m_negative_complete_class_cache() {} -bool ObjCLanguageRuntime::IsWhitelistedRuntimeValue(ConstString name) { +bool ObjCLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { static ConstString g_self = ConstString("self"); static ConstString g_cmd = ConstString("_cmd"); return name == g_self || name == g_cmd; @@ -127,9 +127,9 @@ ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) { for (uint32_t i = 0; i < types.GetSize(); ++i) { TypeSP type_sp(types.GetTypeAtIndex(i)); - if (ClangASTContext::IsObjCObjectOrInterfaceType( + if (TypeSystemClang::IsObjCObjectOrInterfaceType( type_sp->GetForwardCompilerType())) { - if (type_sp->IsCompleteObjCClass()) { + if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) { m_complete_class_cache[name] = type_sp; return type_sp; } @@ -387,9 +387,9 @@ ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) { CompilerType class_type; bool is_pointer_type = false; - if (ClangASTContext::IsObjCObjectPointerType(base_type, &class_type)) + if (TypeSystemClang::IsObjCObjectPointerType(base_type, &class_type)) is_pointer_type = true; - else if (ClangASTContext::IsObjCObjectOrInterfaceType(base_type)) + else if (TypeSystemClang::IsObjCObjectOrInterfaceType(base_type)) class_type = base_type; else return llvm::None; @@ -397,7 +397,7 @@ ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) { if (!class_type) return llvm::None; - ConstString class_name(class_type.GetConstTypeName()); + ConstString class_name(class_type.GetTypeName()); if (!class_name) return llvm::None; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h index b9a4d5dae08a..c43acf54bbcd 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ObjCLanguageRuntime_h_ -#define liblldb_ObjCLanguageRuntime_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H #include <functional> #include <map> @@ -17,7 +17,6 @@ #include "llvm/Support/Casting.h" #include "lldb/Breakpoint/BreakpointPrecondition.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/ThreadSafeDenseMap.h" #include "lldb/Symbol/CompilerType.h" @@ -29,6 +28,7 @@ class CommandObjectObjC_ClassTable_Dump; namespace lldb_private { +class TypeSystemClang; class UtilityFunction; class ObjCLanguageRuntime : public LanguageRuntime { @@ -144,12 +144,12 @@ public: public: virtual ~EncodingToType(); - virtual CompilerType RealizeType(ClangASTContext &ast_ctx, const char *name, + virtual CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name, bool for_expression) = 0; virtual CompilerType RealizeType(const char *name, bool for_expression); protected: - std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_up; + std::unique_ptr<TypeSystemClang> m_scratch_ast_ctx_up; }; class ObjCExceptionPrecondition : public BreakpointPrecondition { @@ -186,7 +186,8 @@ public: TaggedPointerVendor() = default; private: - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor); + TaggedPointerVendor(const TaggedPointerVendor &) = delete; + const TaggedPointerVendor &operator=(const TaggedPointerVendor &) = delete; }; ~ObjCLanguageRuntime() override; @@ -299,7 +300,7 @@ public: /// Check whether the name is "self" or "_cmd" and should show up in /// "frame variable". - bool IsWhitelistedRuntimeValue(ConstString name) override; + bool IsAllowedRuntimeValue(ConstString name) override; protected: // Classes that inherit from ObjCLanguageRuntime can see and modify these @@ -417,9 +418,10 @@ protected: void ReadObjCLibraryIfNeeded(const ModuleList &module_list); - DISALLOW_COPY_AND_ASSIGN(ObjCLanguageRuntime); + ObjCLanguageRuntime(const ObjCLanguageRuntime &) = delete; + const ObjCLanguageRuntime &operator=(const ObjCLanguageRuntime &) = delete; }; } // namespace lldb_private -#endif // liblldb_ObjCLanguageRuntime_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp index b396781e6726..6858c7134d33 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp @@ -1,4 +1,4 @@ -//===-- RenderScriptExpressionOpts.cpp --------------------------*- C++ -*-===// +//===-- RenderScriptExpressionOpts.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -86,7 +86,7 @@ bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { llvm::StringRef real_triple = m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); const llvm::Target *target_info = - llvm::TargetRegistry::lookupTarget(real_triple, err); + llvm::TargetRegistry::lookupTarget(std::string(real_triple), err); if (!target_info) { if (log) log->Warning("couldn't determine real target architecture: '%s'", diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h index 3ec4e37b6db0..52da677128e2 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_RENDERSCRIPT_EXPROPTS_H -#define LLDB_RENDERSCRIPT_EXPROPTS_H +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTEXPRESSIONOPTS_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTEXPRESSIONOPTS_H #include "llvm/IR/Module.h" #include "llvm/Support/TargetRegistry.h" diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index 4edb8dec6082..dd9312234d8b 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -1,4 +1,4 @@ -//===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===// +//===-- RenderScriptRuntime.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -46,6 +46,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_renderscript; +LLDB_PLUGIN_DEFINE(RenderScriptRuntime) + #define FMT_COORD "(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")" char RenderScriptRuntime::ID = 0; @@ -791,6 +793,9 @@ RenderScriptRuntime::CreateInstance(Process *process, Searcher::CallbackReturn RSBreakpointResolver::SearchCallback(SearchFilter &filter, SymbolContext &context, Address *) { + BreakpointSP breakpoint_sp = GetBreakpoint(); + assert(breakpoint_sp); + ModuleSP module = context.module_sp; if (!module || !IsRenderScriptScriptModule(module)) @@ -811,7 +816,7 @@ RSBreakpointResolver::SearchCallback(SearchFilter &filter, if (kernel_sym) { Address bp_addr = kernel_sym->GetAddress(); if (filter.AddressPasses(bp_addr)) - m_breakpoint->AddLocation(bp_addr); + breakpoint_sp->AddLocation(bp_addr); } return Searcher::eCallbackReturnContinue; @@ -821,6 +826,9 @@ Searcher::CallbackReturn RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter, lldb_private::SymbolContext &context, Address *) { + BreakpointSP breakpoint_sp = GetBreakpoint(); + assert(breakpoint_sp); + // We need to have access to the list of reductions currently parsed, as // reduce names don't actually exist as symbols in a module. They are only // identifiable by parsing the .rs.info packet, or finding the expand symbol. @@ -867,7 +875,7 @@ RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter, if (!SkipPrologue(module, address)) { LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__); } - m_breakpoint->AddLocation(address, &new_bp); + breakpoint_sp->AddLocation(address, &new_bp); LLDB_LOGF(log, "%s: %s reduction breakpoint on %s in %s", __FUNCTION__, new_bp ? "new" : "existing", kernel_name.GetCString(), @@ -882,7 +890,8 @@ RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter, Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback( SearchFilter &filter, SymbolContext &context, Address *addr) { - if (!m_breakpoint) + BreakpointSP breakpoint_sp = GetBreakpoint(); + if (!breakpoint_sp) return eCallbackReturnContinue; Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); @@ -892,7 +901,8 @@ Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback( return Searcher::eCallbackReturnContinue; std::vector<std::string> names; - m_breakpoint->GetNames(names); + Breakpoint& breakpoint = *breakpoint_sp; + breakpoint.GetNames(names); if (names.empty()) return eCallbackReturnContinue; @@ -932,7 +942,7 @@ Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback( } bool new_bp; - m_breakpoint->AddLocation(address, &new_bp); + breakpoint.AddLocation(address, &new_bp); LLDB_LOGF(log, "%s: Placed %sbreakpoint on %s", __FUNCTION__, new_bp ? "new " : "", k.m_name.AsCString()); @@ -1029,8 +1039,8 @@ bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) { } lldb::BreakpointResolverSP -RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bp, bool catch_bp, - bool throw_bp) { +RenderScriptRuntime::CreateExceptionResolver(const lldb::BreakpointSP &bp, + bool catch_bp, bool throw_bp) { BreakpointResolverSP resolver_sp; return resolver_sp; } @@ -1513,7 +1523,7 @@ void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook, script->type = ScriptDetails::eScriptC; script->cache_dir = cache_dir; script->res_name = res_name; - script->shared_lib = strm.GetString(); + script->shared_lib = std::string(strm.GetString()); script->context = addr_t(args[eRsContext]); } @@ -3129,7 +3139,7 @@ void RenderScriptRuntime::DumpKernels(Stream &strm) const { strm.Printf("Resource '%s':", module->m_resname.c_str()); strm.EOL(); for (const auto &kernel : module->m_kernels) { - strm.Indent(kernel.m_name.AsCString()); + strm.Indent(kernel.m_name.GetStringRef()); strm.EOL(); } } @@ -3939,9 +3949,10 @@ void RSModuleDescriptor::Dump(Stream &strm) const { } void RSGlobalDescriptor::Dump(Stream &strm) const { - strm.Indent(m_name.AsCString()); + strm.Indent(m_name.GetStringRef()); VariableList var_list; - m_module->m_module->FindGlobalVariables(m_name, nullptr, 1U, var_list); + m_module->m_module->FindGlobalVariables(m_name, CompilerDeclContext(), 1U, + var_list); if (var_list.GetSize() == 1) { auto var = var_list.GetVariableAtIndex(0); auto type = var->GetType(); @@ -3964,12 +3975,12 @@ void RSGlobalDescriptor::Dump(Stream &strm) const { } void RSKernelDescriptor::Dump(Stream &strm) const { - strm.Indent(m_name.AsCString()); + strm.Indent(m_name.GetStringRef()); strm.EOL(); } void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const { - stream.Indent(m_reduce_name.AsCString()); + stream.Indent(m_reduce_name.GetStringRef()); stream.IndentMore(); stream.EOL(); stream.Indent(); diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h index c3740ba55a11..5e3726548369 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RenderScriptRuntime_h_ -#define liblldb_RenderScriptRuntime_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTRUNTIME_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTRUNTIME_H #include <array> #include <map> @@ -24,6 +24,10 @@ #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +namespace clang { +class TargetOptions; +} + namespace lldb_private { namespace lldb_renderscript { @@ -54,7 +58,7 @@ struct RSCoordinate { // for .expand kernels as a fallback. class RSBreakpointResolver : public BreakpointResolver { public: - RSBreakpointResolver(Breakpoint *bp, ConstString name) + RSBreakpointResolver(const lldb::BreakpointSP &bp, ConstString name) : BreakpointResolver(bp, BreakpointResolver::NameResolver), m_kernel_name(name) {} @@ -73,9 +77,9 @@ public: lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } lldb::BreakpointResolverSP - CopyForBreakpoint(Breakpoint &breakpoint) override { + CopyForBreakpoint(lldb::BreakpointSP &breakpoint) override { lldb::BreakpointResolverSP ret_sp( - new RSBreakpointResolver(&breakpoint, m_kernel_name)); + new RSBreakpointResolver(breakpoint, m_kernel_name)); return ret_sp; } @@ -96,7 +100,7 @@ public: }; RSReduceBreakpointResolver( - Breakpoint *breakpoint, ConstString reduce_name, + const lldb::BreakpointSP &breakpoint, ConstString reduce_name, std::vector<lldb_renderscript::RSModuleDescriptorSP> *rs_modules, int kernel_types = eKernelTypeAll) : BreakpointResolver(breakpoint, BreakpointResolver::NameResolver), @@ -123,9 +127,9 @@ public: lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } lldb::BreakpointResolverSP - CopyForBreakpoint(Breakpoint &breakpoint) override { + CopyForBreakpoint(lldb::BreakpointSP &breakpoint) override { lldb::BreakpointResolverSP ret_sp(new RSReduceBreakpointResolver( - &breakpoint, m_reduce_name, m_rsmodules, m_kernel_types)); + breakpoint, m_reduce_name, m_rsmodules, m_kernel_types)); return ret_sp; } @@ -246,7 +250,8 @@ typedef std::vector<RSScriptGroupDescriptorSP> RSScriptGroupList; class RSScriptGroupBreakpointResolver : public BreakpointResolver { public: - RSScriptGroupBreakpointResolver(Breakpoint *bp, ConstString name, + RSScriptGroupBreakpointResolver(const lldb::BreakpointSP &bp, + ConstString name, const RSScriptGroupList &groups, bool stop_on_all) : BreakpointResolver(bp, BreakpointResolver::NameResolver), @@ -268,9 +273,9 @@ public: lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } lldb::BreakpointResolverSP - CopyForBreakpoint(Breakpoint &breakpoint) override { + CopyForBreakpoint(lldb::BreakpointSP &breakpoint) override { lldb::BreakpointResolverSP ret_sp(new RSScriptGroupBreakpointResolver( - &breakpoint, m_group_name, m_script_groups, m_stop_on_all)); + breakpoint, m_group_name, m_script_groups, m_stop_on_all)); return ret_sp; } @@ -343,9 +348,9 @@ public: bool CouldHaveDynamicValue(ValueObject &in_value) override; - lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bp, - bool catch_bp, - bool throw_bp) override; + lldb::BreakpointResolverSP + CreateExceptionResolver(const lldb::BreakpointSP &bp, + bool catch_bp, bool throw_bp) override; bool LoadModule(const lldb::ModuleSP &module_sp); @@ -402,6 +407,8 @@ public: return false; } + bool GetOverrideExprOptions(clang::TargetOptions &prototype); + // PluginInterface protocol lldb_private::ConstString GetPluginName() override; @@ -421,7 +428,8 @@ protected: void InitSearchFilter(lldb::TargetSP target) { if (!m_filtersp) - m_filtersp.reset(new SearchFilterForUnconstrainedSearches(target)); + m_filtersp = + std::make_shared<SearchFilterForUnconstrainedSearches>(target); } void FixupScriptDetails(lldb_renderscript::RSModuleDescriptorSP rsmodule_sp); @@ -577,11 +585,9 @@ private: // any previous stored allocation which has the same address. AllocationDetails *CreateAllocation(lldb::addr_t address); - bool GetOverrideExprOptions(clang::TargetOptions &prototype) override; - bool GetIRPasses(LLVMUserExpression::IRPasses &passes) override; }; } // namespace lldb_private -#endif // liblldb_RenderScriptRuntime_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTRUNTIME_H diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp index 45d0d028d047..b6f8b20c90c3 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp @@ -1,4 +1,4 @@ -//===-- RenderScriptScriptGroup.cpp -----------------------------*- C++ -*-===// +//===-- RenderScriptScriptGroup.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h index c25e240f6d52..03d3a7823a98 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RenderScriptScriptGroup_h_ -#define liblldb_RenderScriptScriptGroup_h_ +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTSCRIPTGROUP_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTSCRIPTGROUP_H #include "lldb/Interpreter/CommandInterpreter.h" lldb::CommandObjectSP NewCommandObjectRenderScriptScriptGroup( lldb_private::CommandInterpreter &interpreter); -#endif // liblldb_RenderScriptScriptGroup_h_ +#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTSCRIPTGROUP_H diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp index 4ddff3ad9c4c..f51190e0c82c 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp @@ -1,4 +1,4 @@ -//===-- RenderScriptx86ABIFixups.cpp ----------------------------*- C++ -*-===// +//===-- RenderScriptx86ABIFixups.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,7 +10,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/IR/BasicBlock.h" -#include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" @@ -158,12 +157,11 @@ bool fixupX86StructRetCalls(llvm::Module &module) { assert(new_func_type && "failed to clone functionType for Renderscript ABI fixup"); - llvm::CallSite call_site(call_inst); llvm::Function *func = call_inst->getCalledFunction(); assert(func && "cannot resolve function in RenderScriptRuntime"); // Copy the original call arguments - std::vector<llvm::Value *> new_call_args(call_site.arg_begin(), - call_site.arg_end()); + std::vector<llvm::Value *> new_call_args(call_inst->arg_begin(), + call_inst->arg_end()); // Allocate enough space to store the return value of the original function // we pass a pointer to this allocation as the StructRet param, and then @@ -189,15 +187,17 @@ bool fixupX86StructRetCalls(llvm::Module &module) { ->setName("new_func_ptr_load_cast"); // load the new function address ready for a jump llvm::LoadInst *new_func_addr_load = - new llvm::LoadInst(new_func_ptr, "load_func_pointer", call_inst); + new llvm::LoadInst(new_func_ptr->getType()->getPointerElementType(), + new_func_ptr, "load_func_pointer", call_inst); // and create a callinstruction from it llvm::CallInst *new_call_inst = llvm::CallInst::Create(new_func_type, new_func_addr_load, new_call_args, "new_func_call", call_inst); new_call_inst->setCallingConv(call_inst->getCallingConv()); new_call_inst->setTailCall(call_inst->isTailCall()); - llvm::LoadInst *lldb_save_result_address = - new llvm::LoadInst(return_value_alloc, "save_return_val", call_inst); + llvm::LoadInst *lldb_save_result_address = new llvm::LoadInst( + return_value_alloc->getType()->getPointerElementType(), + return_value_alloc, "save_return_val", call_inst); // Now remove the old broken call call_inst->replaceAllUsesWith(lldb_save_result_address); diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h index a5efc999aea4..7836fff4a3a9 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_RENDERSCRIPT_X86_H -#define LLDB_RENDERSCRIPT_X86_H +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTX86ABIFIXUPS_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTX86ABIFIXUPS_H #include "llvm/IR/Module.h" diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index e0d2c5d0eef8..333113a0b17a 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -1,4 +1,4 @@ -//===-- MemoryHistoryASan.cpp -----------------------------------*- C++ -*-===// +//===-- MemoryHistoryASan.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -28,6 +28,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(MemoryHistoryASan) + MemoryHistorySP MemoryHistoryASan::CreateInstance(const ProcessSP &process_sp) { if (!process_sp.get()) return nullptr; @@ -136,7 +138,12 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, pcs.push_back(pc); } - HistoryThread *history_thread = new HistoryThread(*process_sp, tid, pcs); + // The ASAN runtime already massages the return addresses into call + // addresses, we don't want LLDB's unwinder to try to locate the previous + // instruction again as this might lead to us reporting a different line. + bool pcs_are_call_addresses = true; + HistoryThread *history_thread = + new HistoryThread(*process_sp, tid, pcs, pcs_are_call_addresses); ThreadSP new_thread_sp(history_thread); std::ostringstream thread_name_with_number; thread_name_with_number << thread_name << " Thread " << tid; diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h index 266576b0cd96..e9fe37d344a4 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_MemoryHistoryASan_h_ -#define liblldb_MemoryHistoryASan_h_ +#ifndef LLDB_SOURCE_PLUGINS_MEMORYHISTORY_ASAN_MEMORYHISTORYASAN_H +#define LLDB_SOURCE_PLUGINS_MEMORYHISTORY_ASAN_MEMORYHISTORYASAN_H #include "lldb/Target/ABI.h" #include "lldb/Target/MemoryHistory.h" @@ -45,4 +45,4 @@ private: } // namespace lldb_private -#endif // liblldb_MemoryHistoryASan_h_ +#endif // LLDB_SOURCE_PLUGINS_MEMORYHISTORY_ASAN_MEMORYHISTORYASAN_H diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 512b5bebf07f..83cf9f8bd269 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -1,4 +1,4 @@ -//===-- ObjectContainerBSDArchive.cpp ---------------------------*- C++ -*-===// +//===-- ObjectContainerBSDArchive.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -40,6 +40,8 @@ typedef struct ar_hdr { using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ObjectContainerBSDArchive) + ObjectContainerBSDArchive::Object::Object() : ar_name(), modification_time(0), uid(0), gid(0), mode(0), size(0), file_offset(0), file_size(0) {} @@ -86,7 +88,7 @@ ObjectContainerBSDArchive::Object::Extract(const DataExtractor &data, return LLDB_INVALID_OFFSET; str.assign((const char *)data.GetData(&offset, 16), 16); - if (str.find("#1/") == 0) { + 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. diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h index 5d9c01315a66..f6862afff8a0 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ObjectContainerBSDArchive_h_ -#define liblldb_ObjectContainerBSDArchive_h_ +#ifndef LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BSD_ARCHIVE_OBJECTCONTAINERBSDARCHIVE_H +#define LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BSD_ARCHIVE_OBJECTCONTAINERBSDARCHIVE_H #include "lldb/Core/UniqueCStringMap.h" #include "lldb/Symbol/ObjectContainer.h" @@ -174,4 +174,4 @@ protected: Archive::shared_ptr m_archive_sp; }; -#endif // liblldb_ObjectContainerBSDArchive_h_ +#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BSD_ARCHIVE_OBJECTCONTAINERBSDARCHIVE_H diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp index b83b2efb492f..bd8eeedce57d 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp +++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp @@ -1,4 +1,4 @@ -//===-- BreakpadRecords.cpp ----------------------------------- -*- C++ -*-===// +//===-- BreakpadRecords.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -205,7 +205,7 @@ llvm::Optional<InfoRecord> InfoRecord::parse(llvm::StringRef Line) { // use this as the UUID. Otherwise, we should revert back to the module ID. UUID ID; if (Line.trim().empty()) { - if (Str.empty() || ID.SetFromStringRef(Str, Str.size() / 2) != Str.size()) + if (Str.empty() || !ID.SetFromStringRef(Str)) return llvm::None; } return InfoRecord(std::move(ID)); diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h index 27bef975125d..1620a1210b84 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h +++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H -#define LLDB_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H #include "lldb/Utility/UUID.h" #include "lldb/lldb-types.h" @@ -183,4 +183,4 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StackWinRecord &R); } // namespace breakpad } // namespace lldb_private -#endif // LLDB_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp index 3b9e0e2092a9..7a9163ddb880 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp +++ b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp @@ -1,4 +1,4 @@ -//===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===// +//===-- ObjectFileBreakpad.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -16,6 +16,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::breakpad; +LLDB_PLUGIN_DEFINE(ObjectFileBreakpad) + namespace { struct Header { ArchSpec arch; diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h index cb4bba01fb71..8724feaa422d 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h +++ b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H -#define LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" @@ -103,4 +103,4 @@ private: } // namespace breakpad } // namespace lldb_private -#endif // LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index aa9871071b0e..f0496beba2ef 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -1,4 +1,4 @@ -//===-- ELFHeader.cpp ----------------------------------------- -*- C++ -*-===// +//===-- ELFHeader.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h index bb228e269d40..963cc850736f 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -17,8 +17,8 @@ /// reading both 32 and 64 bit instances of the object. //===----------------------------------------------------------------------===// -#ifndef liblldb_ELFHeader_h_ -#define liblldb_ELFHeader_h_ +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_ELFHEADER_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_ELFHEADER_H #include "llvm/BinaryFormat/ELF.h" @@ -391,4 +391,4 @@ struct ELFRela { } // End namespace elf. -#endif // #ifndef liblldb_ELFHeader_h_ +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_ELFHEADER_H diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 8b62afa18cd6..bca575b7f884 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1,4 +1,4 @@ -//===-- ObjectFileELF.cpp ------------------------------------- -*- C++ -*-===// +//===-- ObjectFileELF.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -51,6 +51,8 @@ using namespace lldb_private; using namespace elf; using namespace llvm::ELF; +LLDB_PLUGIN_DEFINE(ObjectFileELF) + namespace { // ELF note owner definitions @@ -206,7 +208,9 @@ unsigned ELFRelocation::RelocAddend64(const ELFRelocation &rel) { } // end anonymous namespace -static user_id_t SegmentID(size_t PHdrIndex) { return ~PHdrIndex; } +static user_id_t SegmentID(size_t PHdrIndex) { + return ~user_id_t(PHdrIndex); +} bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { // Read all fields. @@ -537,7 +541,8 @@ size_t ObjectFileELF::GetModuleSpecifications( __FUNCTION__, file.GetPath().c_str()); } - data_sp = MapFileData(file, -1, file_offset); + if (data_sp->GetByteSize() < length) + data_sp = MapFileData(file, -1, file_offset); if (data_sp) data.SetData(data_sp); // In case there is header extension in the section #0, the header we @@ -576,8 +581,7 @@ size_t ObjectFileELF::GetModuleSpecifications( func_cat, "Calculating module crc32 %s with size %" PRIu64 " KiB", file.GetLastPathComponent().AsCString(), - (FileSystem::Instance().GetByteSize(file) - file_offset) / - 1024); + (length - file_offset) / 1024); // For core files - which usually don't happen to have a // gnu_debuglink, and are pretty bulky - calculating whole @@ -899,7 +903,7 @@ size_t ObjectFileELF::ParseDependentModules() { if (m_filespec_up) return m_filespec_up->GetSize(); - m_filespec_up.reset(new FileSpecList()); + m_filespec_up = std::make_unique<FileSpecList>(); if (!ParseSectionHeaders()) return 0; @@ -1235,7 +1239,7 @@ void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length, lldb::offset_t Offset = 0; uint8_t FormatVersion = data.GetU8(&Offset); - if (FormatVersion != llvm::ARMBuildAttrs::Format_Version) + if (FormatVersion != llvm::ELFAttrs::Format_Version) return; Offset = Offset + sizeof(uint32_t); // Section Length @@ -1588,6 +1592,7 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) { .Case("str.dwo", eSectionTypeDWARFDebugStrDwo) .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets) .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) + .Case("tu_index", eSectionTypeDWARFDebugTuIndex) .Case("types", eSectionTypeDWARFDebugTypes) .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo) .Default(eSectionTypeOther); @@ -1696,7 +1701,7 @@ class VMAddressProvider { public: VMAddressProvider(ObjectFile::Type Type, llvm::StringRef SegmentName) - : ObjectType(Type), SegmentName(SegmentName) {} + : ObjectType(Type), SegmentName(std::string(SegmentName)) {} std::string GetNextSegmentName() const { return llvm::formatv("{0}[{1}]", SegmentName, SegmentCount).str(); @@ -2230,8 +2235,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, if (!mangled_name.empty()) mangled.SetMangledName(ConstString((mangled_name + suffix).str())); - ConstString demangled = - mangled.GetDemangledName(lldb::eLanguageTypeUnknown); + ConstString demangled = mangled.GetDemangledName(); llvm::StringRef demangled_name = demangled.GetStringRef(); if (!demangled_name.empty()) mangled.SetDemangledName(ConstString((demangled_name + suffix).str())); @@ -2713,7 +2717,7 @@ Symtab *ObjectFileELF::GetSymtab() { Section *symtab = section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get(); if (symtab) { - m_symtab_up.reset(new Symtab(symtab->GetObjectFile())); + m_symtab_up = std::make_unique<Symtab>(symtab->GetObjectFile()); symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, symtab); } @@ -2730,7 +2734,7 @@ Symtab *ObjectFileELF::GetSymtab() { .get(); if (dynsym) { if (!m_symtab_up) - m_symtab_up.reset(new Symtab(dynsym->GetObjectFile())); + m_symtab_up = std::make_unique<Symtab>(dynsym->GetObjectFile()); symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, dynsym); } } @@ -2757,7 +2761,8 @@ Symtab *ObjectFileELF::GetSymtab() { assert(reloc_header); if (m_symtab_up == nullptr) - m_symtab_up.reset(new Symtab(reloc_section->GetObjectFile())); + m_symtab_up = + std::make_unique<Symtab>(reloc_section->GetObjectFile()); ParseTrampolineSymbols(m_symtab_up.get(), symbol_id, reloc_header, reloc_id); @@ -2767,17 +2772,17 @@ Symtab *ObjectFileELF::GetSymtab() { if (DWARFCallFrameInfo *eh_frame = GetModule()->GetUnwindTable().GetEHFrameInfo()) { if (m_symtab_up == nullptr) - m_symtab_up.reset(new Symtab(this)); + m_symtab_up = std::make_unique<Symtab>(this); ParseUnwindSymbols(m_symtab_up.get(), eh_frame); } // If we still don't have any symtab then create an empty instance to avoid // do the section lookup next time. if (m_symtab_up == nullptr) - m_symtab_up.reset(new Symtab(this)); + m_symtab_up = std::make_unique<Symtab>(this); // In the event that there's no symbol entry for the entry point we'll - // artifically create one. We delegate to the symtab object the figuring + // artificially create one. We delegate to the symtab object the figuring // out of the proper size, this will usually make it span til the next // symbol it finds in the section. This means that if there are missing // symbols the entry point might span beyond its function definition. @@ -2874,7 +2879,7 @@ void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, return; // First we save the new symbols into a separate list and add them to the - // symbol table after we colleced all symbols we want to add. This is + // symbol table after we collected all symbols we want to add. This is // neccessary because adding a new symbol invalidates the internal index of // the symtab what causing the next lookup to be slow because it have to // recalculate the index first. @@ -2953,7 +2958,8 @@ void ObjectFileELF::Dump(Stream *s) { s->EOL(); SectionList *section_list = GetSectionList(); if (section_list) - section_list->Dump(s, nullptr, true, UINT32_MAX); + section_list->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, + UINT32_MAX); Symtab *symtab = GetSymtab(); if (symtab) symtab->Dump(s, nullptr, eSortOrderNone); diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 3b273896cb59..062271f1caf0 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ObjectFileELF_h_ -#define liblldb_ObjectFileELF_h_ +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H #include <stdint.h> @@ -328,9 +328,6 @@ private: /// section index 0 is never valid). lldb::user_id_t GetSectionIndexByName(const char *name); - // Returns the ID of the first section that has the given type. - lldb::user_id_t GetSectionIndexByType(unsigned type); - /// Returns the section header with the given id or NULL. const ELFSectionHeaderInfo *GetSectionHeaderByIndex(lldb::user_id_t id); @@ -397,4 +394,4 @@ private: std::shared_ptr<ObjectFileELF> GetGnuDebugDataObjectFile(); }; -#endif // liblldb_ObjectFileELF_h_ +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index c55b96d9110b..93c2c9f945fe 100644 --- a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -1,4 +1,4 @@ -//===-- ObjectFileJIT.cpp ---------------------------------------*- C++ -*-===// +//===-- ObjectFileJIT.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -39,6 +39,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ObjectFileJIT) + char ObjectFileJIT::ID; void ObjectFileJIT::Initialize() { @@ -118,7 +120,7 @@ Symtab *ObjectFileJIT::GetSymtab() { if (module_sp) { std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); if (m_symtab_up == nullptr) { - m_symtab_up.reset(new Symtab(this)); + m_symtab_up = std::make_unique<Symtab>(this); std::lock_guard<std::recursive_mutex> symtab_guard( m_symtab_up->GetMutex()); ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); @@ -137,7 +139,7 @@ bool ObjectFileJIT::IsStripped() { void ObjectFileJIT::CreateSections(SectionList &unified_section_list) { if (!m_sections_up) { - m_sections_up.reset(new SectionList()); + m_sections_up = std::make_unique<SectionList>(); ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); if (delegate_sp) { delegate_sp->PopulateSectionList(this, *m_sections_up); @@ -161,7 +163,8 @@ void ObjectFileJIT::Dump(Stream *s) { SectionList *sections = GetSectionList(); if (sections) - sections->Dump(s, nullptr, true, UINT32_MAX); + sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, + UINT32_MAX); if (m_symtab_up) m_symtab_up->Dump(s, nullptr, eSortOrderNone); diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h index c992683cfc3c..a3a1acea916a 100644 --- a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ObjectFileJIT_h_ -#define liblldb_ObjectFileJIT_h_ +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_JIT_OBJECTFILEJIT_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_JIT_OBJECTFILEJIT_H #include "lldb/Core/Address.h" #include "lldb/Symbol/ObjectFile.h" @@ -104,4 +104,4 @@ protected: lldb::ObjectFileJITDelegateWP m_delegate_wp; }; -#endif // liblldb_ObjectFileJIT_h_ +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_JIT_OBJECTFILEJIT_H diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp new file mode 100644 index 000000000000..91150fa02ebc --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -0,0 +1,466 @@ +//===-- ObjectFileWasm.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 "ObjectFileWasm.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Format.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::wasm; + +LLDB_PLUGIN_DEFINE(ObjectFileWasm) + +static const uint32_t kWasmHeaderSize = + sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion); + +/// Checks whether the data buffer starts with a valid Wasm module header. +static bool ValidateModuleHeader(const DataBufferSP &data_sp) { + if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize) + return false; + + if (llvm::identify_magic(toStringRef(data_sp->GetData())) != + llvm::file_magic::wasm_object) + return false; + + uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic); + + uint32_t version = llvm::support::endian::read32le(Ptr); + return version == llvm::wasm::WasmVersion; +} + +static llvm::Optional<ConstString> +GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) { + // A Wasm string is encoded as a vector of UTF-8 codes. + // Vectors are encoded with their u32 length followed by the element + // sequence. + uint64_t len = data.getULEB128(c); + if (!c) { + consumeError(c.takeError()); + return llvm::None; + } + + if (len >= (uint64_t(1) << 32)) { + return llvm::None; + } + + llvm::SmallVector<uint8_t, 32> str_storage; + data.getU8(c, str_storage, len); + if (!c) { + consumeError(c.takeError()); + return llvm::None; + } + + llvm::StringRef str = toStringRef(makeArrayRef(str_storage)); + return ConstString(str); +} + +char ObjectFileWasm::ID; + +void ObjectFileWasm::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileWasm::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString ObjectFileWasm::GetPluginNameStatic() { + static ConstString g_name("wasm"); + return g_name; +} + +ObjectFile * +ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t file_offset, offset_t length) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) { + LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s", + file->GetPath().c_str()); + return nullptr; + } + data_offset = 0; + } + + assert(data_sp); + if (!ValidateModuleHeader(data_sp)) { + LLDB_LOGF(log, + "Failed to create ObjectFileWasm instance: invalid Wasm header"); + return nullptr; + } + + // Update the data to contain the entire file if it doesn't contain it + // already. + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) { + LLDB_LOGF(log, + "Failed to create ObjectFileWasm instance: cannot read file %s", + file->GetPath().c_str()); + return nullptr; + } + data_offset = 0; + } + + std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm( + module_sp, data_sp, data_offset, file, file_offset, length)); + ArchSpec spec = objfile_up->GetArchitecture(); + if (spec && objfile_up->SetModulesArchitecture(spec)) { + LLDB_LOGF(log, + "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s", + static_cast<void *>(objfile_up.get()), + static_cast<void *>(objfile_up->GetModule().get()), + objfile_up->GetModule()->GetSpecificationDescription().c_str(), + file ? file->GetPath().c_str() : "<NULL>"); + return objfile_up.release(); + } + + LLDB_LOGF(log, "Failed to create ObjectFileWasm instance"); + return nullptr; +} + +ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp, + DataBufferSP &data_sp, + const ProcessSP &process_sp, + addr_t header_addr) { + if (!ValidateModuleHeader(data_sp)) + return nullptr; + + std::unique_ptr<ObjectFileWasm> objfile_up( + new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr)); + ArchSpec spec = objfile_up->GetArchitecture(); + if (spec && objfile_up->SetModulesArchitecture(spec)) + return objfile_up.release(); + return nullptr; +} + +bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) { + // Buffer sufficient to read a section header and find the pointer to the next + // section. + const uint32_t kBufferSize = 1024; + DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize); + + llvm::DataExtractor data = section_header_data.GetAsLLVM(); + llvm::DataExtractor::Cursor c(0); + + // Each section consists of: + // - a one-byte section id, + // - the u32 size of the contents, in bytes, + // - the actual contents. + uint8_t section_id = data.getU8(c); + uint64_t payload_len = data.getULEB128(c); + if (!c) + return !llvm::errorToBool(c.takeError()); + + if (payload_len >= (uint64_t(1) << 32)) + return false; + + if (section_id == llvm::wasm::WASM_SEC_CUSTOM) { + // Custom sections have the id 0. Their contents consist of a name + // identifying the custom section, followed by an uninterpreted sequence + // of bytes. + lldb::offset_t prev_offset = c.tell(); + llvm::Optional<ConstString> sect_name = GetWasmString(data, c); + if (!sect_name) + return false; + + if (payload_len < c.tell() - prev_offset) + return false; + + uint32_t section_length = payload_len - (c.tell() - prev_offset); + m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length, + section_id, *sect_name}); + *offset_ptr += (c.tell() + section_length); + } else if (section_id <= llvm::wasm::WASM_SEC_EVENT) { + m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), + static_cast<uint32_t>(payload_len), + section_id, ConstString()}); + *offset_ptr += (c.tell() + payload_len); + } else { + // Invalid section id. + return false; + } + return true; +} + +bool ObjectFileWasm::DecodeSections() { + lldb::offset_t offset = kWasmHeaderSize; + if (IsInMemory()) { + offset += m_memory_addr; + } + + while (DecodeNextSection(&offset)) + ; + return true; +} + +size_t ObjectFileWasm::GetModuleSpecifications( + const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, + offset_t file_offset, offset_t length, ModuleSpecList &specs) { + if (!ValidateModuleHeader(data_sp)) { + return 0; + } + + ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm")); + specs.Append(spec); + return 1; +} + +ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t offset, offset_t length) + : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), + m_arch("wasm32-unknown-unknown-wasm") { + m_data.SetAddressByteSize(4); +} + +ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &header_data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_arch("wasm32-unknown-unknown-wasm") {} + +bool ObjectFileWasm::ParseHeader() { + // We already parsed the header during initialization. + return true; +} + +Symtab *ObjectFileWasm::GetSymtab() { return nullptr; } + +void ObjectFileWasm::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + + m_sections_up = std::make_unique<SectionList>(); + + if (m_sect_infos.empty()) { + DecodeSections(); + } + + for (const section_info §_info : m_sect_infos) { + SectionType section_type = eSectionTypeOther; + ConstString section_name; + offset_t file_offset = sect_info.offset & 0xffffffff; + addr_t vm_addr = file_offset; + size_t vm_size = sect_info.size; + + if (llvm::wasm::WASM_SEC_CODE == sect_info.id) { + section_type = eSectionTypeCode; + section_name = ConstString("code"); + + // A code address in DWARF for WebAssembly is the offset of an + // instruction relative within the Code section of the WebAssembly file. + // For this reason Section::GetFileAddress() must return zero for the + // Code section. + vm_addr = 0; + } else { + section_type = + llvm::StringSwitch<SectionType>(sect_info.name.GetStringRef()) + .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) + .Case(".debug_addr", eSectionTypeDWARFDebugAddr) + .Case(".debug_aranges", eSectionTypeDWARFDebugAranges) + .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex) + .Case(".debug_frame", eSectionTypeDWARFDebugFrame) + .Case(".debug_info", eSectionTypeDWARFDebugInfo) + .Case(".debug_line", eSectionTypeDWARFDebugLine) + .Case(".debug_line_str", eSectionTypeDWARFDebugLineStr) + .Case(".debug_loc", eSectionTypeDWARFDebugLoc) + .Case(".debug_loclists", eSectionTypeDWARFDebugLocLists) + .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo) + .Case(".debug_macro", eSectionTypeDWARFDebugMacro) + .Case(".debug_names", eSectionTypeDWARFDebugNames) + .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames) + .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes) + .Case(".debug_ranges", eSectionTypeDWARFDebugRanges) + .Case(".debug_rnglists", eSectionTypeDWARFDebugRngLists) + .Case(".debug_str", eSectionTypeDWARFDebugStr) + .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets) + .Case(".debug_types", eSectionTypeDWARFDebugTypes) + .Default(eSectionTypeOther); + if (section_type == eSectionTypeOther) + continue; + section_name = sect_info.name; + if (!IsInMemory()) { + vm_size = 0; + vm_addr = 0; + } + } + + SectionSP section_sp( + new Section(GetModule(), // Module to which this section belongs. + this, // ObjectFile to which this section belongs and + // should read section data from. + section_type, // Section ID. + section_name, // Section name. + section_type, // Section type. + vm_addr, // VM address. + vm_size, // VM size in bytes of this section. + file_offset, // Offset of this section in the file. + sect_info.size, // Size of the section as found in the file. + 0, // Alignment of the section + 0, // Flags for this section. + 1)); // Number of host bytes per target byte + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } +} + +bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address, + bool value_is_offset) { + /// In WebAssembly, linear memory is disjointed from code space. The VM can + /// load multiple instances of a module, which logically share the same code. + /// We represent a wasm32 code address with 64-bits, like: + /// 63 32 31 0 + /// +---------------+---------------+ + /// + module_id | offset | + /// +---------------+---------------+ + /// where the lower 32 bits represent a module offset (relative to the module + /// start not to the beginning of the code section) and the higher 32 bits + /// uniquely identify the module in the WebAssembly VM. + /// In other words, we assume that each WebAssembly module is loaded by the + /// engine at a 64-bit address that starts at the boundary of 4GB pages, like + /// 0x0000000400000000 for module_id == 4. + /// These 64-bit addresses will be used to request code ranges for a specific + /// module from the WebAssembly engine. + + assert(m_memory_addr == LLDB_INVALID_ADDRESS || + m_memory_addr == load_address); + + ModuleSP module_sp = GetModule(); + if (!module_sp) + return false; + + DecodeSections(); + + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (!section_list) + return false; + + const size_t num_sections = section_list->GetSize(); + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (target.SetSectionLoadAddress( + section_sp, load_address | section_sp->GetFileOffset())) { + ++num_loaded_sections; + } + } + + return num_loaded_sections > 0; +} + +DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) { + DataExtractor data; + if (m_file) { + if (offset < GetByteSize()) { + size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset); + auto buffer_sp = MapFileData(m_file, size, offset); + return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()); + } + } else { + ProcessSP process_sp(m_process_wp.lock()); + if (process_sp) { + auto data_up = std::make_unique<DataBufferHeap>(size, 0); + Status readmem_error; + size_t bytes_read = process_sp->ReadMemory( + offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error); + if (bytes_read > 0) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + } + + data.SetByteOrder(GetByteOrder()); + return data; +} + +llvm::Optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() { + static ConstString g_sect_name_external_debug_info("external_debug_info"); + + for (const section_info §_info : m_sect_infos) { + if (g_sect_name_external_debug_info == sect_info.name) { + const uint32_t kBufferSize = 1024; + DataExtractor section_header_data = + ReadImageData(sect_info.offset, kBufferSize); + llvm::DataExtractor data = section_header_data.GetAsLLVM(); + llvm::DataExtractor::Cursor c(0); + llvm::Optional<ConstString> symbols_url = GetWasmString(data, c); + if (symbols_url) + return FileSpec(symbols_url->GetStringRef()); + } + } + return llvm::None; +} + +void ObjectFileWasm::Dump(Stream *s) { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return; + + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + + llvm::raw_ostream &ostream = s->AsRawOstream(); + ostream << static_cast<void *>(this) << ": "; + s->Indent(); + ostream << "ObjectFileWasm, file = '"; + m_file.Dump(ostream); + ostream << "', arch = "; + ostream << GetArchitecture().GetArchitectureName() << "\n"; + + SectionList *sections = GetSectionList(); + if (sections) { + sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, + UINT32_MAX); + } + ostream << "\n"; + DumpSectionHeaders(ostream); + ostream << "\n"; +} + +void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream, + const section_info_t &sh) { + ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " " + << llvm::format_hex(sh.offset, 10) << " " + << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6) + << "\n"; +} + +void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) { + ostream << "Section Headers\n"; + ostream << "IDX name addr size id\n"; + ostream << "==== ---------------- ---------- ---------- ------\n"; + + uint32_t idx = 0; + for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end(); + ++pos, ++idx) { + ostream << "[" << llvm::format_decimal(idx, 2) << "] "; + ObjectFileWasm::DumpSectionHeader(ostream, *pos); + } +} diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h new file mode 100644 index 000000000000..b6e906a7b15f --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h @@ -0,0 +1,151 @@ +//===-- ObjectFileWasm.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" + +namespace lldb_private { +namespace wasm { + +/// Generic Wasm object file reader. +/// +/// This class provides a generic wasm32 reader plugin implementing the +/// ObjectFile protocol. +class ObjectFileWasm : public ObjectFile { +public: + static void Initialize(); + static void Terminate(); + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic() { + return "WebAssembly object file reader."; + } + + static ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + ModuleSpecList &specs); + + /// PluginInterface protocol. + /// \{ + ConstString GetPluginName() override { return GetPluginNameStatic(); } + uint32_t GetPluginVersion() override { return 1; } + /// \} + + /// LLVM RTTI support + /// \{ + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + /// \} + + /// ObjectFile Protocol. + /// \{ + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override { + return m_arch.GetByteOrder(); + } + + bool IsExecutable() const override { return false; } + + uint32_t GetAddressByteSize() const override { + return m_arch.GetAddressByteSize(); + } + + AddressClass GetAddressClass(lldb::addr_t file_addr) override { + return AddressClass::eInvalid; + } + + Symtab *GetSymtab() override; + + bool IsStripped() override { return !!GetExternalDebugInfoFileSpec(); } + + void CreateSections(SectionList &unified_section_list) override; + + void Dump(Stream *s) override; + + ArchSpec GetArchitecture() override { return m_arch; } + + UUID GetUUID() override { return m_uuid; } + + uint32_t GetDependentModules(FileSpecList &files) override { return 0; } + + Type CalculateType() override { return eTypeSharedLibrary; } + + Strata CalculateStrata() override { return eStrataUser; } + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + lldb_private::Address GetBaseAddress() override { + return IsInMemory() ? Address(m_memory_addr) : Address(0); + } + /// \} + + /// A Wasm module that has external DWARF debug information should contain a + /// custom section named "external_debug_info", whose payload is an UTF-8 + /// encoded string that points to a Wasm module that contains the debug + /// information for this module. + llvm::Optional<FileSpec> GetExternalDebugInfoFileSpec(); + +private: + ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + ObjectFileWasm(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + /// Wasm section decoding routines. + /// \{ + bool DecodeNextSection(lldb::offset_t *offset_ptr); + bool DecodeSections(); + /// \} + + /// Read a range of bytes from the Wasm module. + DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size); + + typedef struct section_info { + lldb::offset_t offset; + uint32_t size; + uint32_t id; + ConstString name; + } section_info_t; + + /// Wasm section header dump routines. + /// \{ + void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info_t &sh); + void DumpSectionHeaders(llvm::raw_ostream &ostream); + /// \} + + std::vector<section_info_t> m_sect_infos; + ArchSpec m_arch; + UUID m_uuid; +}; + +} // namespace wasm +} // namespace lldb_private +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index b04ac61c99a1..417aa2e21436 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -1,4 +1,4 @@ -//===-- OperatingSystemPython.cpp --------------------------------*- C++-*-===// +//===-- OperatingSystemPython.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -39,6 +39,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(OperatingSystemPython) + void OperatingSystemPython::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, @@ -337,7 +339,7 @@ OperatingSystemPython::CreateRegisterContextForThread(Thread *thread, m_interpreter->OSPlugin_RegisterContextData(m_python_object_sp, thread->GetID()); if (reg_context_data) { - std::string value = reg_context_data->GetValue(); + std::string value = std::string(reg_context_data->GetValue()); DataBufferSP data_sp(new DataBufferHeap(value.c_str(), value.length())); if (data_sp->GetByteSize()) { RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory( diff --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index 261f44c230f9..97c2f22b505f 100644 --- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -1,4 +1,4 @@ -//===-- PlatformFreeBSD.cpp -------------------------------------*- C++ -*-===// +//===-- PlatformFreeBSD.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -36,6 +36,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::platform_freebsd; +LLDB_PLUGIN_DEFINE(PlatformFreeBSD) + static uint32_t g_initialize_count = 0; diff --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h index e3a3aa7145f0..56f2f2771d12 100644 --- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h +++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_PlatformFreeBSD_h_ -#define liblldb_PlatformFreeBSD_h_ +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_FREEBSD_PLATFORMFREEBSD_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_FREEBSD_PLATFORMFREEBSD_H #include "Plugins/Platform/POSIX/PlatformPOSIX.h" @@ -62,10 +62,11 @@ public: lldb::addr_t offset) override; private: - DISALLOW_COPY_AND_ASSIGN(PlatformFreeBSD); + PlatformFreeBSD(const PlatformFreeBSD &) = delete; + const PlatformFreeBSD &operator=(const PlatformFreeBSD &) = delete; }; } // namespace platform_freebsd } // namespace lldb_private -#endif // liblldb_PlatformFreeBSD_h_ +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_FREEBSD_PLATFORMFREEBSD_H diff --git a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp index 53f819e6a272..caebd79c853e 100644 --- a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -1,4 +1,4 @@ -//===-- PlatformNetBSD.cpp -------------------------------------*- C++ -*-===// +//===-- PlatformNetBSD.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -34,6 +34,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::platform_netbsd; +LLDB_PLUGIN_DEFINE(PlatformNetBSD) + static uint32_t g_initialize_count = 0; @@ -329,14 +331,14 @@ PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, // Hook up process PTY if we have one (which we should for local debugging // with llgs). - int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); + int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); if (pty_fd != PseudoTerminal::invalid_fd) { process_sp->SetSTDIOFileDescriptor(pty_fd); LLDB_LOG(log, "hooked up STDIO pty to process"); } else LLDB_LOG(log, "not using process STDIO pty"); } else { - LLDB_LOG(log, "process launch failed: {0}", error); + LLDB_LOG(log, "{0}", error); // FIXME figure out appropriate cleanup here. Do we delete the target? Do // we delete the process? Does our caller do that? } diff --git a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h index 0584d92d6c99..d53e58418884 100644 --- a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h +++ b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_PlatformNetBSD_h_ -#define liblldb_PlatformNetBSD_h_ +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_NETBSD_PLATFORMNETBSD_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_NETBSD_PLATFORMNETBSD_H #include "Plugins/Platform/POSIX/PlatformPOSIX.h" @@ -60,10 +60,11 @@ public: lldb::addr_t offset) override; private: - DISALLOW_COPY_AND_ASSIGN(PlatformNetBSD); + PlatformNetBSD(const PlatformNetBSD &) = delete; + const PlatformNetBSD &operator=(const PlatformNetBSD &) = delete; }; } // namespace platform_netbsd } // namespace lldb_private -#endif // liblldb_PlatformNetBSD_h_ +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_NETBSD_PLATFORMNETBSD_H diff --git a/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp b/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp index 1b63e2da0a4f..a743970990a6 100644 --- a/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp +++ b/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp @@ -1,4 +1,4 @@ -//===-- PlatformOpenBSD.cpp -------------------------------------*- C++ -*-===// +//===-- PlatformOpenBSD.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -34,6 +34,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::platform_openbsd; +LLDB_PLUGIN_DEFINE(PlatformOpenBSD) + static uint32_t g_initialize_count = 0; diff --git a/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h b/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h index 3cb724f30325..9cfe32c3720c 100644 --- a/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h +++ b/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_PlatformOpenBSD_h_ -#define liblldb_PlatformOpenBSD_h_ +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_OPENBSD_PLATFORMOPENBSD_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_OPENBSD_PLATFORMOPENBSD_H #include "Plugins/Platform/POSIX/PlatformPOSIX.h" @@ -54,10 +54,11 @@ public: lldb::addr_t offset) override; private: - DISALLOW_COPY_AND_ASSIGN(PlatformOpenBSD); + PlatformOpenBSD(const PlatformOpenBSD &) = delete; + const PlatformOpenBSD &operator=(const PlatformOpenBSD &) = delete; }; } // namespace platform_openbsd } // namespace lldb_private -#endif // liblldb_PlatformOpenBSD_h_ +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_OPENBSD_PLATFORMOPENBSD_H diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 2b64be63a623..180ea1d2cfd1 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -1,4 +1,4 @@ -//===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===// +//===-- PlatformPOSIX.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,9 +8,9 @@ #include "PlatformPOSIX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObject.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" @@ -22,7 +22,6 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/ProcessLaunchInfo.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" @@ -64,148 +63,6 @@ lldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions( return m_options.at(&interpreter).get(); } -Status -PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, - lldb::ModuleSP &exe_module_sp, - const FileSpecList *module_search_paths_ptr) { - Status error; - // Nothing special to do here, just use the actual file and architecture - - char exe_path[PATH_MAX]; - ModuleSpec resolved_module_spec(module_spec); - - if (IsHost()) { - // If we have "ls" as the exe_file, resolve the executable location based - // on the current path variables - if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { - resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); - resolved_module_spec.GetFileSpec().SetFile(exe_path, - FileSpec::Style::native); - FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); - } - - if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) - FileSystem::Instance().ResolveExecutableLocation( - resolved_module_spec.GetFileSpec()); - - // Resolve any executable within a bundle on MacOSX - Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - - if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) - error.Clear(); - else { - const uint32_t permissions = FileSystem::Instance().GetPermissions( - resolved_module_spec.GetFileSpec()); - if (permissions && (permissions & eFilePermissionsEveryoneR) == 0) - error.SetErrorStringWithFormat( - "executable '%s' is not readable", - resolved_module_spec.GetFileSpec().GetPath().c_str()); - else - error.SetErrorStringWithFormat( - "unable to find executable for '%s'", - resolved_module_spec.GetFileSpec().GetPath().c_str()); - } - } else { - if (m_remote_platform_sp) { - error = - GetCachedExecutable(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, *m_remote_platform_sp); - } else { - // We may connect to a process and use the provided executable (Don't use - // local $PATH). - - // Resolve any executable within a bundle on MacOSX - Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - - if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) - error.Clear(); - else - error.SetErrorStringWithFormat("the platform is not currently " - "connected, and '%s' doesn't exist in " - "the system root.", - exe_path); - } - } - - if (error.Success()) { - if (resolved_module_spec.GetArchitecture().IsValid()) { - error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, nullptr); - if (error.Fail()) { - // If we failed, it may be because the vendor and os aren't known. If - // that is the case, try setting them to the host architecture and give - // it another try. - llvm::Triple &module_triple = - resolved_module_spec.GetArchitecture().GetTriple(); - bool is_vendor_specified = - (module_triple.getVendor() != llvm::Triple::UnknownVendor); - bool is_os_specified = - (module_triple.getOS() != llvm::Triple::UnknownOS); - if (!is_vendor_specified || !is_os_specified) { - const llvm::Triple &host_triple = - HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple(); - - if (!is_vendor_specified) - module_triple.setVendorName(host_triple.getVendorName()); - if (!is_os_specified) - module_triple.setOSName(host_triple.getOSName()); - - error = ModuleList::GetSharedModule(resolved_module_spec, - exe_module_sp, module_search_paths_ptr, nullptr, nullptr); - } - } - - // TODO find out why exe_module_sp might be NULL - if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) { - exe_module_sp.reset(); - error.SetErrorStringWithFormat( - "'%s' doesn't contain the architecture %s", - resolved_module_spec.GetFileSpec().GetPath().c_str(), - resolved_module_spec.GetArchitecture().GetArchitectureName()); - } - } else { - // No valid architecture was specified, ask the platform for the - // architectures that we should be using (in the correct order) and see - // if we can find a match that way - StreamString arch_names; - for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( - idx, resolved_module_spec.GetArchitecture()); - ++idx) { - error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, nullptr); - // Did we find an executable using one of the - if (error.Success()) { - if (exe_module_sp && exe_module_sp->GetObjectFile()) - break; - else - error.SetErrorToGenericError(); - } - - if (idx > 0) - arch_names.PutCString(", "); - arch_names.PutCString( - resolved_module_spec.GetArchitecture().GetArchitectureName()); - } - - if (error.Fail() || !exe_module_sp) { - if (FileSystem::Instance().Readable( - resolved_module_spec.GetFileSpec())) { - error.SetErrorStringWithFormat( - "'%s' doesn't contain any '%s' platform architectures: %s", - resolved_module_spec.GetFileSpec().GetPath().c_str(), - GetPluginName().GetCString(), arch_names.GetData()); - } else { - error.SetErrorStringWithFormat( - "'%s' is not readable", - resolved_module_spec.GetFileSpec().GetPath().c_str()); - } - } - } - } - - return error; -} - static uint32_t chown_file(Platform *platform, const char *path, uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) { @@ -429,7 +286,7 @@ std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() { if (GetLocalCacheDirectory() && *GetLocalCacheDirectory()) stream.Printf("cache dir: %s", GetLocalCacheDirectory()); if (stream.GetSize()) - return stream.GetString(); + return std::string(stream.GetString()); else return ""; } @@ -679,7 +536,7 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper"; Process *process = exe_ctx.GetProcessSP().get(); // Insert the dlopen shim defines into our generic expression: - std::string expr(GetLibdlFunctionDeclarations(process)); + std::string expr(std::string(GetLibdlFunctionDeclarations(process))); expr.append(dlopen_wrapper_code); Status utility_error; DiagnosticManager diagnostics; @@ -706,7 +563,7 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, FunctionCaller *do_dlopen_function = nullptr; // Fetch the clang types we will need: - ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); + TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); if (!ast) return nullptr; @@ -950,9 +807,9 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, Value return_value; // Fetch the clang types we will need: - ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); + TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); if (!ast) { - error.SetErrorString("dlopen error: Unable to get ClangASTContext"); + error.SetErrorString("dlopen error: Unable to get TypeSystemClang"); return LLDB_INVALID_IMAGE_TOKEN; } diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 5858f99088e6..72c54f4147c2 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_PlatformPOSIX_h_ -#define liblldb_PlatformPOSIX_h_ +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_POSIX_PLATFORMPOSIX_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_POSIX_PLATFORMPOSIX_H #include <map> #include <memory> @@ -37,10 +37,6 @@ public: const lldb::UnixSignalsSP &GetRemoteUnixSignals() override; - lldb_private::Status ResolveExecutable( - const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp, - const lldb_private::FileSpecList *module_search_paths_ptr) override; - lldb::ProcessSP Attach(lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be nullptr, if @@ -105,7 +101,8 @@ protected: llvm::StringRef GetLibdlFunctionDeclarations(lldb_private::Process *process); private: - DISALLOW_COPY_AND_ASSIGN(PlatformPOSIX); + PlatformPOSIX(const PlatformPOSIX &) = delete; + const PlatformPOSIX &operator=(const PlatformPOSIX &) = delete; }; -#endif // liblldb_PlatformPOSIX_h_ +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_POSIX_PLATFORMPOSIX_H diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 1e62ddfe94fd..21bf7f4ac46d 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -1,4 +1,4 @@ -//===-- PlatformRemoteGDBServer.cpp -----------------------------*- C++ -*-===// +//===-- PlatformRemoteGDBServer.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -35,6 +35,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::platform_gdb_server; +LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB) + static bool g_initialized = false; void PlatformRemoteGDBServer::Initialize() { @@ -286,40 +288,55 @@ Status PlatformRemoteGDBServer::ConnectRemote(Args &args) { "execute 'platform disconnect' to close the " "current connection", GetHostname()); + return error; + } + + if (args.GetArgumentCount() != 1) { + error.SetErrorString( + "\"platform connect\" takes a single argument: <connect-url>"); + return error; + } + + const char *url = args.GetArgumentAtIndex(0); + if (!url) + return Status("URL is null."); + + int port; + llvm::StringRef scheme, hostname, pathname; + if (!UriParser::Parse(url, scheme, hostname, port, pathname)) + return Status("Invalid URL: %s", url); + + // We're going to reuse the hostname when we connect to the debugserver. + m_platform_scheme = std::string(scheme); + m_platform_hostname = std::string(hostname); + + m_gdb_client.SetConnection(std::make_unique<ConnectionFileDescriptor>()); + if (repro::Reproducer::Instance().IsReplaying()) { + error = m_gdb_replay_server.Connect(m_gdb_client); + if (error.Success()) + m_gdb_replay_server.StartAsyncThread(); } else { - if (args.GetArgumentCount() == 1) { - m_gdb_client.SetConnection(new ConnectionFileDescriptor()); - // we're going to reuse the hostname when we connect to the debugserver - int port; - std::string path; - const char *url = args.GetArgumentAtIndex(0); - if (!url) - return Status("URL is null."); - llvm::StringRef scheme, hostname, pathname; - if (!UriParser::Parse(url, scheme, hostname, port, pathname)) - return Status("Invalid URL: %s", url); - m_platform_scheme = scheme; - m_platform_hostname = hostname; - path = pathname; - - const ConnectionStatus status = m_gdb_client.Connect(url, &error); - if (status == eConnectionStatusSuccess) { - if (m_gdb_client.HandshakeWithServer(&error)) { - m_gdb_client.GetHostInfo(); - // If a working directory was set prior to connecting, send it down - // now - if (m_working_dir) - m_gdb_client.SetWorkingDir(m_working_dir); - } else { - m_gdb_client.Disconnect(); - if (error.Success()) - error.SetErrorString("handshake failed"); - } - } - } else { - error.SetErrorString( - "\"platform connect\" takes a single argument: <connect-url>"); + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + repro::GDBRemoteProvider &provider = + g->GetOrCreate<repro::GDBRemoteProvider>(); + m_gdb_client.SetPacketRecorder(provider.GetNewPacketRecorder()); } + m_gdb_client.Connect(url, &error); + } + + if (error.Fail()) + return error; + + if (m_gdb_client.HandshakeWithServer(&error)) { + m_gdb_client.GetHostInfo(); + // If a working directory was set prior to connecting, send it down + // now. + if (m_working_dir) + m_gdb_client.SetWorkingDir(m_working_dir); + } else { + m_gdb_client.Disconnect(); + if (error.Success()) + error.SetErrorString("handshake failed"); } return error; } @@ -486,10 +503,10 @@ lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess( "gdb-remote", nullptr); if (process_sp) { - error = process_sp->ConnectRemote(nullptr, connect_url.c_str()); + error = process_sp->ConnectRemote(connect_url.c_str()); // Retry the connect remote one time... if (error.Fail()) - error = process_sp->ConnectRemote(nullptr, connect_url.c_str()); + error = process_sp->ConnectRemote(connect_url.c_str()); if (error.Success()) error = process_sp->Launch(launch_info); else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { @@ -572,7 +589,7 @@ lldb::ProcessSP PlatformRemoteGDBServer::Attach( target->CreateProcess(attach_info.GetListenerForProcess(debugger), "gdb-remote", nullptr); if (process_sp) { - error = process_sp->ConnectRemote(nullptr, connect_url.c_str()); + error = process_sp->ConnectRemote(connect_url.c_str()); if (error.Success()) { ListenerSP listener_sp = attach_info.GetHijackListener(); if (listener_sp) @@ -725,7 +742,8 @@ const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() { response.GetResponseType() != response.eResponse) return m_remote_signals_sp; - auto object_sp = StructuredData::ParseJSON(response.GetStringRef()); + auto object_sp = + StructuredData::ParseJSON(std::string(response.GetStringRef())); if (!object_sp || !object_sp->IsValid()) return m_remote_signals_sp; @@ -772,7 +790,7 @@ const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() { std::string description{""}; object_sp = dict->GetValueForKey("description"); if (object_sp && object_sp->IsValid()) - description = object_sp->GetStringValue(); + description = std::string(object_sp->GetStringValue()); remote_signals_sp->AddSignal(signo, name.str().c_str(), suppress, stop, notify, description.c_str()); @@ -811,7 +829,7 @@ std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme, result.Printf(":%u", port); if (path) result.Write(path, strlen(path)); - return result.GetString(); + return std::string(result.GetString()); } lldb::ProcessSP PlatformRemoteGDBServer::ConnectProcess( diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 13edcbab9f59..0602be1fa377 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -7,13 +7,14 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_PlatformRemoteGDBServer_h_ -#define liblldb_PlatformRemoteGDBServer_h_ +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_GDB_SERVER_PLATFORMREMOTEGDBSERVER_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_GDB_SERVER_PLATFORMREMOTEGDBSERVER_H #include <string> -#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h" #include "lldb/Target/Platform.h" namespace lldb_private { @@ -164,6 +165,7 @@ public: protected: process_gdb_remote::GDBRemoteCommunicationClient m_gdb_client; + process_gdb_remote::GDBRemoteCommunicationReplayServer m_gdb_replay_server; std::string m_platform_description; // After we connect we can get a more // complete description of what we are // connected to @@ -192,10 +194,12 @@ private: llvm::Optional<std::string> DoGetUserName(UserIDResolver::id_t uid) override; llvm::Optional<std::string> DoGetGroupName(UserIDResolver::id_t uid) override; - DISALLOW_COPY_AND_ASSIGN(PlatformRemoteGDBServer); + PlatformRemoteGDBServer(const PlatformRemoteGDBServer &) = delete; + const PlatformRemoteGDBServer & + operator=(const PlatformRemoteGDBServer &) = delete; }; } // namespace platform_gdb_server } // namespace lldb_private -#endif // liblldb_PlatformRemoteGDBServer_h_ +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_GDB_SERVER_PLATFORMREMOTEGDBSERVER_H diff --git a/lldb/source/Plugins/Plugins.def.in b/lldb/source/Plugins/Plugins.def.in new file mode 100644 index 000000000000..bf54598fb2f3 --- /dev/null +++ b/lldb/source/Plugins/Plugins.def.in @@ -0,0 +1,37 @@ +/*===- lldb/source/Plugin/Plugins.def ---------------------------*- 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 *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file enumerates all of the plugins supported by this build of LLDB. *| +|* Clients of this file should define the LLDB_PLUGIN macro to be a *| +|* function-like macro with a single parameter (the name of the plugin) *| +|* including this file will then enumerate all of the plugins. Script *| +|* interpreter plugins can be enumerated separately by defining *| +|* LLDB_SCRIPT_PLUGIN in which case they are not part of LLDB_PLUGIN. *| +|* *| +|* *| +|* The set of plugins supported by LLDB is generated at configuration *| +|* time, at which point this header is generated. Do not modify this *| +|* header directly. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLDB_PLUGIN +# error Please define the macro LLDB_PLUGIN(PluginName) +#endif + +#ifndef LLDB_SCRIPT_PLUGIN +#define LLDB_SCRIPT_PLUGIN(p) LLDB_PLUGIN(p) +#endif + +@LLDB_ENUM_PLUGINS@ +@LLDB_PROCESS_WINDOWS_PLUGIN@ +@LLDB_PROCESS_GDB_PLUGIN@ + +#undef LLDB_PLUGIN +#undef LLDB_SCRIPT_PLUGIN diff --git a/lldb/source/Plugins/Process/Darwin/CFBundle.cpp b/lldb/source/Plugins/Process/Darwin/CFBundle.cpp deleted file mode 100644 index 3cdd2fa575e7..000000000000 --- a/lldb/source/Plugins/Process/Darwin/CFBundle.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//===-- CFBundle.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 1/16/08. -// -//===----------------------------------------------------------------------===// - -#include "CFBundle.h" -#include "CFString.h" - -// CFBundle constructor -CFBundle::CFBundle(const char *path) - : CFReleaser<CFBundleRef>(), m_bundle_url() { - if (path && path[0]) - SetPath(path); -} - -// CFBundle copy constructor -CFBundle::CFBundle(const CFBundle &rhs) - : CFReleaser<CFBundleRef>(rhs), m_bundle_url(rhs.m_bundle_url) {} - -// CFBundle copy constructor -CFBundle &CFBundle::operator=(const CFBundle &rhs) { - *this = rhs; - return *this; -} - -// Destructor -CFBundle::~CFBundle() {} - -// Set the path for a bundle by supplying a -bool CFBundle::SetPath(const char *path) { - CFAllocatorRef alloc = kCFAllocatorDefault; - // Release our old bundle and ULR - reset(); // This class is a CFReleaser<CFBundleRef> - m_bundle_url.reset(); - // Make a CFStringRef from the supplied path - CFString cf_path; - cf_path.SetFileSystemRepresentation(path); - if (cf_path.get()) { - // Make our Bundle URL - m_bundle_url.reset(::CFURLCreateWithFileSystemPath( - alloc, cf_path.get(), kCFURLPOSIXPathStyle, true)); - if (m_bundle_url.get()) { - reset(::CFBundleCreate(alloc, m_bundle_url.get())); - } - } - return get() != NULL; -} - -CFStringRef CFBundle::GetIdentifier() const { - CFBundleRef bundle = get(); - if (bundle != NULL) - return ::CFBundleGetIdentifier(bundle); - return NULL; -} - -CFURLRef CFBundle::CopyExecutableURL() const { - CFBundleRef bundle = get(); - if (bundle != NULL) - return CFBundleCopyExecutableURL(bundle); - return NULL; -} diff --git a/lldb/source/Plugins/Process/Darwin/CFBundle.h b/lldb/source/Plugins/Process/Darwin/CFBundle.h deleted file mode 100644 index f49dc30f1f8f..000000000000 --- a/lldb/source/Plugins/Process/Darwin/CFBundle.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- CFBundle.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 1/16/08. -// -//===----------------------------------------------------------------------===// - -#ifndef __CFBundle_h__ -#define __CFBundle_h__ - -#include "CFUtils.h" - -class CFBundle : public CFReleaser<CFBundleRef> { -public: - // Constructors and Destructors - CFBundle(const char *path = NULL); - CFBundle(const CFBundle &rhs); - CFBundle &operator=(const CFBundle &rhs); - virtual ~CFBundle(); - bool SetPath(const char *path); - - CFStringRef GetIdentifier() const; - - CFURLRef CopyExecutableURL() const; - -protected: - CFReleaser<CFURLRef> m_bundle_url; -}; - -#endif // #ifndef __CFBundle_h__ diff --git a/lldb/source/Plugins/Process/Darwin/CFString.cpp b/lldb/source/Plugins/Process/Darwin/CFString.cpp deleted file mode 100644 index 4dcc05c86657..000000000000 --- a/lldb/source/Plugins/Process/Darwin/CFString.cpp +++ /dev/null @@ -1,153 +0,0 @@ -//===-- CFString.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 1/16/08. -// -//===----------------------------------------------------------------------===// - -#include "CFString.h" -#include <glob.h> -#include <string> - -// CFString constructor -CFString::CFString(CFStringRef s) : CFReleaser<CFStringRef>(s) {} - -// CFString copy constructor -CFString::CFString(const CFString &rhs) : CFReleaser<CFStringRef>(rhs) {} - -// CFString copy constructor -CFString &CFString::operator=(const CFString &rhs) { - if (this != &rhs) - *this = rhs; - return *this; -} - -CFString::CFString(const char *cstr, CFStringEncoding cstr_encoding) - : CFReleaser<CFStringRef>() { - if (cstr && cstr[0]) { - reset( - ::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding)); - } -} - -// Destructor -CFString::~CFString() {} - -const char *CFString::GetFileSystemRepresentation(std::string &s) { - return CFString::FileSystemRepresentation(get(), s); -} - -CFStringRef CFString::SetFileSystemRepresentation(const char *path) { - CFStringRef new_value = NULL; - if (path && path[0]) - new_value = - ::CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path); - reset(new_value); - return get(); -} - -CFStringRef CFString::SetFileSystemRepresentationFromCFType(CFTypeRef cf_type) { - CFStringRef new_value = NULL; - if (cf_type != NULL) { - CFTypeID cf_type_id = ::CFGetTypeID(cf_type); - - if (cf_type_id == ::CFStringGetTypeID()) { - // Retain since we are using the existing object - new_value = (CFStringRef)::CFRetain(cf_type); - } else if (cf_type_id == ::CFURLGetTypeID()) { - new_value = - ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle); - } - } - reset(new_value); - return get(); -} - -CFStringRef -CFString::SetFileSystemRepresentationAndExpandTilde(const char *path) { - std::string expanded_path; - if (CFString::GlobPath(path, expanded_path)) - SetFileSystemRepresentation(expanded_path.c_str()); - else - reset(); - return get(); -} - -const char *CFString::UTF8(std::string &str) { - return CFString::UTF8(get(), str); -} - -// Static function that puts a copy of the UTF8 contents of CF_STR into STR and -// returns the C string pointer that is contained in STR when successful, else -// NULL is returned. This allows the std::string parameter to own the extracted -// string, -// and also allows that string to be returned as a C string pointer that can be -// used. - -const char *CFString::UTF8(CFStringRef cf_str, std::string &str) { - if (cf_str) { - const CFStringEncoding encoding = kCFStringEncodingUTF8; - CFIndex max_utf8_str_len = CFStringGetLength(cf_str); - max_utf8_str_len = - CFStringGetMaximumSizeForEncoding(max_utf8_str_len, encoding); - if (max_utf8_str_len > 0) { - str.resize(max_utf8_str_len); - if (!str.empty()) { - if (CFStringGetCString(cf_str, &str[0], str.size(), encoding)) { - str.resize(strlen(str.c_str())); - return str.c_str(); - } - } - } - } - return NULL; -} - -// Static function that puts a copy of the file system representation of CF_STR -// into STR and returns the C string pointer that is contained in STR when -// successful, else NULL is returned. This allows the std::string parameter to -// own the extracted string, and also allows that string to be returned as a C -// string pointer that can be used. - -const char *CFString::FileSystemRepresentation(CFStringRef cf_str, - std::string &str) { - if (cf_str) { - CFIndex max_length = - ::CFStringGetMaximumSizeOfFileSystemRepresentation(cf_str); - if (max_length > 0) { - str.resize(max_length); - if (!str.empty()) { - if (::CFStringGetFileSystemRepresentation(cf_str, &str[0], - str.size())) { - str.erase(::strlen(str.c_str())); - return str.c_str(); - } - } - } - } - str.erase(); - return NULL; -} - -CFIndex CFString::GetLength() const { - CFStringRef str = get(); - if (str) - return CFStringGetLength(str); - return 0; -} - -const char *CFString::GlobPath(const char *path, std::string &expanded_path) { - glob_t globbuf; - if (::glob(path, GLOB_TILDE, NULL, &globbuf) == 0) { - expanded_path = globbuf.gl_pathv[0]; - ::globfree(&globbuf); - } else - expanded_path.clear(); - - return expanded_path.c_str(); -} diff --git a/lldb/source/Plugins/Process/Darwin/CFString.h b/lldb/source/Plugins/Process/Darwin/CFString.h deleted file mode 100644 index d1bd5682689e..000000000000 --- a/lldb/source/Plugins/Process/Darwin/CFString.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- CFString.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 1/16/08. -// -//===----------------------------------------------------------------------===// - -#ifndef __CFString_h__ -#define __CFString_h__ - -#include "CFUtils.h" -#include <iosfwd> - -class CFString : public CFReleaser<CFStringRef> { -public: - // Constructors and Destructors - CFString(CFStringRef cf_str = NULL); - CFString(const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8); - CFString(const CFString &rhs); - CFString &operator=(const CFString &rhs); - virtual ~CFString(); - - const char *GetFileSystemRepresentation(std::string &str); - CFStringRef SetFileSystemRepresentation(const char *path); - CFStringRef SetFileSystemRepresentationFromCFType(CFTypeRef cf_type); - CFStringRef SetFileSystemRepresentationAndExpandTilde(const char *path); - const char *UTF8(std::string &str); - CFIndex GetLength() const; - static const char *UTF8(CFStringRef cf_str, std::string &str); - static const char *FileSystemRepresentation(CFStringRef cf_str, - std::string &str); - static const char *GlobPath(const char *path, std::string &expanded_path); -}; - -#endif // #ifndef __CFString_h__ diff --git a/lldb/source/Plugins/Process/Darwin/CFUtils.h b/lldb/source/Plugins/Process/Darwin/CFUtils.h deleted file mode 100644 index b567524ce63a..000000000000 --- a/lldb/source/Plugins/Process/Darwin/CFUtils.h +++ /dev/null @@ -1,75 +0,0 @@ -//===-- CFUtils.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 3/5/07. -// -//===----------------------------------------------------------------------===// - -#ifndef __CFUtils_h__ -#define __CFUtils_h__ - -#include <CoreFoundation/CoreFoundation.h> - -#ifdef __cplusplus - -// Templatized CF helper class that can own any CF pointer and will -// call CFRelease() on any valid pointer it owns unless that pointer is -// explicitly released using the release() member function. -template <class T> class CFReleaser { -public: - // Type names for the avlue - typedef T element_type; - - // Constructors and destructors - CFReleaser(T ptr = NULL) : _ptr(ptr) {} - CFReleaser(const CFReleaser ©) : _ptr(copy.get()) { - if (get()) - ::CFRetain(get()); - } - virtual ~CFReleaser() { reset(); } - - // Assignments - CFReleaser &operator=(const CFReleaser<T> ©) { - if (copy != *this) { - // Replace our owned pointer with the new one - reset(copy.get()); - // Retain the current pointer that we own - if (get()) - ::CFRetain(get()); - } - } - // Get the address of the contained type - T *ptr_address() { return &_ptr; } - - // Access the pointer itself - const T get() const { return _ptr; } - T get() { return _ptr; } - - // Set a new value for the pointer and CFRelease our old - // value if we had a valid one. - void reset(T ptr = NULL) { - if (ptr != _ptr) { - if (_ptr != NULL) - ::CFRelease(_ptr); - _ptr = ptr; - } - } - - // Release ownership without calling CFRelease - T release() { - T tmp = _ptr; - _ptr = NULL; - return tmp; - } - -private: - element_type _ptr; -}; - -#endif // #ifdef __cplusplus -#endif // #ifndef __CFUtils_h__ diff --git a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp deleted file mode 100644 index f70ef97a2bc5..000000000000 --- a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp +++ /dev/null @@ -1,638 +0,0 @@ -//===-- DarwinProcessLauncher.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 -// -//===----------------------------------------------------------------------===// - -// -// DarwinProcessLauncher.cpp -// lldb -// -// Created by Todd Fiala on 8/30/16. -// -// - -#include "DarwinProcessLauncher.h" - -// C includes -#include <spawn.h> -#include <sys/ptrace.h> -#include <sys/stat.h> -#include <sys/sysctl.h> - -#ifndef _POSIX_SPAWN_DISABLE_ASLR -#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 -#endif - -// LLDB includes -#include "lldb/lldb-enumerations.h" - -#include "lldb/Host/PseudoTerminal.h" -#include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/StreamString.h" -#include "llvm/Support/Errno.h" - -#include "CFBundle.h" -#include "CFString.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; -using namespace lldb_private::darwin_process_launcher; - -namespace { -static LaunchFlavor g_launch_flavor = LaunchFlavor::Default; -} - -namespace lldb_private { -namespace darwin_process_launcher { - -static uint32_t GetCPUTypeForLocalProcess(::pid_t pid) { - int mib[CTL_MAXNAME] = { - 0, - }; - size_t len = CTL_MAXNAME; - if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) - return 0; - - mib[len] = pid; - len++; - - cpu_type_t cpu; - size_t cpu_len = sizeof(cpu); - if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) - cpu = 0; - return cpu; -} - -static bool ResolveExecutablePath(const char *path, char *resolved_path, - size_t resolved_path_size) { - if (path == NULL || path[0] == '\0') - return false; - - char max_path[PATH_MAX]; - std::string result; - CFString::GlobPath(path, result); - - if (result.empty()) - result = path; - - struct stat path_stat; - if (::stat(path, &path_stat) == 0) { - if ((path_stat.st_mode & S_IFMT) == S_IFDIR) { - CFBundle bundle(path); - CFReleaser<CFURLRef> url(bundle.CopyExecutableURL()); - if (url.get()) { - if (::CFURLGetFileSystemRepresentation( - url.get(), true, (UInt8 *)resolved_path, resolved_path_size)) - return true; - } - } - } - - if (realpath(path, max_path)) { - // Found the path relatively... - ::strncpy(resolved_path, max_path, resolved_path_size); - return strlen(resolved_path) + 1 < resolved_path_size; - } else { - // Not a relative path, check the PATH environment variable if the - const char *PATH = getenv("PATH"); - if (PATH) { - const char *curr_path_start = PATH; - const char *curr_path_end; - while (curr_path_start && *curr_path_start) { - curr_path_end = strchr(curr_path_start, ':'); - if (curr_path_end == NULL) { - result.assign(curr_path_start); - curr_path_start = NULL; - } else if (curr_path_end > curr_path_start) { - size_t len = curr_path_end - curr_path_start; - result.assign(curr_path_start, len); - curr_path_start += len + 1; - } else - break; - - result += '/'; - result += path; - struct stat s; - if (stat(result.c_str(), &s) == 0) { - ::strncpy(resolved_path, result.c_str(), resolved_path_size); - return result.size() + 1 < resolved_path_size; - } - } - } - } - return false; -} - -// TODO check if we have a general purpose fork and exec. We may be -// able to get rid of this entirely. -static Status ForkChildForPTraceDebugging(const char *path, char const *argv[], - char const *envp[], ::pid_t *pid, - int *pty_fd) { - Status error; - if (!path || !argv || !envp || !pid || !pty_fd) { - error.SetErrorString("invalid arguments"); - return error; - } - - // Use a fork that ties the child process's stdin/out/err to a pseudo - // terminal so we can read it in our MachProcess::STDIOThread as unbuffered - // io. - PseudoTerminal pty; - char fork_error[256]; - memset(fork_error, 0, sizeof(fork_error)); - *pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error))); - if (*pid < 0) { - // Status during fork. - *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID); - error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__, - fork_error); - return error; - } else if (pid == 0) { - // Child process - - // Debug this process. - ::ptrace(PT_TRACE_ME, 0, 0, 0); - - // Get BSD signals as mach exceptions. - ::ptrace(PT_SIGEXC, 0, 0, 0); - - // If our parent is setgid, lets make sure we don't inherit those extra - // powers due to nepotism. - if (::setgid(getgid()) == 0) { - // Let the child have its own process group. We need to execute this call - // in both the child and parent to avoid a race condition between the two - // processes. - - // Set the child process group to match its pid. - ::setpgid(0, 0); - - // Sleep a bit to before the exec call. - ::sleep(1); - - // Turn this process into the given executable. - ::execv(path, (char *const *)argv); - } - // Exit with error code. Child process should have taken over in above exec - // call and if the exec fails it will exit the child process below. - ::exit(127); - } else { - // Parent process - // Let the child have its own process group. We need to execute this call - // in both the child and parent to avoid a race condition between the two - // processes. - - // Set the child process group to match its pid - ::setpgid(*pid, *pid); - if (pty_fd) { - // Release our master pty file descriptor so the pty class doesn't close - // it and so we can continue to use it in our STDIO thread - *pty_fd = pty.ReleaseMasterFileDescriptor(); - } - } - return error; -} - -static Status -CreatePosixSpawnFileAction(const FileAction &action, - posix_spawn_file_actions_t *file_actions) { - Status error; - - // Log it. - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) { - StreamString stream; - stream.PutCString("converting file action for posix_spawn(): "); - action.Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - - // Validate args. - if (!file_actions) { - error.SetErrorString("mandatory file_actions arg is null"); - return error; - } - - // Build the posix file action. - switch (action.GetAction()) { - case FileAction::eFileActionOpen: { - const int error_code = ::posix_spawn_file_actions_addopen( - file_actions, action.GetFD(), action.GetPath(), - action.GetActionArgument(), 0); - if (error_code != 0) { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } - - case FileAction::eFileActionClose: { - const int error_code = - ::posix_spawn_file_actions_addclose(file_actions, action.GetFD()); - if (error_code != 0) { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } - - case FileAction::eFileActionDuplicate: { - const int error_code = ::posix_spawn_file_actions_adddup2( - file_actions, action.GetFD(), action.GetActionArgument()); - if (error_code != 0) { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } - - case FileAction::eFileActionNone: - default: - LLDB_LOGF(log, "%s(): unsupported file action %u", __FUNCTION__, - action.GetAction()); - break; - } - - return error; -} - -static Status PosixSpawnChildForPTraceDebugging(const char *path, - ProcessLaunchInfo &launch_info, - ::pid_t *pid, - cpu_type_t *actual_cpu_type) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!pid) { - error.SetErrorStringWithFormat("%s(): pid arg cannot be null", - __FUNCTION__); - return error; - } - - posix_spawnattr_t attr; - short flags; - if (log) { - StreamString stream; - stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path); - launch_info.Dump(stream, nullptr); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - - int error_code; - if ((error_code = ::posix_spawnattr_init(&attr)) != 0) { - LLDB_LOGF(log, "::posix_spawnattr_init(&attr) failed"); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - - // Ensure we clean up the spawnattr structure however we exit this function. - std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up( - &attr, ::posix_spawnattr_destroy); - - flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF | - POSIX_SPAWN_SETSIGMASK; - if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) - flags |= _POSIX_SPAWN_DISABLE_ASLR; - - sigset_t no_signals; - sigset_t all_signals; - sigemptyset(&no_signals); - sigfillset(&all_signals); - ::posix_spawnattr_setsigmask(&attr, &no_signals); - ::posix_spawnattr_setsigdefault(&attr, &all_signals); - - if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) { - LLDB_LOG(log, - "::posix_spawnattr_setflags(&attr, " - "POSIX_SPAWN_START_SUSPENDED{0}) failed: {1}", - flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR" - : "", - llvm::sys::StrError(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - -#if !defined(__arm__) - - // We don't need to do this for ARM, and we really shouldn't now that we have - // multiple CPU subtypes and no posix_spawnattr call that allows us to set - // which CPU subtype to launch... - cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType(); - if (desired_cpu_type != LLDB_INVALID_CPUTYPE) { - size_t ocount = 0; - error_code = - ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount); - if (error_code != 0) { - LLDB_LOG(log, - "::posix_spawnattr_setbinpref_np(&attr, 1, " - "cpu_type = {0:x8}, count => {1}): {2}", - desired_cpu_type, ocount, llvm::sys::StrError(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - if (ocount != 1) { - error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np " - "did not set the expected number " - "of cpu_type entries: expected 1 " - "but was %zu", - ocount); - return error; - } - } -#endif - - posix_spawn_file_actions_t file_actions; - if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) { - LLDB_LOG(log, "::posix_spawn_file_actions_init(&file_actions) failed: {0}", - llvm::sys::StrError(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - - // Ensure we clean up file actions however we exit this. When the - // file_actions_up below goes out of scope, we'll get our file action - // cleanup. - std::unique_ptr<posix_spawn_file_actions_t, - int (*)(posix_spawn_file_actions_t *)> - file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy); - - // We assume the caller has setup the file actions appropriately. We are not - // in the business of figuring out what we really need here. lldb-server will - // have already called FinalizeFileActions() as well to button these up - // properly. - const size_t num_actions = launch_info.GetNumFileActions(); - for (size_t action_index = 0; action_index < num_actions; ++action_index) { - const FileAction *const action = - launch_info.GetFileActionAtIndex(action_index); - if (!action) - continue; - - error = CreatePosixSpawnFileAction(*action, &file_actions); - if (!error.Success()) { - LLDB_LOGF(log, - "%s(): error converting FileAction to posix_spawn " - "file action: %s", - __FUNCTION__, error.AsCString()); - return error; - } - } - - // TODO: Verify if we can set the working directory back immediately - // after the posix_spawnp call without creating a race condition??? - const char *const working_directory = - launch_info.GetWorkingDirectory().GetCString(); - if (working_directory && working_directory[0]) - ::chdir(working_directory); - - auto argv = launch_info.GetArguments().GetArgumentVector(); - auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector(); - error_code = ::posix_spawnp(pid, path, &file_actions, &attr, - (char *const *)argv, (char *const *)envp); - if (error_code != 0) { - LLDB_LOG(log, - "::posix_spawnp(pid => {0}, path = '{1}', file_actions " - "= {2}, attr = {3}, argv = {4}, envp = {5}) failed: {6}", - pid, path, &file_actions, &attr, argv, envp, - llvm::sys::StrError(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - - // Validate we got a pid. - if (pid == LLDB_INVALID_PROCESS_ID) { - error.SetErrorString("posix_spawn() did not indicate a failure but it " - "failed to return a pid, aborting."); - return error; - } - - if (actual_cpu_type) { - *actual_cpu_type = GetCPUTypeForLocalProcess(*pid); - LLDB_LOGF(log, - "%s(): cpu type for launched process pid=%i: " - "cpu_type=0x%8.8x", - __FUNCTION__, *pid, *actual_cpu_type); - } - - return error; -} - -Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, - LaunchFlavor *launch_flavor) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!launch_flavor) { - error.SetErrorString("mandatory launch_flavor field was null"); - return error; - } - - if (log) { - StreamString stream; - stream.Printf("NativeProcessDarwin::%s(): launching with the " - "following launch info:", - __FUNCTION__); - launch_info.Dump(stream, nullptr); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - - // Retrieve the binary name given to us. - char given_path[PATH_MAX]; - given_path[0] = '\0'; - launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path)); - - // Determine the manner in which we'll launch. - *launch_flavor = g_launch_flavor; - if (*launch_flavor == LaunchFlavor::Default) { - // Our default launch method is posix spawn - *launch_flavor = LaunchFlavor::PosixSpawn; -#if defined WITH_FBS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(given_path, ".app")) { - *launch_flavor = eLaunchFlavorFBS; - } -#elif defined WITH_BKS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(given_path, ".app")) { - *launch_flavor = eLaunchFlavorBKS; - } -#elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (strstr(given_path, ".app")) { - *launch_flavor = eLaunchFlavorSpringBoard; - } -#endif - } - - // Attempt to resolve the binary name to an absolute path. - char resolved_path[PATH_MAX]; - resolved_path[0] = '\0'; - - LLDB_LOGF(log, "%s(): attempting to resolve given binary path: \"%s\"", - __FUNCTION__, given_path); - - // If we fail to resolve the path to our executable, then just use what we - // were given and hope for the best - if (!ResolveExecutablePath(given_path, resolved_path, - sizeof(resolved_path))) { - LLDB_LOGF(log, - "%s(): failed to resolve binary path, using " - "what was given verbatim and hoping for the best", - __FUNCTION__); - ::strncpy(resolved_path, given_path, sizeof(resolved_path)); - } else { - LLDB_LOGF(log, "%s(): resolved given binary path to: \"%s\"", __FUNCTION__, - resolved_path); - } - - char launch_err_str[PATH_MAX]; - launch_err_str[0] = '\0'; - - // TODO figure out how to handle QSetProcessEvent - // const char *process_event = ctx.GetProcessEvent(); - - // Ensure the binary is there. - struct stat path_stat; - if (::stat(resolved_path, &path_stat) == -1) { - error.SetErrorToErrno(); - return error; - } - - // Fork a child process for debugging - // state_callback(eStateLaunching); - - const auto argv = launch_info.GetArguments().GetConstArgumentVector(); - const auto envp = - launch_info.GetEnvironmentEntries().GetConstArgumentVector(); - - switch (*launch_flavor) { - case LaunchFlavor::ForkExec: { - ::pid_t pid = LLDB_INVALID_PROCESS_ID; - error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid, - pty_master_fd); - if (error.Success()) { - launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); - } else { - // Reset any variables that might have been set during a failed launch - // attempt. - if (pty_master_fd) - *pty_master_fd = -1; - - // We're done. - return error; - } - } break; - -#ifdef WITH_FBS - case LaunchFlavor::FBS: { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { - std::string app_bundle_path(path, app_ext + strlen(".app")); - m_flags |= eMachProcessFlagsUsingFBS; - if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, - no_stdio, disable_aslr, event_data, - launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a - // non-zero m_pid. - else - break; // We tried a FBS launch, but didn't succeed lets get out - } - } break; -#endif - -#ifdef WITH_BKS - case LaunchFlavor::BKS: { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { - std::string app_bundle_path(path, app_ext + strlen(".app")); - m_flags |= eMachProcessFlagsUsingBKS; - if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, - no_stdio, disable_aslr, event_data, - launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a - // non-zero m_pid. - else - break; // We tried a BKS launch, but didn't succeed lets get out - } - } break; -#endif - -#ifdef WITH_SPRINGBOARD - case LaunchFlavor::SpringBoard: { - // .../whatever.app/whatever ? - // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in - // "com.apple.whatever" here - const char *app_ext = strstr(path, ".app/"); - if (app_ext == NULL) { - // .../whatever.app ? - int len = strlen(path); - if (len > 5) { - if (strcmp(path + len - 4, ".app") == 0) { - app_ext = path + len - 4; - } - } - } - if (app_ext) { - std::string app_bundle_path(path, app_ext + strlen(".app")); - if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, - disable_aslr, launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a - // non-zero m_pid. - else - break; // We tried a springboard launch, but didn't succeed lets get out - } - } break; -#endif - - case LaunchFlavor::PosixSpawn: { - ::pid_t pid = LLDB_INVALID_PROCESS_ID; - - // Retrieve paths for stdin/stdout/stderr. - cpu_type_t actual_cpu_type = 0; - error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid, - &actual_cpu_type); - if (error.Success()) { - launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); - if (pty_master_fd) - *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); - } else { - // Reset any variables that might have been set during a failed launch - // attempt. - if (pty_master_fd) - *pty_master_fd = -1; - - // We're done. - return error; - } - break; - } - - default: - // Invalid launch flavor. - error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown " - "launch flavor %d", - __FUNCTION__, (int)*launch_flavor); - return error; - } - - if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) { - // If we don't have a valid process ID and no one has set the error, then - // return a generic error. - if (error.Success()) - error.SetErrorStringWithFormat("%s(): failed to launch, no reason " - "specified", - __FUNCTION__); - } - - // We're done with the launch side of the operation. - return error; -} -} -} // namespaces diff --git a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h deleted file mode 100644 index 0e65b56a143e..000000000000 --- a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h +++ /dev/null @@ -1,48 +0,0 @@ -//===-- DarwinProcessLauncher.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 DarwinProcessLauncher_h -#define DarwinProcessLauncher_h - -// C headers -#include <mach/machine.h> -#include <sys/types.h> - -// C++ headers -#include <functional> - -// LLDB headers -#include "lldb/lldb-enumerations.h" -#include "lldb/lldb-forward.h" - -#include "LaunchFlavor.h" - -namespace lldb_private { -namespace darwin_process_launcher { -// ============================================================================= -/// Launches a process for debugging. -/// -/// \param[inout] launch_info -/// Specifies details about the process to launch (e.g. path, architecture, -/// etc.). On output, includes the launched ProcessID (pid). -/// -/// \param[out] pty_master_fd -/// Returns the master side of the pseudo-terminal used to communicate -/// with stdin/stdout from the launched process. May be nullptr. -/// -/// \param[out] launch_flavor -/// Contains the launch flavor used when launching the process. -// ============================================================================= -Status -LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, - lldb_private::process_darwin::LaunchFlavor *launch_flavor); - -} // darwin_process_launcher -} // lldb_private - -#endif /* DarwinProcessLauncher_h */ diff --git a/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h b/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h deleted file mode 100644 index cfd76d1b9c3c..000000000000 --- a/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- LaunchFlavor.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 LaunchFlavor_h -#define LaunchFlavor_h - -namespace lldb_private { -namespace process_darwin { - -enum class LaunchFlavor { - Default = 0, - PosixSpawn = 1, - ForkExec = 2, -#ifdef WITH_SPRINGBOARD - SpringBoard = 3, -#endif -#ifdef WITH_BKS - BKS = 4, -#endif -#ifdef WITH_FBS - FBS = 5 -#endif -}; -} -} // namespaces - -#endif /* LaunchFlavor_h */ diff --git a/lldb/source/Plugins/Process/Darwin/MachException.cpp b/lldb/source/Plugins/Process/Darwin/MachException.cpp deleted file mode 100644 index 073ad64b300c..000000000000 --- a/lldb/source/Plugins/Process/Darwin/MachException.cpp +++ /dev/null @@ -1,514 +0,0 @@ -//===-- MachException.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/18/07. -// -//===----------------------------------------------------------------------===// - -#include "MachException.h" - -// C includes -#include <errno.h> -#include <sys/ptrace.h> -#include <sys/types.h> - -// C++ includes -#include <mutex> - -// LLDB includes -#include "lldb/Target/UnixSignals.h" -#include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/Stream.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; - -// Routine mach_exception_raise -extern "C" kern_return_t -catch_mach_exception_raise(mach_port_t exception_port, mach_port_t thread, - mach_port_t task, exception_type_t exception, - mach_exception_data_t code, - mach_msg_type_number_t codeCnt); - -extern "C" kern_return_t catch_mach_exception_raise_state( - mach_port_t exception_port, exception_type_t exception, - const mach_exception_data_t code, mach_msg_type_number_t codeCnt, - int *flavor, const thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt); - -// Routine mach_exception_raise_state_identity -extern "C" kern_return_t catch_mach_exception_raise_state_identity( - mach_port_t exception_port, mach_port_t thread, mach_port_t task, - exception_type_t exception, mach_exception_data_t code, - mach_msg_type_number_t codeCnt, int *flavor, thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt); - -extern "C" boolean_t mach_exc_server(mach_msg_header_t *InHeadP, - mach_msg_header_t *OutHeadP); - -static MachException::Data *g_message = NULL; - -extern "C" kern_return_t catch_mach_exception_raise_state( - mach_port_t exc_port, exception_type_t exc_type, - const mach_exception_data_t exc_data, mach_msg_type_number_t exc_data_count, - int *flavor, const thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt) { - // TODO change to LIBLLDB_LOG_EXCEPTION - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) { - LLDB_LOGF(log, - "::%s(exc_port = 0x%4.4x, exc_type = %d (%s), " - "exc_data = 0x%llx, exc_data_count = %d)", - __FUNCTION__, exc_port, exc_type, MachException::Name(exc_type), - (uint64_t)exc_data, exc_data_count); - } - return KERN_FAILURE; -} - -extern "C" kern_return_t catch_mach_exception_raise_state_identity( - mach_port_t exc_port, mach_port_t thread_port, mach_port_t task_port, - exception_type_t exc_type, mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count, int *flavor, - thread_state_t old_state, mach_msg_type_number_t old_stateCnt, - thread_state_t new_state, mach_msg_type_number_t *new_stateCnt) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) { - LLDB_LOGF(log, - "::%s(exc_port = 0x%4.4x, thd_port = 0x%4.4x, " - "tsk_port = 0x%4.4x, exc_type = %d (%s), exc_data[%d] = " - "{ 0x%llx, 0x%llx })", - __FUNCTION__, exc_port, thread_port, task_port, exc_type, - MachException::Name(exc_type), exc_data_count, - (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), - (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); - } - - return KERN_FAILURE; -} - -extern "C" kern_return_t -catch_mach_exception_raise(mach_port_t exc_port, mach_port_t thread_port, - mach_port_t task_port, exception_type_t exc_type, - mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) { - LLDB_LOGF(log, - "::%s(exc_port = 0x%4.4x, thd_port = 0x%4.4x, " - "tsk_port = 0x%4.4x, exc_type = %d (%s), exc_data[%d] " - "= { 0x%llx, 0x%llx })", - __FUNCTION__, exc_port, thread_port, task_port, exc_type, - MachException::Name(exc_type), exc_data_count, - (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), - (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); - } - - if (task_port == g_message->task_port) { - g_message->task_port = task_port; - g_message->thread_port = thread_port; - g_message->exc_type = exc_type; - g_message->exc_data.resize(exc_data_count); - ::memcpy(&g_message->exc_data[0], exc_data, - g_message->exc_data.size() * sizeof(mach_exception_data_type_t)); - return KERN_SUCCESS; - } - return KERN_FAILURE; -} - -bool MachException::Data::GetStopInfo(struct ThreadStopInfo *stop_info, - const UnixSignals &signals, - Stream &stream) const { - if (!stop_info) - return false; - - // Zero out the structure. - memset(stop_info, 0, sizeof(struct ThreadStopInfo)); - - if (exc_type == 0) { - stop_info->reason = eStopReasonInvalid; - return true; - } - - // We always stop with a mach exception. - stop_info->reason = eStopReasonException; - // Save the EXC_XXXX exception type. - stop_info->details.exception.type = exc_type; - - // Fill in a text description - const char *exc_name = MachException::Name(exc_type); - if (exc_name) - stream.Printf("%s", exc_name); - else - stream.Printf("%i", exc_type); - - stop_info->details.exception.data_count = exc_data.size(); - - int soft_signal = SoftSignal(); - if (soft_signal) { - const char *sig_str = signals.GetSignalAsCString(soft_signal); - stream.Printf(" EXC_SOFT_SIGNAL( %i ( %s ))", soft_signal, - sig_str ? sig_str : "unknown signal"); - } else { - // No special disassembly for exception data, just print it. - size_t idx; - stream.Printf(" data[%llu] = {", - (uint64_t)stop_info->details.exception.data_count); - - for (idx = 0; idx < stop_info->details.exception.data_count; ++idx) { - stream.Printf( - "0x%llx%c", (uint64_t)exc_data[idx], - ((idx + 1 == stop_info->details.exception.data_count) ? '}' : ',')); - } - } - - // Copy the exception data - for (size_t i = 0; i < stop_info->details.exception.data_count; i++) - stop_info->details.exception.data[i] = exc_data[i]; - - return true; -} - -Status MachException::Message::Receive(mach_port_t port, - mach_msg_option_t options, - mach_msg_timeout_t timeout, - mach_port_t notify_port) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - mach_msg_timeout_t mach_msg_timeout = - options & MACH_RCV_TIMEOUT ? timeout : 0; - if (log && ((options & MACH_RCV_TIMEOUT) == 0)) { - // Dump this log message if we have no timeout in case it never returns - LLDB_LOGF(log, - "::mach_msg(msg->{bits = %#x, size = %u remote_port = %#x, " - "local_port = %#x, reserved = 0x%x, id = 0x%x}, " - "option = %#x, send_size = 0, rcv_size = %llu, " - "rcv_name = %#x, timeout = %u, notify = %#x)", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, - (uint64_t)sizeof(exc_msg.data), port, mach_msg_timeout, - notify_port); - } - - mach_msg_return_t mach_err = - ::mach_msg(&exc_msg.hdr, - options, // options - 0, // Send size - sizeof(exc_msg.data), // Receive size - port, // exception port to watch for - // exception on - mach_msg_timeout, // timeout in msec (obeyed only - // if MACH_RCV_TIMEOUT is ORed - // into the options parameter) - notify_port); - error.SetError(mach_err, eErrorTypeMachKernel); - - // Dump any errors we get - if (error.Fail() && log) { - LLDB_LOGF(log, - "::mach_msg(msg->{bits = %#x, size = %u remote_port = %#x, " - "local_port = %#x, reserved = 0x%x, id = 0x%x}, " - "option = %#x, send_size = %u, rcv_size = %lu, rcv_name " - "= %#x, timeout = %u, notify = %#x) failed: %s", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, 0, - sizeof(exc_msg.data), port, mach_msg_timeout, notify_port, - error.AsCString()); - } - return error; -} - -void MachException::Message::Dump(Stream &stream) const { - stream.Printf(" exc_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = " - "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = " - "0x%8.8x }\n", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id); - - stream.Printf(" reply_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = " - "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = " - "0x%8.8x }", - reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, - reply_msg.hdr.msgh_remote_port, reply_msg.hdr.msgh_local_port, - reply_msg.hdr.msgh_reserved, reply_msg.hdr.msgh_id); -} - -bool MachException::Message::CatchExceptionRaise(task_t task) { - bool success = false; - state.task_port = task; - g_message = &state; - // The exc_server function is the MIG generated server handling function to - // handle messages from the kernel relating to the occurrence of an exception - // in a thread. Such messages are delivered to the exception port set via - // thread_set_exception_ports or task_set_exception_ports. When an exception - // occurs in a thread, the thread sends an exception message to its exception - // port, blocking in the kernel waiting for the receipt of a reply. The - // exc_server function performs all necessary argument handling for this - // kernel message and calls catch_exception_raise, - // catch_exception_raise_state or catch_exception_raise_state_identity, which - // should handle the exception. If the called routine returns KERN_SUCCESS, a - // reply message will be sent, allowing the thread to continue from the point - // of the exception; otherwise, no reply message is sent and the called - // routine must have dealt with the exception thread directly. - if (mach_exc_server(&exc_msg.hdr, &reply_msg.hdr)) { - success = true; - } else { - Log *log( - GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - LLDB_LOGF(log, - "MachException::Message::%s(): mach_exc_server " - "returned zero...", - __FUNCTION__); - } - g_message = NULL; - return success; -} - -Status MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task, - int signal) { - // Reply to the exception... - Status error; - - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - // If we had a soft signal, we need to update the thread first so it can - // continue without signaling - int soft_signal = state.SoftSignal(); - if (soft_signal) { - int state_pid = -1; - if (inferior_task == state.task_port) { - // This is our task, so we can update the signal to send to it - state_pid = inferior_pid; - soft_signal = signal; - } else { - auto mach_err = ::pid_for_task(state.task_port, &state_pid); - if (mach_err) { - error.SetError(mach_err, eErrorTypeMachKernel); - LLDB_LOGF(log, - "MachException::Message::%s(): pid_for_task() " - "failed: %s", - __FUNCTION__, error.AsCString()); - return error; - } - } - - lldbassert(state_pid != -1); - if (state_pid != -1) { - errno = 0; - caddr_t thread_port_caddr = (caddr_t)(uintptr_t)state.thread_port; - if (::ptrace(PT_THUPDATE, state_pid, thread_port_caddr, soft_signal) != 0) - error.SetError(errno, eErrorTypePOSIX); - - if (!error.Success()) { - LLDB_LOGF(log, - "::ptrace(request = PT_THUPDATE, pid = " - "0x%4.4x, tid = 0x%4.4x, signal = %i)", - state_pid, state.thread_port, soft_signal); - return error; - } - } - } - - LLDB_LOGF(log, - "::mach_msg ( msg->{bits = %#x, size = %u, remote_port " - "= %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, " - "option = %#x, send_size = %u, rcv_size = %u, rcv_name " - "= %#x, timeout = %u, notify = %#x)", - reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, - reply_msg.hdr.msgh_remote_port, reply_msg.hdr.msgh_local_port, - reply_msg.hdr.msgh_reserved, reply_msg.hdr.msgh_id, - MACH_SEND_MSG | MACH_SEND_INTERRUPT, reply_msg.hdr.msgh_size, 0, - MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - - auto mach_err = - ::mach_msg(&reply_msg.hdr, MACH_SEND_MSG | MACH_SEND_INTERRUPT, - reply_msg.hdr.msgh_size, 0, MACH_PORT_NULL, - MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (mach_err) - error.SetError(mach_err, eErrorTypeMachKernel); - - // Log our error if we have one. - if (error.Fail() && log) { - if (error.GetError() == MACH_SEND_INTERRUPTED) { - log->PutCString("::mach_msg() - send interrupted"); - // TODO: keep retrying to reply??? - } else if (state.task_port == inferior_task) { - LLDB_LOGF(log, - "mach_msg(): returned an error when replying " - "to a mach exception: error = %u (%s)", - error.GetError(), error.AsCString()); - } else { - LLDB_LOGF(log, "::mach_msg() - failed (child of task): %u (%s)", - error.GetError(), error.AsCString()); - } - } - - return error; -} - -#define PREV_EXC_MASK_ALL \ - (EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | \ - EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | \ - EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | \ - EXC_MASK_MACHINE) - -// Don't listen for EXC_RESOURCE, it should really get handled by the system -// handler. - -#ifndef EXC_RESOURCE -#define EXC_RESOURCE 11 -#endif - -#ifndef EXC_MASK_RESOURCE -#define EXC_MASK_RESOURCE (1 << EXC_RESOURCE) -#endif - -#define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE) - -Status MachException::PortInfo::Save(task_t task) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - LLDB_LOGF(log, "MachException::PortInfo::%s(task = 0x%4.4x)", __FUNCTION__, - task); - - // Be careful to be able to have debugserver built on a newer OS than what it - // is currently running on by being able to start with all exceptions and - // back off to just what is supported on the current system - mask = LLDB_EXC_MASK; - - count = (sizeof(ports) / sizeof(ports[0])); - auto mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports, - behaviors, flavors); - if (mach_err) - error.SetError(mach_err, eErrorTypeMachKernel); - - if (log) { - if (error.Success()) { - LLDB_LOGF(log, - "::task_get_exception_ports(task = 0x%4.4x, mask = " - "0x%x, maskCnt => %u, ports, behaviors, flavors)", - task, mask, count); - } else { - LLDB_LOGF(log, - "::task_get_exception_ports(task = 0x%4.4x, mask = 0x%x, " - "maskCnt => %u, ports, behaviors, flavors) error: %u (%s)", - task, mask, count, error.GetError(), error.AsCString()); - } - } - - if ((error.GetError() == KERN_INVALID_ARGUMENT) && - (mask != PREV_EXC_MASK_ALL)) { - mask = PREV_EXC_MASK_ALL; - count = (sizeof(ports) / sizeof(ports[0])); - mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports, - behaviors, flavors); - error.SetError(mach_err, eErrorTypeMachKernel); - if (log) { - if (error.Success()) { - LLDB_LOGF(log, - "::task_get_exception_ports(task = 0x%4.4x, " - "mask = 0x%x, maskCnt => %u, ports, behaviors, " - "flavors)", - task, mask, count); - } else { - LLDB_LOGF(log, - "::task_get_exception_ports(task = 0x%4.4x, mask = " - "0x%x, maskCnt => %u, ports, behaviors, flavors) " - "error: %u (%s)", - task, mask, count, error.GetError(), error.AsCString()); - } - } - } - if (error.Fail()) { - mask = 0; - count = 0; - } - return error; -} - -Status MachException::PortInfo::Restore(task_t task) { - Status error; - - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - LLDB_LOGF(log, "MachException::PortInfo::Restore(task = 0x%4.4x)", task); - - uint32_t i = 0; - if (count > 0) { - for (i = 0; i < count; i++) { - auto mach_err = ::task_set_exception_ports(task, masks[i], ports[i], - behaviors[i], flavors[i]); - if (mach_err) - error.SetError(mach_err, eErrorTypeMachKernel); - if (log) { - if (error.Success()) { - LLDB_LOGF(log, - "::task_set_exception_ports(task = 0x%4.4x, " - "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " - "behavior = 0x%8.8x, new_flavor = 0x%8.8x)", - task, masks[i], ports[i], behaviors[i], flavors[i]); - } else { - LLDB_LOGF(log, - "::task_set_exception_ports(task = 0x%4.4x, " - "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " - "behavior = 0x%8.8x, new_flavor = 0x%8.8x): " - "error %u (%s)", - task, masks[i], ports[i], behaviors[i], flavors[i], - error.GetError(), error.AsCString()); - } - } - - // Bail if we encounter any errors - if (error.Fail()) - break; - } - } - - count = 0; - return error; -} - -const char *MachException::Name(exception_type_t exc_type) { - switch (exc_type) { - case EXC_BAD_ACCESS: - return "EXC_BAD_ACCESS"; - case EXC_BAD_INSTRUCTION: - return "EXC_BAD_INSTRUCTION"; - case EXC_ARITHMETIC: - return "EXC_ARITHMETIC"; - case EXC_EMULATION: - return "EXC_EMULATION"; - case EXC_SOFTWARE: - return "EXC_SOFTWARE"; - case EXC_BREAKPOINT: - return "EXC_BREAKPOINT"; - case EXC_SYSCALL: - return "EXC_SYSCALL"; - case EXC_MACH_SYSCALL: - return "EXC_MACH_SYSCALL"; - case EXC_RPC_ALERT: - return "EXC_RPC_ALERT"; -#ifdef EXC_CRASH - case EXC_CRASH: - return "EXC_CRASH"; -#endif - default: - break; - } - return NULL; -} diff --git a/lldb/source/Plugins/Process/Darwin/MachException.h b/lldb/source/Plugins/Process/Darwin/MachException.h deleted file mode 100644 index 18e49173b020..000000000000 --- a/lldb/source/Plugins/Process/Darwin/MachException.h +++ /dev/null @@ -1,139 +0,0 @@ -//===-- MachException.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/18/07. -// -//===----------------------------------------------------------------------===// - -#ifndef __MachException_h__ -#define __MachException_h__ - -#include <mach/mach.h> -#include <vector> - -#include "lldb/Host/Debug.h" -#include "lldb/lldb-private-forward.h" -#include "lldb/lldb-types.h" - -namespace lldb_private { -namespace process_darwin { - -typedef union MachMessageTag { - mach_msg_header_t hdr; - char data[1024]; -} MachMessage; - -class MachException { -public: - struct PortInfo { - exception_mask_t mask; // the exception mask for this device which may be a - // subset of EXC_MASK_ALL... - exception_mask_t masks[EXC_TYPES_COUNT]; - mach_port_t ports[EXC_TYPES_COUNT]; - exception_behavior_t behaviors[EXC_TYPES_COUNT]; - thread_state_flavor_t flavors[EXC_TYPES_COUNT]; - mach_msg_type_number_t count; - - Status Save(task_t task); - - Status Restore(task_t task); - }; - - struct Data { - task_t task_port; - thread_t thread_port; - exception_type_t exc_type; - std::vector<mach_exception_data_type_t> exc_data; - Data() - : task_port(TASK_NULL), thread_port(THREAD_NULL), exc_type(0), - exc_data() {} - - void Clear() { - task_port = TASK_NULL; - thread_port = THREAD_NULL; - exc_type = 0; - exc_data.clear(); - } - - bool IsValid() const { - return task_port != TASK_NULL && thread_port != THREAD_NULL && - exc_type != 0; - } - - // Return the SoftSignal for this MachException data, or zero if there is - // none - int SoftSignal() const { - if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && - exc_data[0] == EXC_SOFT_SIGNAL) - return static_cast<int>(exc_data[1]); - return 0; - } - - bool IsBreakpoint() const { - return (exc_type == EXC_BREAKPOINT || - ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1)); - } - - bool GetStopInfo(ThreadStopInfo *stop_info, const UnixSignals &signals, - Stream &stream) const; - }; - - struct Message { - MachMessage exc_msg; - MachMessage reply_msg; - Data state; - - Message() : state() { - memset(&exc_msg, 0, sizeof(exc_msg)); - memset(&reply_msg, 0, sizeof(reply_msg)); - } - - bool CatchExceptionRaise(task_t task); - - Status Reply(::pid_t inferior_pid, task_t inferior_task, int signal); - - Status Receive(mach_port_t receive_port, mach_msg_option_t options, - mach_msg_timeout_t timeout, - mach_port_t notify_port = MACH_PORT_NULL); - - void Dump(Stream &stream) const; - - typedef std::vector<Message> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - }; - - enum { - e_actionForward, // Forward signal to inferior process - e_actionStop, // Stop when this signal is received - }; - struct Action { - task_t task_port; // Set to TASK_NULL for any TASK - thread_t thread_port; // Set to THREAD_NULL for any thread - exception_type_t exc_mask; // Mach exception mask to watch for - std::vector<mach_exception_data_type_t> exc_data_mask; // Mask to apply to - // exception data, or - // empty to ignore - // exc_data value for - // exception - std::vector<mach_exception_data_type_t> exc_data_value; // Value to compare - // to exception data - // after masking, or - // empty to ignore - // exc_data value - // for exception - uint8_t flags; // Action flags describing what to do with the exception - }; - - static const char *Name(exception_type_t exc_type); -}; - -} // namespace process_darwin -} // namespace lldb_private - -#endif diff --git a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp deleted file mode 100644 index 18dbdda9a33b..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp +++ /dev/null @@ -1,1535 +0,0 @@ -//===-- NativeProcessDarwin.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 "NativeProcessDarwin.h" - -// C includes -#include <mach/mach_init.h> -#include <mach/mach_traps.h> -#include <sys/ptrace.h> -#include <sys/stat.h> -#include <sys/sysctl.h> -#include <sys/types.h> - -// C++ includes -// LLDB includes -#include "lldb/Host/PseudoTerminal.h" -#include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/State.h" -#include "lldb/Utility/StreamString.h" - -#include "CFBundle.h" -#include "CFString.h" -#include "DarwinProcessLauncher.h" - -#include "MachException.h" - -#include "llvm/Support/FileSystem.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; -using namespace lldb_private::darwin_process_launcher; - -// Hidden Impl - -namespace { -struct hack_task_dyld_info { - mach_vm_address_t all_image_info_addr; - mach_vm_size_t all_image_info_size; -}; -} - -// Public Static Methods - -Status NativeProcessProtocol::Launch( - ProcessLaunchInfo &launch_info, - NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop, - NativeProcessProtocolSP &native_process_sp) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - Status error; - - // Verify the working directory is valid if one was specified. - FileSpec working_dir(launch_info.GetWorkingDirectory()); - if (working_dir) { - FileInstance::Instance().Resolve(working_dir); - if (!FileSystem::Instance().IsDirectory(working_dir)) { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return error; - } - } - - // Launch the inferior. - int pty_master_fd = -1; - LaunchFlavor launch_flavor = LaunchFlavor::Default; - - error = LaunchInferior(launch_info, &pty_master_fd, &launch_flavor); - - // Handle launch failure. - if (!error.Success()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() failed to launch process: " - "%s", - __FUNCTION__, error.AsCString()); - return error; - } - - // Handle failure to return a pid. - if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() launch succeeded but no " - "pid was returned! Aborting.", - __FUNCTION__); - return error; - } - - // Create the Darwin native process impl. - std::shared_ptr<NativeProcessDarwin> np_darwin_sp( - new NativeProcessDarwin(launch_info.GetProcessID(), pty_master_fd)); - if (!np_darwin_sp->RegisterNativeDelegate(native_delegate)) { - native_process_sp.reset(); - error.SetErrorStringWithFormat("failed to register the native delegate"); - return error; - } - - // Finalize the processing needed to debug the launched process with a - // NativeProcessDarwin instance. - error = np_darwin_sp->FinalizeLaunch(launch_flavor, mainloop); - if (!error.Success()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() aborting, failed to finalize" - " the launching of the process: %s", - __FUNCTION__, error.AsCString()); - return error; - } - - // Return the process and process id to the caller through the launch args. - native_process_sp = np_darwin_sp; - return error; -} - -Status NativeProcessProtocol::Attach( - lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - LLDB_LOGF(log, "NativeProcessDarwin::%s(pid = %" PRIi64 ")", __FUNCTION__, - pid); - - // Retrieve the architecture for the running process. - ArchSpec process_arch; - Status error = ResolveProcessArchitecture(pid, process_arch); - if (!error.Success()) - return error; - - // TODO get attach to return this value. - const int pty_master_fd = -1; - std::shared_ptr<NativeProcessDarwin> native_process_darwin_sp( - new NativeProcessDarwin(pid, pty_master_fd)); - - if (!native_process_darwin_sp->RegisterNativeDelegate(native_delegate)) { - error.SetErrorStringWithFormat("failed to register the native " - "delegate"); - return error; - } - - native_process_darwin_sp->AttachToInferior(mainloop, pid, error); - if (!error.Success()) - return error; - - native_process_sp = native_process_darwin_sp; - return error; -} - -// ctor/dtor - -NativeProcessDarwin::NativeProcessDarwin(lldb::pid_t pid, int pty_master_fd) - : NativeProcessProtocol(pid), m_task(TASK_NULL), m_did_exec(false), - m_cpu_type(0), m_exception_port(MACH_PORT_NULL), m_exc_port_info(), - m_exception_thread(nullptr), m_exception_messages_mutex(), - m_sent_interrupt_signo(0), m_auto_resume_signo(0), m_thread_list(), - m_thread_actions(), m_waitpid_pipe(), m_waitpid_thread(nullptr), - m_waitpid_reader_handle() { - // TODO add this to the NativeProcessProtocol constructor. - m_terminal_fd = pty_master_fd; -} - -NativeProcessDarwin::~NativeProcessDarwin() {} - -// Instance methods - -Status NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor, - MainLoop &main_loop) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - error = StartExceptionThread(); - if (!error.Success()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failure starting the " - "mach exception port monitor thread: %s", - __FUNCTION__, error.AsCString()); - - // Terminate the inferior process. There's nothing meaningful we can do if - // we can't receive signals and exceptions. Since we launched the process, - // it's fair game for us to kill it. - ::ptrace(PT_KILL, m_pid, 0, 0); - SetState(eStateExited); - - return error; - } - - StartSTDIOThread(); - - if (launch_flavor == LaunchFlavor::PosixSpawn) { - SetState(eStateAttaching); - errno = 0; - int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); - if (err == 0) { - // m_flags |= eMachProcessFlagsAttached; - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): successfully spawned " - "process with pid %" PRIu64, - __FUNCTION__, m_pid); - } else { - error.SetErrorToErrno(); - SetState(eStateExited); - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): error: failed to " - "attach to spawned pid %" PRIu64 " (error=%d (%s))", - __FUNCTION__, m_pid, (int)error.GetError(), error.AsCString()); - return error; - } - } - - LLDB_LOGF(log, "NativeProcessDarwin::%s(): new pid is %" PRIu64 "...", - __FUNCTION__, m_pid); - - // Spawn a thread to reap our child inferior process... - error = StartWaitpidThread(main_loop); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to start waitpid() " - "thread: %s", - __FUNCTION__, error.AsCString()); - kill(SIGKILL, static_cast<::pid_t>(m_pid)); - return error; - } - - if (TaskPortForProcessID(error) == TASK_NULL) { - // We failed to get the task for our process ID which is bad. Kill our - // process; otherwise, it will be stopped at the entry point and get - // reparented to someone else and never go away. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): could not get task port " - "for process, sending SIGKILL and exiting: %s", - __FUNCTION__, error.AsCString()); - kill(SIGKILL, static_cast<::pid_t>(m_pid)); - return error; - } - - // Indicate that we're stopped, as we always launch suspended. - SetState(eStateStopped); - - // Success. - return error; -} - -Status NativeProcessDarwin::SaveExceptionPortInfo() { - return m_exc_port_info.Save(m_task); -} - -bool NativeProcessDarwin::ProcessUsingSpringBoard() const { - // TODO implement flags - // return (m_flags & eMachProcessFlagsUsingSBS) != 0; - return false; -} - -bool NativeProcessDarwin::ProcessUsingBackBoard() const { - // TODO implement flags - // return (m_flags & eMachProcessFlagsUsingBKS) != 0; - return false; -} - -// Called by the exception thread when an exception has been received from our -// process. The exception message is completely filled and the exception data -// has already been copied. -void NativeProcessDarwin::ExceptionMessageReceived( - const MachException::Message &message) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex); - if (m_exception_messages.empty()) { - // Suspend the task the moment we receive our first exception message. - SuspendTask(); - } - - // Use a locker to automatically unlock our mutex in case of exceptions Add - // the exception to our internal exception stack - m_exception_messages.push_back(message); - - LLDB_LOGF(log, "NativeProcessDarwin::%s(): new queued message count: %lu", - __FUNCTION__, m_exception_messages.size()); -} - -void *NativeProcessDarwin::ExceptionThread(void *arg) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (!arg) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): cannot run mach exception " - "thread, mandatory process arg was null", - __FUNCTION__); - return nullptr; - } - - return reinterpret_cast<NativeProcessDarwin *>(arg)->DoExceptionThread(); -} - -void *NativeProcessDarwin::DoExceptionThread() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - LLDB_LOGF(log, "NativeProcessDarwin::%s(arg=%p) starting thread...", - __FUNCTION__, this); - - pthread_setname_np("exception monitoring thread"); - - // Ensure we don't get CPU starved. - MaybeRaiseThreadPriority(); - - // We keep a count of the number of consecutive exceptions received so we - // know to grab all exceptions without a timeout. We do this to get a bunch - // of related exceptions on our exception port so we can process then - // together. When we have multiple threads, we can get an exception per - // thread and they will come in consecutively. The main loop in this thread - // can stop periodically if needed to service things related to this process. - // - // [did we lose some words here?] - // - // flag set in the options, so we will wait forever for an exception on - // 0 our exception port. After we get one exception, we then will use the - // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current - // exceptions for our process. After we have received the last pending - // exception, we will get a timeout which enables us to then notify our main - // thread that we have an exception bundle available. We then wait for the - // main thread to tell this exception thread to start trying to get - // exceptions messages again and we start again with a mach_msg read with - // infinite timeout. - // - // We choose to park a thread on this, rather than polling, because the - // polling is expensive. On devices, we need to minimize overhead caused by - // the process monitor. - uint32_t num_exceptions_received = 0; - Status error; - task_t task = m_task; - mach_msg_timeout_t periodic_timeout = 0; - -#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) - mach_msg_timeout_t watchdog_elapsed = 0; - mach_msg_timeout_t watchdog_timeout = 60 * 1000; - ::pid_t pid = (::pid_t)process->GetID(); - CFReleaser<SBSWatchdogAssertionRef> watchdog; - - if (process->ProcessUsingSpringBoard()) { - // Request a renewal for every 60 seconds if we attached using SpringBoard. - watchdog.reset(::SBSWatchdogAssertionCreateForPID(nullptr, pid, 60)); - LLDB_LOGF(log, - "::SBSWatchdogAssertionCreateForPID(NULL, %4.4x, 60) " - "=> %p", - pid, watchdog.get()); - - if (watchdog.get()) { - ::SBSWatchdogAssertionRenew(watchdog.get()); - - CFTimeInterval watchdogRenewalInterval = - ::SBSWatchdogAssertionGetRenewalInterval(watchdog.get()); - LLDB_LOGF(log, - "::SBSWatchdogAssertionGetRenewalInterval(%p) => " - "%g seconds", - watchdog.get(), watchdogRenewalInterval); - if (watchdogRenewalInterval > 0.0) { - watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000; - if (watchdog_timeout > 3000) { - // Give us a second to renew our timeout. - watchdog_timeout -= 1000; - } else if (watchdog_timeout > 1000) { - // Give us a quarter of a second to renew our timeout. - watchdog_timeout -= 250; - } - } - } - if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout) - periodic_timeout = watchdog_timeout; - } -#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - -#ifdef WITH_BKS - CFReleaser<BKSWatchdogAssertionRef> watchdog; - if (process->ProcessUsingBackBoard()) { - ::pid_t pid = process->GetID(); - CFAllocatorRef alloc = kCFAllocatorDefault; - watchdog.reset(::BKSWatchdogAssertionCreateForPID(alloc, pid)); - } -#endif // #ifdef WITH_BKS - - // Do we want to use a weak pointer to the NativeProcessDarwin here, in which - // case we can guarantee we don't whack the process monitor if we race - // between this thread and the main one on shutdown? - while (IsExceptionPortValid()) { - ::pthread_testcancel(); - - MachException::Message exception_message; - - if (num_exceptions_received > 0) { - // We don't want a timeout here, just receive as many exceptions as we - // can since we already have one. We want to get all currently available - // exceptions for this task at once. - error = exception_message.Receive( - GetExceptionPort(), - MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0); - } else if (periodic_timeout > 0) { - // We need to stop periodically in this loop, so try and get a mach - // message with a valid timeout (ms). - error = exception_message.Receive(GetExceptionPort(), - MACH_RCV_MSG | MACH_RCV_INTERRUPT | - MACH_RCV_TIMEOUT, - periodic_timeout); - } else { - // We don't need to parse all current exceptions or stop periodically, - // just wait for an exception forever. - error = exception_message.Receive(GetExceptionPort(), - MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0); - } - - if (error.Success()) { - // We successfully received an exception. - if (exception_message.CatchExceptionRaise(task)) { - ++num_exceptions_received; - ExceptionMessageReceived(exception_message); - } - } else { - if (error.GetError() == MACH_RCV_INTERRUPTED) { - // We were interrupted. - - // If we have no task port we should exit this thread, as it implies - // the inferior went down. - if (!IsExceptionPortValid()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): the inferior " - "exception port is no longer valid, " - "canceling exception thread...", - __FUNCTION__); - // Should we be setting a process state here? - break; - } - - // Make sure the inferior task is still valid. - if (IsTaskValid()) { - // Task is still ok. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): interrupted, but " - "the inferior task iss till valid, " - "continuing...", - __FUNCTION__); - continue; - } else { - // The inferior task is no longer valid. Time to exit as the process - // has gone away. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): the inferior task " - "has exited, and so will we...", - __FUNCTION__); - // Does this race at all with our waitpid()? - SetState(eStateExited); - break; - } - } else if (error.GetError() == MACH_RCV_TIMED_OUT) { - // We timed out when waiting for exceptions. - - if (num_exceptions_received > 0) { - // We were receiving all current exceptions with a timeout of zero. - // It is time to go back to our normal looping mode. - num_exceptions_received = 0; - - // Notify our main thread we have a complete exception message bundle - // available. Get the possibly updated task port back from the - // process in case we exec'ed and our task port changed. - task = ExceptionMessageBundleComplete(); - - // In case we use a timeout value when getting exceptions, make sure - // our task is still valid. - if (IsTaskValid(task)) { - // Task is still ok. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): got a timeout, " - "continuing...", - __FUNCTION__); - continue; - } else { - // The inferior task is no longer valid. Time to exit as the - // process has gone away. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): the inferior " - "task has exited, and so will we...", - __FUNCTION__); - // Does this race at all with our waitpid()? - SetState(eStateExited); - break; - } - } - -#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) - if (watchdog.get()) { - watchdog_elapsed += periodic_timeout; - if (watchdog_elapsed >= watchdog_timeout) { - LLDB_LOGF(log, "SBSWatchdogAssertionRenew(%p)", watchdog.get()); - ::SBSWatchdogAssertionRenew(watchdog.get()); - watchdog_elapsed = 0; - } - } -#endif - } else { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): continuing after " - "receiving an unexpected error: %u (%s)", - __FUNCTION__, error.GetError(), error.AsCString()); - // TODO: notify of error? - } - } - } - -#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) - if (watchdog.get()) { - // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel - // when we - // all are up and running on systems that support it. The SBS framework has - // a #define that will forward SBSWatchdogAssertionRelease to - // SBSWatchdogAssertionCancel for now so it should still build either way. - DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", - watchdog.get()); - ::SBSWatchdogAssertionRelease(watchdog.get()); - } -#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - - LLDB_LOGF(log, "NativeProcessDarwin::%s(%p): thread exiting...", __FUNCTION__, - this); - return nullptr; -} - -Status NativeProcessDarwin::StartExceptionThread() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - LLDB_LOGF(log, "NativeProcessDarwin::%s() called", __FUNCTION__); - - // Make sure we've looked up the inferior port. - TaskPortForProcessID(error); - - // Ensure the inferior task is valid. - if (!IsTaskValid()) { - error.SetErrorStringWithFormat("cannot start exception thread: " - "task 0x%4.4x is not valid", - m_task); - return error; - } - - // Get the mach port for the process monitor. - mach_port_t task_self = mach_task_self(); - - // Allocate an exception port that we will use to track our child process - auto mach_err = ::mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, - &m_exception_port); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): mach_port_allocate(" - "task_self=0x%4.4x, MACH_PORT_RIGHT_RECEIVE, " - "&m_exception_port) failed: %u (%s)", - __FUNCTION__, task_self, error.GetError(), error.AsCString()); - return error; - } - - // Add the ability to send messages on the new exception port - mach_err = ::mach_port_insert_right( - task_self, m_exception_port, m_exception_port, MACH_MSG_TYPE_MAKE_SEND); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): mach_port_insert_right(" - "task_self=0x%4.4x, m_exception_port=0x%4.4x, " - "m_exception_port=0x%4.4x, MACH_MSG_TYPE_MAKE_SEND) " - "failed: %u (%s)", - __FUNCTION__, task_self, m_exception_port, m_exception_port, - error.GetError(), error.AsCString()); - return error; - } - - // Save the original state of the exception ports for our child process. - error = SaveExceptionPortInfo(); - if (error.Fail() || (m_exc_port_info.mask == 0)) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): SaveExceptionPortInfo() " - "failed, cannot install exception handler: %s", - __FUNCTION__, error.AsCString()); - return error; - } - - // Set the ability to get all exceptions on this port. - mach_err = ::task_set_exception_ports( - m_task, m_exc_port_info.mask, m_exception_port, - EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "::task_set_exception_ports (task = 0x%4.4x, " - "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " - "behavior = 0x%8.8x, new_flavor = 0x%8.8x) failed: " - "%u (%s)", - m_task, m_exc_port_info.mask, m_exception_port, - (EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES), THREAD_STATE_NONE, - error.GetError(), error.AsCString()); - return error; - } - - // Create the exception thread. - auto pthread_err = - ::pthread_create(&m_exception_thread, nullptr, ExceptionThread, this); - error.SetError(pthread_err, eErrorTypePOSIX); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to create Mach " - "exception-handling thread: %u (%s)", - __FUNCTION__, error.GetError(), error.AsCString()); - } - - return error; -} - -lldb::addr_t -NativeProcessDarwin::GetDYLDAllImageInfosAddress(Status &error) const { - error.Clear(); - - struct hack_task_dyld_info dyld_info; - mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; - // Make sure that COUNT isn't bigger than our hacked up struct - // hack_task_dyld_info. If it is, then make COUNT smaller to match. - if (count > (sizeof(struct hack_task_dyld_info) / sizeof(natural_t))) { - count = (sizeof(struct hack_task_dyld_info) / sizeof(natural_t)); - } - - TaskPortForProcessID(error); - if (error.Fail()) - return LLDB_INVALID_ADDRESS; - - auto mach_err = - ::task_info(m_task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Success()) { - // We now have the address of the all image infos structure. - return dyld_info.all_image_info_addr; - } - - // We don't have it. - return LLDB_INVALID_ADDRESS; -} - -uint32_t NativeProcessDarwin::GetCPUTypeForLocalProcess(::pid_t pid) { - int mib[CTL_MAXNAME] = { - 0, - }; - size_t len = CTL_MAXNAME; - - if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) - return 0; - - mib[len] = pid; - len++; - - cpu_type_t cpu; - size_t cpu_len = sizeof(cpu); - if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) - cpu = 0; - return cpu; -} - -uint32_t NativeProcessDarwin::GetCPUType() const { - if (m_cpu_type == 0 && m_pid != 0) - m_cpu_type = GetCPUTypeForLocalProcess(m_pid); - return m_cpu_type; -} - -task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { - // We have a complete bundle of exceptions for our child process. - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex); - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): processing %lu exception " - "messages.", - __FUNCTION__, m_exception_messages.size()); - - if (m_exception_messages.empty()) { - // Not particularly useful... - return m_task; - } - - bool auto_resume = false; - m_did_exec = false; - - // First check for any SIGTRAP and make sure we didn't exec - const task_t task = m_task; - size_t i; - if (m_pid != 0) { - bool received_interrupt = false; - uint32_t num_task_exceptions = 0; - for (i = 0; i < m_exception_messages.size(); ++i) { - if (m_exception_messages[i].state.task_port != task) { - // This is an exception that is not for our inferior, ignore. - continue; - } - - // This is an exception for the inferior. - ++num_task_exceptions; - const int signo = m_exception_messages[i].state.SoftSignal(); - if (signo == SIGTRAP) { - // SIGTRAP could mean that we exec'ed. We need to check the - // dyld all_image_infos.infoArray to see if it is NULL and if so, say - // that we exec'ed. - const addr_t aii_addr = GetDYLDAllImageInfosAddress(error); - if (aii_addr == LLDB_INVALID_ADDRESS) - break; - - const addr_t info_array_count_addr = aii_addr + 4; - uint32_t info_array_count = 0; - size_t bytes_read = 0; - Status read_error; - read_error = ReadMemory(info_array_count_addr, // source addr - &info_array_count, // dest addr - 4, // byte count - bytes_read); // #bytes read - if (read_error.Success() && (bytes_read == 4)) { - if (info_array_count == 0) { - // We got the all infos address, and there are zero entries. We - // think we exec'd. - m_did_exec = true; - - // Force the task port to update itself in case the task port - // changed after exec - const task_t old_task = m_task; - const bool force_update = true; - const task_t new_task = TaskPortForProcessID(error, force_update); - if (old_task != new_task) { - LLDB_LOGF(log, - "exec: inferior task port changed " - "from 0x%4.4x to 0x%4.4x", - old_task, new_task); - } - } - } else { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() warning: " - "failed to read all_image_infos." - "infoArrayCount from 0x%8.8llx", - __FUNCTION__, info_array_count_addr); - } - } else if ((m_sent_interrupt_signo != 0) && - (signo == m_sent_interrupt_signo)) { - // We just received the interrupt that we sent to ourselves. - received_interrupt = true; - } - } - - if (m_did_exec) { - cpu_type_t process_cpu_type = GetCPUTypeForLocalProcess(m_pid); - if (m_cpu_type != process_cpu_type) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): arch changed from " - "0x%8.8x to 0x%8.8x", - __FUNCTION__, m_cpu_type, process_cpu_type); - m_cpu_type = process_cpu_type; - // TODO figure out if we need to do something here. - // DNBArchProtocol::SetArchitecture (process_cpu_type); - } - m_thread_list.Clear(); - - // TODO hook up breakpoints. - // m_breakpoints.DisableAll(); - } - - if (m_sent_interrupt_signo != 0) { - if (received_interrupt) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): process " - "successfully interrupted with signal %i", - __FUNCTION__, m_sent_interrupt_signo); - - // Mark that we received the interrupt signal - m_sent_interrupt_signo = 0; - // Now check if we had a case where: - // 1 - We called NativeProcessDarwin::Interrupt() but we stopped - // for another reason. - // 2 - We called NativeProcessDarwin::Resume() (but still - // haven't gotten the interrupt signal). - // 3 - We are now incorrectly stopped because we are handling - // the interrupt signal we missed. - // 4 - We might need to resume if we stopped only with the - // interrupt signal that we never handled. - if (m_auto_resume_signo != 0) { - // Only auto_resume if we stopped with _only_ the interrupt signal. - if (num_task_exceptions == 1) { - auto_resume = true; - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): auto " - "resuming due to unhandled interrupt " - "signal %i", - __FUNCTION__, m_auto_resume_signo); - } - m_auto_resume_signo = 0; - } - } else { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): didn't get signal " - "%i after MachProcess::Interrupt()", - __FUNCTION__, m_sent_interrupt_signo); - } - } - } - - // Let all threads recover from stopping and do any clean up based on the - // previous thread state (if any). - m_thread_list.ProcessDidStop(*this); - - // Let each thread know of any exceptions - for (i = 0; i < m_exception_messages.size(); ++i) { - // Let the thread list forward all exceptions on down to each thread. - if (m_exception_messages[i].state.task_port == task) { - // This exception is for our inferior. - m_thread_list.NotifyException(m_exception_messages[i].state); - } - - if (log) { - StreamString stream; - m_exception_messages[i].Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - } - - if (log) { - StreamString stream; - m_thread_list.Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - - bool step_more = false; - if (m_thread_list.ShouldStop(step_more) && (auto_resume == false)) { -// TODO - need to hook up event system here. !!!! -#if 0 - // Wait for the eEventProcessRunningStateChanged event to be reset - // before changing state to stopped to avoid race condition with very - // fast start/stops. - struct timespec timeout; - - //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms - DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms - m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, - &timeout); -#endif - SetState(eStateStopped); - } else { - // Resume without checking our current state. - PrivateResume(); - } - - return m_task; -} - -void NativeProcessDarwin::StartSTDIOThread() { - // TODO implement -} - -Status NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Strategy: create a thread that sits on waitpid(), waiting for the inferior - // process to die, reaping it in the process. Arrange for the thread to have - // a pipe file descriptor that it can send a byte over when the waitpid - // completes. Have the main loop have a read object for the other side of - // the pipe, and have the callback for the read do the process termination - // message sending. - - // Create a single-direction communication channel. - const bool child_inherits = false; - error = m_waitpid_pipe.CreateNew(child_inherits); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to create waitpid " - "communication pipe: %s", - __FUNCTION__, error.AsCString()); - return error; - } - - // Hook up the waitpid reader callback. - - // TODO make PipePOSIX derive from IOObject. This is goofy here. - const bool transfer_ownership = false; - auto io_sp = IOObjectSP(new NativeFile(m_waitpid_pipe.GetReadFileDescriptor(), - transfer_ownership)); - m_waitpid_reader_handle = main_loop.RegisterReadObject( - io_sp, [this](MainLoopBase &) { HandleWaitpidResult(); }, error); - - // Create the thread. - auto pthread_err = - ::pthread_create(&m_waitpid_thread, nullptr, WaitpidThread, this); - error.SetError(pthread_err, eErrorTypePOSIX); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to create waitpid " - "handling thread: %u (%s)", - __FUNCTION__, error.GetError(), error.AsCString()); - return error; - } - - return error; -} - -void *NativeProcessDarwin::WaitpidThread(void *arg) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!arg) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): cannot run waitpid " - "thread, mandatory process arg was null", - __FUNCTION__); - return nullptr; - } - - return reinterpret_cast<NativeProcessDarwin *>(arg)->DoWaitpidThread(); -} - -void NativeProcessDarwin::MaybeRaiseThreadPriority() { -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, - &thread_param) == 0) { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } -#endif -} - -void *NativeProcessDarwin::DoWaitpidThread() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (m_pid == LLDB_INVALID_PROCESS_ID) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): inferior process ID is " - "not set, cannot waitpid on it", - __FUNCTION__); - return nullptr; - } - - // Name the thread. - pthread_setname_np("waitpid thread"); - - // Ensure we don't get CPU starved. - MaybeRaiseThreadPriority(); - - Status error; - int status = -1; - - while (1) { - // Do a waitpid. - ::pid_t child_pid = ::waitpid(m_pid, &status, 0); - if (child_pid < 0) - error.SetErrorToErrno(); - if (error.Fail()) { - if (error.GetError() == EINTR) { - // This is okay, we can keep going. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ", &status, 0) interrupted, continuing", - __FUNCTION__, m_pid); - continue; - } - - // This error is not okay, abort. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ", &status, 0) aborting due to error: %u (%s)", - __FUNCTION__, m_pid, error.GetError(), error.AsCString()); - break; - } - - // Log the successful result. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ", &status, 0) => %i, status = %i", - __FUNCTION__, m_pid, child_pid, status); - - // Handle the result. - if (WIFSTOPPED(status)) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ") received a stop, continuing waitpid() loop", - __FUNCTION__, m_pid); - continue; - } else // if (WIFEXITED(status) || WIFSIGNALED(status)) - { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(pid = %" PRIu64 "): " - "waitpid thread is setting exit status for pid = " - "%i to %i", - __FUNCTION__, m_pid, child_pid, status); - - error = SendInferiorExitStatusToMainLoop(child_pid, status); - return nullptr; - } - } - - // We should never exit as long as our child process is alive. If we get - // here, something completely unexpected went wrong and we should exit. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): internal error: waitpid thread " - "exited out of its main loop in an unexpected way. pid = %" PRIu64 - ". Sending exit status of -1.", - __FUNCTION__, m_pid); - - error = SendInferiorExitStatusToMainLoop((::pid_t)m_pid, -1); - return nullptr; -} - -Status NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid, - int status) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - size_t bytes_written = 0; - - // Send the pid. - error = m_waitpid_pipe.Write(&pid, sizeof(pid), bytes_written); - if (error.Fail() || (bytes_written < sizeof(pid))) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() - failed to write " - "waitpid exiting pid to the pipe. Client will not " - "hear about inferior exit status!", - __FUNCTION__); - return error; - } - - // Send the status. - bytes_written = 0; - error = m_waitpid_pipe.Write(&status, sizeof(status), bytes_written); - if (error.Fail() || (bytes_written < sizeof(status))) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() - failed to write " - "waitpid exit result to the pipe. Client will not " - "hear about inferior exit status!", - __FUNCTION__); - } - return error; -} - -Status NativeProcessDarwin::HandleWaitpidResult() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Read the pid. - const bool notify_status = true; - - ::pid_t pid = -1; - size_t bytes_read = 0; - error = m_waitpid_pipe.Read(&pid, sizeof(pid), bytes_read); - if (error.Fail() || (bytes_read < sizeof(pid))) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() - failed to read " - "waitpid exiting pid from the pipe. Will notify " - "as if parent process died with exit status -1.", - __FUNCTION__); - SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status); - return error; - } - - // Read the status. - int status = -1; - error = m_waitpid_pipe.Read(&status, sizeof(status), bytes_read); - if (error.Fail() || (bytes_read < sizeof(status))) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() - failed to read " - "waitpid exit status from the pipe. Will notify " - "as if parent process died with exit status -1.", - __FUNCTION__); - SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status); - return error; - } - - // Notify the monitor that our state has changed. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): main loop received waitpid " - "exit status info: pid=%i (%s), status=%i", - __FUNCTION__, pid, - (pid == m_pid) ? "the inferior" : "not the inferior", status); - - SetExitStatus(WaitStatus::Decode(status), notify_status); - return error; -} - -task_t NativeProcessDarwin::TaskPortForProcessID(Status &error, - bool force) const { - if ((m_task == TASK_NULL) || force) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (m_pid == LLDB_INVALID_PROCESS_ID) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): cannot get task due " - "to invalid pid", - __FUNCTION__); - return TASK_NULL; - } - - const uint32_t num_retries = 10; - const uint32_t usec_interval = 10000; - - mach_port_t task_self = mach_task_self(); - task_t task = TASK_NULL; - - for (uint32_t i = 0; i < num_retries; i++) { - kern_return_t err = ::task_for_pid(task_self, m_pid, &task); - if (err == 0) { - // Succeeded. Save and return it. - error.Clear(); - m_task = task; - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): ::task_for_pid(" - "stub_port = 0x%4.4x, pid = %llu, &task) " - "succeeded: inferior task port = 0x%4.4x", - __FUNCTION__, task_self, m_pid, m_task); - return m_task; - } else { - // Failed to get the task for the inferior process. - error.SetError(err, eErrorTypeMachKernel); - if (log) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): ::task_for_pid(" - "stub_port = 0x%4.4x, pid = %llu, &task) " - "failed, err = 0x%8.8x (%s)", - __FUNCTION__, task_self, m_pid, err, error.AsCString()); - } - } - - // Sleep a bit and try again - ::usleep(usec_interval); - } - - // We failed to get the task for the inferior process. Ensure that it is - // cleared out. - m_task = TASK_NULL; - } - return m_task; -} - -void NativeProcessDarwin::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, - Status &error) { - error.SetErrorString("TODO: implement"); -} - -Status NativeProcessDarwin::PrivateResume() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex); - m_auto_resume_signo = m_sent_interrupt_signo; - - if (log) { - if (m_auto_resume_signo) - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): task 0x%x resuming (with " - "unhandled interrupt signal %i)...", - __FUNCTION__, m_task, m_auto_resume_signo); - else - LLDB_LOGF(log, "NativeProcessDarwin::%s(): task 0x%x resuming...", - __FUNCTION__, m_task); - } - - error = ReplyToAllExceptions(); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): aborting, failed to " - "reply to exceptions: %s", - __FUNCTION__, error.AsCString()); - return error; - } - // bool stepOverBreakInstruction = step; - - // Let the thread prepare to resume and see if any threads want us to step - // over a breakpoint instruction (ProcessWillResume will modify the value of - // stepOverBreakInstruction). - m_thread_list.ProcessWillResume(*this, m_thread_actions); - - // Set our state accordingly - if (m_thread_actions.NumActionsWithState(eStateStepping)) - SetState(eStateStepping); - else - SetState(eStateRunning); - - // Now resume our task. - error = ResumeTask(); - return error; -} - -Status NativeProcessDarwin::ReplyToAllExceptions() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - TaskPortForProcessID(error); - if (error.Fail()) { - LLDB_LOGF(log, "NativeProcessDarwin::%s(): no task port, aborting", - __FUNCTION__); - return error; - } - - std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex); - if (m_exception_messages.empty()) { - // We're done. - return error; - } - - size_t index = 0; - for (auto &message : m_exception_messages) { - if (log) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): replying to exception " - "%zu...", - __FUNCTION__, index++); - } - - int thread_reply_signal = 0; - - const tid_t tid = - m_thread_list.GetThreadIDByMachPortNumber(message.state.thread_port); - const ResumeAction *action = nullptr; - if (tid != LLDB_INVALID_THREAD_ID) - action = m_thread_actions.GetActionForThread(tid, false); - - if (action) { - thread_reply_signal = action->signal; - if (thread_reply_signal) - m_thread_actions.SetSignalHandledForThread(tid); - } - - error = message.Reply(m_pid, m_task, thread_reply_signal); - if (error.Fail() && log) { - // We log any error here, but we don't stop the exception response - // handling. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to reply to " - "exception: %s", - __FUNCTION__, error.AsCString()); - error.Clear(); - } - } - - // Erase all exception message as we should have used and replied to them all - // already. - m_exception_messages.clear(); - return error; -} - -Status NativeProcessDarwin::ResumeTask() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - TaskPortForProcessID(error); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to get task port " - "for process when attempting to resume: %s", - __FUNCTION__, error.AsCString()); - return error; - } - if (m_task == TASK_NULL) { - error.SetErrorString("task port retrieval succeeded but task port is " - "null when attempting to resume the task"); - return error; - } - - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): requesting resume of task " - "0x%4.4x", - __FUNCTION__, m_task); - - // Get the BasicInfo struct to verify that we're suspended before we try to - // resume the task. - struct task_basic_info task_info; - error = GetTaskBasicInfo(m_task, &task_info); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to get task " - "BasicInfo when attempting to resume: %s", - __FUNCTION__, error.AsCString()); - return error; - } - - // task_resume isn't counted like task_suspend calls are, so if the task is - // not suspended, don't try and resume it since it is already running - if (task_info.suspend_count > 0) { - auto mach_err = ::task_resume(m_task); - error.SetError(mach_err, eErrorTypeMachKernel); - if (log) { - if (error.Success()) - LLDB_LOGF(log, "::task_resume(target_task = 0x%4.4x): success", m_task); - else - LLDB_LOGF(log, "::task_resume(target_task = 0x%4.4x) error: %s", m_task, - error.AsCString()); - } - } else { - LLDB_LOGF(log, - "::task_resume(target_task = 0x%4.4x): ignored, " - "already running", - m_task); - } - - return error; -} - -bool NativeProcessDarwin::IsTaskValid() const { - if (m_task == TASK_NULL) - return false; - - struct task_basic_info task_info; - return GetTaskBasicInfo(m_task, &task_info).Success(); -} - -bool NativeProcessDarwin::IsTaskValid(task_t task) const { - if (task == TASK_NULL) - return false; - - struct task_basic_info task_info; - return GetTaskBasicInfo(task, &task_info).Success(); -} - -mach_port_t NativeProcessDarwin::GetExceptionPort() const { - return m_exception_port; -} - -bool NativeProcessDarwin::IsExceptionPortValid() const { - return MACH_PORT_VALID(m_exception_port); -} - -Status -NativeProcessDarwin::GetTaskBasicInfo(task_t task, - struct task_basic_info *info) const { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Validate args. - if (info == NULL) { - error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): mandatory " - "info arg is null", - __FUNCTION__); - return error; - } - - // Grab the task if we don't already have it. - if (task == TASK_NULL) { - error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): given task " - "is invalid", - __FUNCTION__); - } - - mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; - auto err = ::task_info(m_task, TASK_BASIC_INFO, (task_info_t)info, &count); - error.SetError(err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "::task_info(target_task = 0x%4.4x, " - "flavor = TASK_BASIC_INFO, task_info_out => %p, " - "task_info_outCnt => %u) failed: %u (%s)", - m_task, info, count, error.GetError(), error.AsCString()); - return error; - } - - Log *verbose_log( - GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (verbose_log) { - float user = (float)info->user_time.seconds + - (float)info->user_time.microseconds / 1000000.0f; - float system = (float)info->user_time.seconds + - (float)info->user_time.microseconds / 1000000.0f; - verbose_LLDB_LOGF(log, - "task_basic_info = { suspend_count = %i, " - "virtual_size = 0x%8.8llx, resident_size = " - "0x%8.8llx, user_time = %f, system_time = %f }", - info->suspend_count, (uint64_t)info->virtual_size, - (uint64_t)info->resident_size, user, system); - } - return error; -} - -Status NativeProcessDarwin::SuspendTask() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (m_task == TASK_NULL) { - error.SetErrorString("task port is null, cannot suspend task"); - LLDB_LOGF(log, "NativeProcessDarwin::%s() failed: %s", __FUNCTION__, - error.AsCString()); - return error; - } - - auto mach_err = ::task_suspend(m_task); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail() && log) - LLDB_LOGF(log, "::task_suspend(target_task = 0x%4.4x)", m_task); - - return error; -} - -Status NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - LLDB_LOGF(log, "NativeProcessDarwin::%s() called", __FUNCTION__); - - if (CanResume()) { - m_thread_actions = resume_actions; - error = PrivateResume(); - return error; - } - - auto state = GetState(); - if (state == eStateRunning) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): task 0x%x is already " - "running, ignoring...", - __FUNCTION__, TaskPortForProcessID(error)); - return error; - } - - // We can't resume from this state. - error.SetErrorStringWithFormat("task 0x%x has state %s, can't resume", - TaskPortForProcessID(error), - StateAsCString(state)); - return error; -} - -Status NativeProcessDarwin::Halt() { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::Detach() { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::Signal(int signo) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::Interrupt() { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::Kill() { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::ReadMemory(lldb::addr_t addr, void *buf, - size_t size, size_t &bytes_read) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, - size_t size, - size_t &bytes_read) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::WriteMemory(lldb::addr_t addr, const void *buf, - size_t size, size_t &bytes_written) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -lldb::addr_t NativeProcessDarwin::GetSharedLibraryInfoAddress() { - return LLDB_INVALID_ADDRESS; -} - -size_t NativeProcessDarwin::UpdateThreads() { return 0; } - -bool NativeProcessDarwin::GetArchitecture(ArchSpec &arch) const { - return false; -} - -Status NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size, - bool hardware) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -void NativeProcessDarwin::DoStopIDBumped(uint32_t newBumpId) {} - -Status NativeProcessDarwin::GetLoadedModuleFileSpec(const char *module_path, - FileSpec &file_spec) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef &file_name, - lldb::addr_t &load_addr) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -// NativeProcessProtocol protected interface -Status NativeProcessDarwin::GetSoftwareBreakpointTrapOpcode( - size_t trap_opcode_size_hint, size_t &actual_opcode_size, - const uint8_t *&trap_opcode_bytes) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} diff --git a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h b/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h deleted file mode 100644 index 6741d4ddc5d8..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h +++ /dev/null @@ -1,337 +0,0 @@ -//===-- NativeProcessDarwin.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 NativeProcessDarwin_h -#define NativeProcessDarwin_h - -// NOTE: this code should only be compiled on Apple Darwin systems. It is -// not cross-platform code and is not intended to build on any other platform. -// Therefore, platform-specific headers and code are okay here. - -// C includes -#include <mach/mach_types.h> - -// C++ includes -#include <mutex> -#include <unordered_set> - -#include "lldb/Host/Debug.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Host/Pipe.h" -#include "lldb/Host/common/NativeProcessProtocol.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/lldb-types.h" - -#include "LaunchFlavor.h" -#include "MachException.h" -#include "NativeThreadDarwin.h" -#include "NativeThreadListDarwin.h" - -namespace lldb_private { -class Status; -class Scalar; - -namespace process_darwin { - -/// \class NativeProcessDarwin -/// Manages communication with the inferior (debugee) process. -/// -/// Upon construction, this class prepares and launches an inferior process -/// for debugging. -/// -/// Changes in the inferior process state are broadcasted. -class NativeProcessDarwin : public NativeProcessProtocol { - friend Status NativeProcessProtocol::Launch( - ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); - - friend Status NativeProcessProtocol::Attach( - lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); - -public: - ~NativeProcessDarwin() override; - - // NativeProcessProtocol Interface - Status Resume(const ResumeActionList &resume_actions) override; - - Status Halt() override; - - Status Detach() override; - - Status Signal(int signo) override; - - Status Interrupt() override; - - Status Kill() override; - - Status GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) override; - - Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) override; - - Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) override; - - Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, - size_t &bytes_written) override; - - Status AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) override; - - Status DeallocateMemory(lldb::addr_t addr) override; - - lldb::addr_t GetSharedLibraryInfoAddress() override; - - size_t UpdateThreads() override; - - bool GetArchitecture(ArchSpec &arch) const override; - - Status SetBreakpoint(lldb::addr_t addr, uint32_t size, - bool hardware) override; - - void DoStopIDBumped(uint32_t newBumpId) override; - - Status GetLoadedModuleFileSpec(const char *module_path, - FileSpec &file_spec) override; - - Status GetFileLoadAddress(const llvm::StringRef &file_name, - lldb::addr_t &load_addr) override; - - NativeThreadDarwinSP GetThreadByID(lldb::tid_t id); - - task_t GetTask() const { return m_task; } - - // Interface used by NativeRegisterContext-derived classes. - static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, - void *data = nullptr, size_t data_size = 0, - long *result = nullptr); - - bool SupportHardwareSingleStepping() const; - -protected: - // NativeProcessProtocol protected interface - Status - GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint, - size_t &actual_opcode_size, - const uint8_t *&trap_opcode_bytes) override; - -private: - /// Mach task-related Member Variables - - // The task port for the inferior process. - mutable task_t m_task; - - // True if the inferior process did an exec since we started - // monitoring it. - bool m_did_exec; - - // The CPU type of this process. - mutable cpu_type_t m_cpu_type; - - /// Exception/Signal Handling Member Variables - - // Exception port on which we will receive child exceptions - mach_port_t m_exception_port; - - // Saved state of the child exception port prior to us installing - // our own intercepting port. - MachException::PortInfo m_exc_port_info; - - // The thread that runs the Mach exception read and reply handler. - pthread_t m_exception_thread; - - // TODO see if we can remove this if we get the exception collection - // and distribution to happen in a single-threaded fashion. - std::recursive_mutex m_exception_messages_mutex; - - // A collection of exception messages caught when listening to the - // exception port. - MachException::Message::collection m_exception_messages; - - // When we call MachProcess::Interrupt(), we want to send this - // signal (if non-zero). - int m_sent_interrupt_signo; - - // If we resume the process and still haven't received our - // interrupt signal (if this is non-zero). - int m_auto_resume_signo; - - /// Thread-related Member Variables - NativeThreadListDarwin m_thread_list; - ResumeActionList m_thread_actions; - - /// Process Lifetime Member Variable - - // The pipe over which the waitpid thread and the main loop will - // communicate. - Pipe m_waitpid_pipe; - - // The thread that runs the waitpid handler. - pthread_t m_waitpid_thread; - - // waitpid reader callback handle. - MainLoop::ReadHandleUP m_waitpid_reader_handle; - - // Private Instance Methods - NativeProcessDarwin(lldb::pid_t pid, int pty_master_fd); - - /// Finalize the launch. - /// - /// This method associates the NativeProcessDarwin instance with the host - /// process that was just launched. It peforms actions like attaching a - /// listener to the inferior exception port, ptracing the process, and the - /// like. - /// - /// \param[in] launch_flavor - /// The launch flavor that was used to launch the process. - /// - /// \param[in] main_loop - /// The main loop that will run the process monitor. Work - /// that needs to be done (e.g. reading files) gets registered - /// here along with callbacks to process the work. - /// - /// \return - /// Any error that occurred during the aforementioned - /// operations. Failure here will force termination of the - /// launched process and debugging session. - Status FinalizeLaunch(LaunchFlavor launch_flavor, MainLoop &main_loop); - - Status SaveExceptionPortInfo(); - - void ExceptionMessageReceived(const MachException::Message &message); - - void MaybeRaiseThreadPriority(); - - Status StartExceptionThread(); - - Status SendInferiorExitStatusToMainLoop(::pid_t pid, int status); - - Status HandleWaitpidResult(); - - bool ProcessUsingSpringBoard() const; - - bool ProcessUsingBackBoard() const; - - static void *ExceptionThread(void *arg); - - void *DoExceptionThread(); - - lldb::addr_t GetDYLDAllImageInfosAddress(Status &error) const; - - static uint32_t GetCPUTypeForLocalProcess(::pid_t pid); - - uint32_t GetCPUType() const; - - task_t ExceptionMessageBundleComplete(); - - void StartSTDIOThread(); - - Status StartWaitpidThread(MainLoop &main_loop); - - static void *WaitpidThread(void *arg); - - void *DoWaitpidThread(); - - task_t TaskPortForProcessID(Status &error, bool force = false) const; - - /// Attaches to an existing process. Forms the implementation of - /// Process::DoAttach. - void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error); - - ::pid_t Attach(lldb::pid_t pid, Status &error); - - Status PrivateResume(); - - Status ReplyToAllExceptions(); - - Status ResumeTask(); - - bool IsTaskValid() const; - - bool IsTaskValid(task_t task) const; - - mach_port_t GetExceptionPort() const; - - bool IsExceptionPortValid() const; - - Status GetTaskBasicInfo(task_t task, struct task_basic_info *info) const; - - Status SuspendTask(); - - static Status SetDefaultPtraceOpts(const lldb::pid_t); - - static void *MonitorThread(void *baton); - - void MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status); - - void WaitForNewThread(::pid_t tid); - - void MonitorSIGTRAP(const siginfo_t &info, NativeThreadDarwin &thread); - - void MonitorTrace(NativeThreadDarwin &thread); - - void MonitorBreakpoint(NativeThreadDarwin &thread); - - void MonitorWatchpoint(NativeThreadDarwin &thread, uint32_t wp_index); - - void MonitorSignal(const siginfo_t &info, NativeThreadDarwin &thread, - bool exited); - - Status SetupSoftwareSingleStepping(NativeThreadDarwin &thread); - - bool HasThreadNoLock(lldb::tid_t thread_id); - - bool StopTrackingThread(lldb::tid_t thread_id); - - NativeThreadDarwinSP AddThread(lldb::tid_t thread_id); - - Status GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size); - - Status FixupBreakpointPCAsNeeded(NativeThreadDarwin &thread); - - /// Writes a siginfo_t structure corresponding to the given thread - /// ID to the memory region pointed to by \p siginfo. - Status GetSignalInfo(lldb::tid_t tid, void *siginfo); - - /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) - /// corresponding to the given thread ID to the memory pointed to by @p - /// message. - Status GetEventMessage(lldb::tid_t tid, unsigned long *message); - - void NotifyThreadDeath(lldb::tid_t tid); - - Status Detach(lldb::tid_t tid); - - // This method is requests a stop on all threads which are still - // running. It sets up a deferred delegate notification, which will - // fire once threads report as stopped. The triggerring_tid will be - // set as the current thread (main stop reason). - void StopRunningThreads(lldb::tid_t triggering_tid); - - // Notify the delegate if all threads have stopped. - void SignalIfAllThreadsStopped(); - - // Resume the given thread, optionally passing it the given signal. - // The type of resume operation (continue, single-step) depends on - // the state parameter. - Status ResumeThread(NativeThreadDarwin &thread, lldb::StateType state, - int signo); - - void ThreadWasCreated(NativeThreadDarwin &thread); - - void SigchldHandler(); -}; - -} // namespace process_darwin -} // namespace lldb_private - -#endif /* NativeProcessDarwin_h */ diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp b/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp deleted file mode 100644 index bcd6d8c2c4c1..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp +++ /dev/null @@ -1,281 +0,0 @@ -//===-- NativeThreadDarwin.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 "NativeThreadDarwin.h" - -// C includes -#include <libproc.h> - -// LLDB includes -#include "lldb/Utility/Stream.h" - -#include "NativeProcessDarwin.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; - -uint64_t NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID( - ::thread_t mach_port_id) { - thread_identifier_info_data_t tident; - mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; - - auto mach_err = ::thread_info(mach_port_id, THREAD_IDENTIFIER_INFO, - (thread_info_t)&tident, &tident_count); - if (mach_err != KERN_SUCCESS) { - // When we fail to get thread info for the supposed port, assume it is - // really a globally unique thread id already, or return the best thing we - // can, which is the thread port. - return mach_port_id; - } - return tident.thread_id; -} - -NativeThreadDarwin::NativeThreadDarwin(NativeProcessDarwin *process, - bool is_64_bit, - lldb::tid_t unique_thread_id, - ::thread_t mach_thread_port) - : NativeThreadProtocol(process, unique_thread_id), - m_mach_thread_port(mach_thread_port), m_basic_info(), - m_proc_threadinfo() {} - -bool NativeThreadDarwin::GetIdentifierInfo() { - // Don't try to get the thread info once and cache it for the life of the - // thread. It changes over time, for instance if the thread name changes, - // then the thread_handle also changes... So you have to refetch it every - // time. - mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - kern_return_t kret = ::thread_info(m_mach_thread_port, THREAD_IDENTIFIER_INFO, - (thread_info_t)&m_ident_info, &count); - return kret == KERN_SUCCESS; - - return false; -} - -std::string NativeThreadDarwin::GetName() { - std::string name; - - if (GetIdentifierInfo()) { - auto process_sp = GetProcess(); - if (!process_sp) { - name = "<unavailable>"; - return name; - } - - int len = ::proc_pidinfo(process_sp->GetID(), PROC_PIDTHREADINFO, - m_ident_info.thread_handle, &m_proc_threadinfo, - sizeof(m_proc_threadinfo)); - - if (len && m_proc_threadinfo.pth_name[0]) - name = m_proc_threadinfo.pth_name; - } - return name; -} - -lldb::StateType NativeThreadDarwin::GetState() { - // TODO implement - return eStateInvalid; -} - -bool NativeThreadDarwin::GetStopReason(ThreadStopInfo &stop_info, - std::string &description) { - // TODO implement - return false; -} - -NativeRegisterContextSP NativeThreadDarwin::GetRegisterContext() { - // TODO implement - return NativeRegisterContextSP(); -} - -Status NativeThreadDarwin::SetWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags, bool hardware) { - Status error; - error.SetErrorString("not yet implemented"); - return error; -} - -Status NativeThreadDarwin::RemoveWatchpoint(lldb::addr_t addr) { - Status error; - error.SetErrorString("not yet implemented"); - return error; -} - -void NativeThreadDarwin::Dump(Stream &stream) const { -// This is what we really want once we have the thread class wired up. -#if 0 - DNBLogThreaded("[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64 ", sp: 0x%16.16" PRIx64 ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d", - index, - m_seq_id, - m_unique_id, - GetPC(INVALID_NUB_ADDRESS), - GetSP(INVALID_NUB_ADDRESS), - m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds, - m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds, - m_basic_info.cpu_usage, - m_basic_info.policy, - m_basic_info.run_state, - thread_run_state, - m_basic_info.flags, - m_basic_info.suspend_count, m_suspend_count, - m_basic_info.sleep_time); - -#else - // Here's all we have right now. - stream.Printf("tid: 0x%8.8" PRIx64 ", thread port: 0x%4.4x", GetID(), - m_mach_thread_port); -#endif -} - -bool NativeThreadDarwin::NotifyException(MachException::Data &exc) { -// TODO implement this. -#if 0 - // Allow the arch specific protocol to process (MachException::Data &)exc - // first before possible reassignment of m_stop_exception with exc. See - // also MachThread::GetStopException(). - bool handled = m_arch_up->NotifyException(exc); - - if (m_stop_exception.IsValid()) - { - // We may have more than one exception for a thread, but we need to - // only remember the one that we will say is the reason we stopped. We - // may have been single stepping and also gotten a signal exception, so - // just remember the most pertinent one. - if (m_stop_exception.IsBreakpoint()) - m_stop_exception = exc; - } - else - { - m_stop_exception = exc; - } - - return handled; -#else - // Pretend we handled it. - return true; -#endif -} - -bool NativeThreadDarwin::ShouldStop(bool &step_more) const { -// TODO: implement this -#if 0 - // See if this thread is at a breakpoint? - DNBBreakpoint *bp = CurrentBreakpoint(); - - if (bp) - { - // This thread is sitting at a breakpoint, ask the breakpoint if we - // should be stopping here. - return true; - } - else - { - if (m_arch_up->StepNotComplete()) - { - step_more = true; - return false; - } - // The thread state is used to let us know what the thread was trying - // to do. MachThread::ThreadWillResume() will set the thread state to - // various values depending if the thread was the current thread and if - // it was to be single stepped, or resumed. - if (GetState() == eStateRunning) - { - // If our state is running, then we should continue as we are in - // the process of stepping over a breakpoint. - return false; - } - else - { - // Stop if we have any kind of valid exception for this thread. - if (GetStopException().IsValid()) - return true; - } - } - return false; -#else - return false; -#endif -} - -void NativeThreadDarwin::ThreadDidStop() { -// TODO implement this. -#if 0 - // This thread has existed prior to resuming under debug nub control, and - // has just been stopped. Do any cleanup that needs to be done after - // running. - - // The thread state and breakpoint will still have the same values as they - // had prior to resuming the thread, so it makes it easy to check if we - // were trying to step a thread, or we tried to resume while being at a - // breakpoint. - - // When this method gets called, the process state is still in the state it - // was in while running so we can act accordingly. - m_arch_up->ThreadDidStop(); - - - // We may have suspended this thread so the primary thread could step - // without worrying about race conditions, so lets restore our suspend - // count. - RestoreSuspendCountAfterStop(); - - // Update the basic information for a thread - MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); - - if (m_basic_info.suspend_count > 0) - SetState(eStateSuspended); - else - SetState(eStateStopped); -#endif -} - -bool NativeThreadDarwin::MachPortNumberIsValid(::thread_t thread) { - return thread != (::thread_t)(0); -} - -const struct thread_basic_info *NativeThreadDarwin::GetBasicInfo() const { - if (GetBasicInfo(m_mach_thread_port, &m_basic_info)) - return &m_basic_info; - return NULL; -} - -bool NativeThreadDarwin::GetBasicInfo(::thread_t thread, - struct thread_basic_info *basicInfoPtr) { - if (MachPortNumberIsValid(thread)) { - unsigned int info_count = THREAD_BASIC_INFO_COUNT; - kern_return_t err = ::thread_info(thread, THREAD_BASIC_INFO, - (thread_info_t)basicInfoPtr, &info_count); - if (err == KERN_SUCCESS) - return true; - } - ::memset(basicInfoPtr, 0, sizeof(struct thread_basic_info)); - return false; -} - -bool NativeThreadDarwin::IsUserReady() const { - if (m_basic_info.run_state == 0) - GetBasicInfo(); - - switch (m_basic_info.run_state) { - default: - case TH_STATE_UNINTERRUPTIBLE: - break; - - case TH_STATE_RUNNING: - case TH_STATE_STOPPED: - case TH_STATE_WAITING: - case TH_STATE_HALTED: - return true; - } - return false; -} - -NativeProcessDarwinSP NativeThreadDarwin::GetNativeProcessDarwinSP() { - return std::static_pointer_cast<NativeProcessDarwin>(GetProcess()); -} diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h b/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h deleted file mode 100644 index 616a9a7b9bf0..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h +++ /dev/null @@ -1,165 +0,0 @@ -//===-- NativeThreadDarwin.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 NativeThreadDarwin_H -#define NativeThreadDarwin_H - -// C includes -#include <mach/mach_types.h> -#include <sched.h> -#include <sys/proc_info.h> - -// C++ includes -#include <map> -#include <memory> -#include <string> - -// LLDB includes -#include "lldb/Host/common/NativeThreadProtocol.h" -#include "lldb/lldb-private-forward.h" - -#include "MachException.h" - -namespace lldb_private { -namespace process_darwin { - -class NativeProcessDarwin; -using NativeProcessDarwinSP = std::shared_ptr<NativeProcessDarwin>; - -class NativeThreadListDarwin; - -class NativeThreadDarwin : public NativeThreadProtocol { - friend class NativeProcessDarwin; - friend class NativeThreadListDarwin; - -public: - static uint64_t - GetGloballyUniqueThreadIDForMachPortID(::thread_t mach_port_id); - - NativeThreadDarwin(NativeProcessDarwin *process, bool is_64_bit, - lldb::tid_t unique_thread_id = 0, - ::thread_t mach_thread_port = 0); - - // NativeThreadProtocol Interface - std::string GetName() override; - - lldb::StateType GetState() override; - - bool GetStopReason(ThreadStopInfo &stop_info, - std::string &description) override; - - NativeRegisterContextSP GetRegisterContext() override; - - Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, - bool hardware) override; - - Status RemoveWatchpoint(lldb::addr_t addr) override; - - // New methods that are fine for others to call. - void Dump(Stream &stream) const; - -private: - // Interface for friend classes - - /// Resumes the thread. If \p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - Status Resume(uint32_t signo); - - /// Single steps the thread. If \p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - Status SingleStep(uint32_t signo); - - bool NotifyException(MachException::Data &exc); - - bool ShouldStop(bool &step_more) const; - - void ThreadDidStop(); - - void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); - - /// Return true if the thread is stopped. - /// If stopped by a signal, indicate the signo in the signo - /// argument. Otherwise, return LLDB_INVALID_SIGNAL_NUMBER. - bool IsStopped(int *signo); - - const struct thread_basic_info *GetBasicInfo() const; - - static bool GetBasicInfo(::thread_t thread, - struct thread_basic_info *basicInfoPtr); - - bool IsUserReady() const; - - void SetStoppedByExec(); - - void SetStoppedByBreakpoint(); - - void SetStoppedByWatchpoint(uint32_t wp_index); - - bool IsStoppedAtBreakpoint(); - - bool IsStoppedAtWatchpoint(); - - void SetStoppedByTrace(); - - void SetStoppedWithNoReason(); - - void SetExited(); - - Status RequestStop(); - - /// Return the mach thread port number for this thread. - /// - /// \return - /// The mach port number for this thread. Returns NULL_THREAD - /// when the thread is invalid. - thread_t GetMachPortNumber() const { return m_mach_thread_port; } - - static bool MachPortNumberIsValid(::thread_t thread); - - // Private interface - bool GetIdentifierInfo(); - - void MaybeLogStateChange(lldb::StateType new_state); - - NativeProcessDarwinSP GetNativeProcessDarwinSP(); - - void SetStopped(); - - inline void MaybePrepareSingleStepWorkaround(); - - inline void MaybeCleanupSingleStepWorkaround(); - - // Member Variables - - // The mach thread port for the thread. - ::thread_t m_mach_thread_port; - - // The most recently-retrieved thread basic info. - mutable ::thread_basic_info m_basic_info; - - struct proc_threadinfo m_proc_threadinfo; - - thread_identifier_info_data_t m_ident_info; - -#if 0 - lldb::StateType m_state; - ThreadStopInfo m_stop_info; - NativeRegisterContextSP m_reg_context_sp; - std::string m_stop_description; - using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>; - WatchpointIndexMap m_watchpoint_index_map; - // cpu_set_t m_original_cpu_set; // For single-step workaround. -#endif -}; - -typedef std::shared_ptr<NativeThreadDarwin> NativeThreadDarwinSP; - -} // namespace process_darwin -} // namespace lldb_private - -#endif // #ifndef NativeThreadDarwin_H diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp b/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp deleted file mode 100644 index 1faa5b219cbc..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp +++ /dev/null @@ -1,702 +0,0 @@ -//===-- NativeThreadListDarwin.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/19/07. -// -//===----------------------------------------------------------------------===// - -#include "NativeThreadListDarwin.h" - -// C includes -#include <inttypes.h> -#include <mach/vm_map.h> -#include <sys/sysctl.h> - -// LLDB includes -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/Stream.h" -#include "lldb/lldb-enumerations.h" - -#include "NativeProcessDarwin.h" -#include "NativeThreadDarwin.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; - -NativeThreadListDarwin::NativeThreadListDarwin() - : m_threads(), m_threads_mutex(), m_is_64_bit(false) {} - -NativeThreadListDarwin::~NativeThreadListDarwin() {} - -// These methods will be accessed directly from NativeThreadDarwin -#if 0 -nub_state_t -NativeThreadListDarwin::GetState(nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetState(); - return eStateInvalid; -} - -const char * -NativeThreadListDarwin::GetName (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetName(); - return NULL; -} -#endif - -// TODO: figure out if we need to add this to NativeThreadDarwin yet. -#if 0 -ThreadInfo::QoS -NativeThreadListDarwin::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetRequestedQoS(tsd, dti_qos_class_index); - return ThreadInfo::QoS(); -} - -nub_addr_t -NativeThreadListDarwin::GetPThreadT (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetPThreadT(); - return INVALID_NUB_ADDRESS; -} - -nub_addr_t -NativeThreadListDarwin::GetDispatchQueueT (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetDispatchQueueT(); - return INVALID_NUB_ADDRESS; -} - -nub_addr_t -NativeThreadListDarwin::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetTSDAddressForThread(plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); - return INVALID_NUB_ADDRESS; -} -#endif - -// TODO implement these -#if 0 -nub_thread_t -NativeThreadListDarwin::SetCurrentThread(nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - { - m_current_thread = thread_sp; - return tid; - } - return INVALID_NUB_THREAD; -} - - -bool -NativeThreadListDarwin::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetStopException().GetStopInfo(stop_info); - return false; -} - -bool -NativeThreadListDarwin::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info) -{ - thread_t mach_port_number = GetMachPortNumberByThreadID (tid); - - mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - return ::thread_info (mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS; -} - -void -NativeThreadListDarwin::DumpThreadStoppedReason (nub_thread_t tid) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - thread_sp->GetStopException().DumpStopReason(); -} - -const char * -NativeThreadListDarwin::GetThreadInfo (nub_thread_t tid) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetBasicInfoAsString(); - return NULL; -} - -#endif - -NativeThreadDarwinSP -NativeThreadListDarwin::GetThreadByID(lldb::tid_t tid) const { - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp && (thread_sp->GetID() == tid)) - return thread_sp; - } - return NativeThreadDarwinSP(); -} - -NativeThreadDarwinSP NativeThreadListDarwin::GetThreadByMachPortNumber( - ::thread_t mach_port_number) const { - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) - return thread_sp; - } - return NativeThreadDarwinSP(); -} - -lldb::tid_t NativeThreadListDarwin::GetThreadIDByMachPortNumber( - ::thread_t mach_port_number) const { - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) - return thread_sp->GetID(); - } - return LLDB_INVALID_THREAD_ID; -} - -// TODO implement -#if 0 -thread_t -NativeThreadListDarwin::GetMachPortNumberByThreadID (nub_thread_t globally_unique_id) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - MachThreadSP thread_sp; - const size_t num_threads = m_threads.size(); - for (size_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->ThreadID() == globally_unique_id) - { - return m_threads[idx]->MachPortNumber(); - } - } - return 0; -} - -bool -NativeThreadListDarwin::GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value ) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetRegisterValue(set, reg, reg_value); - - return false; -} - -bool -NativeThreadListDarwin::SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value ) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SetRegisterValue(set, reg, reg_value); - - return false; -} - -nub_size_t -NativeThreadListDarwin::GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetRegisterContext (buf, buf_len); - return 0; -} - -nub_size_t -NativeThreadListDarwin::SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SetRegisterContext (buf, buf_len); - return 0; -} - -uint32_t -NativeThreadListDarwin::SaveRegisterState (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SaveRegisterState (); - return 0; -} - -bool -NativeThreadListDarwin::RestoreRegisterState (nub_thread_t tid, uint32_t save_id) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->RestoreRegisterState (save_id); - return 0; -} -#endif - -size_t NativeThreadListDarwin::GetNumberOfThreads() const { - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - return static_cast<size_t>(m_threads.size()); -} - -// TODO implement -#if 0 -nub_thread_t -NativeThreadListDarwin::ThreadIDAtIndex (nub_size_t idx) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - if (idx < m_threads.size()) - return m_threads[idx]->ThreadID(); - return INVALID_NUB_THREAD; -} - -nub_thread_t -NativeThreadListDarwin::CurrentThreadID ( ) -{ - MachThreadSP thread_sp; - CurrentThread(thread_sp); - if (thread_sp.get()) - return thread_sp->ThreadID(); - return INVALID_NUB_THREAD; -} - -#endif - -bool NativeThreadListDarwin::NotifyException(MachException::Data &exc) { - auto thread_sp = GetThreadByMachPortNumber(exc.thread_port); - if (thread_sp) { - thread_sp->NotifyException(exc); - return true; - } - return false; -} - -void NativeThreadListDarwin::Clear() { - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - m_threads.clear(); -} - -uint32_t NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process, - bool update, - collection *new_threads) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - LLDB_LOGF(log, - "NativeThreadListDarwin::%s() (pid = %" PRIu64 ", update = " - "%u) process stop count = %u", - __FUNCTION__, process.GetID(), update, process.GetStopID()); - - if (process.GetStopID() == 0) { - // On our first stop, we'll record details like 32/64 bitness and select - // the proper architecture implementation. - // - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)process.GetID()}; - - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if ((sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, - &bufsize, NULL, 0) == 0) && - (bufsize > 0)) { - if (processInfo.kp_proc.p_flag & P_LP64) - m_is_64_bit = true; - } - -// TODO implement architecture selection and abstraction. -#if 0 -#if defined(__i386__) || defined(__x86_64__) - if (m_is_64_bit) - DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); - else - DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); -#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - if (m_is_64_bit) - DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); - else - DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); -#endif -#endif - } - - if (m_threads.empty() || update) { - thread_array_t thread_list = nullptr; - mach_msg_type_number_t thread_list_count = 0; - task_t task = process.GetTask(); - - Status error; - auto mach_err = ::task_threads(task, &thread_list, &thread_list_count); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "::task_threads(task = 0x%4.4x, thread_list => %p, " - "thread_list_count => %u) failed: %u (%s)", - task, thread_list, thread_list_count, error.GetError(), - error.AsCString()); - return 0; - } - - if (thread_list_count > 0) { - collection currThreads; - size_t idx; - // Iterator through the current thread list and see which threads we - // already have in our list (keep them), which ones we don't (add them), - // and which ones are not around anymore (remove them). - for (idx = 0; idx < thread_list_count; ++idx) { - // Get the Mach thread port. - const ::thread_t mach_port_num = thread_list[idx]; - - // Get the unique thread id for the mach port number. - uint64_t unique_thread_id = - NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID( - mach_port_num); - - // Retrieve the thread if it exists. - auto thread_sp = GetThreadByID(unique_thread_id); - if (thread_sp) { - // We are already tracking it. Keep the existing native thread - // instance. - currThreads.push_back(thread_sp); - } else { - // We don't have a native thread instance for this thread. Create it - // now. - thread_sp.reset(new NativeThreadDarwin( - &process, m_is_64_bit, unique_thread_id, mach_port_num)); - - // Add the new thread regardless of its is user ready state. Make - // sure the thread is ready to be displayed and shown to users before - // we add this thread to our list... - if (thread_sp->IsUserReady()) { - if (new_threads) - new_threads->push_back(thread_sp); - - currThreads.push_back(thread_sp); - } - } - } - - m_threads.swap(currThreads); - m_current_thread.reset(); - - // Free the vm memory given to us by ::task_threads() - vm_size_t thread_list_size = - (vm_size_t)(thread_list_count * sizeof(::thread_t)); - ::vm_deallocate(::mach_task_self(), (vm_address_t)thread_list, - thread_list_size); - } - } - return static_cast<uint32_t>(m_threads.size()); -} - -// TODO implement -#if 0 - -void -NativeThreadListDarwin::CurrentThread (MachThreadSP& thread_sp) -{ - // locker will keep a mutex locked until it goes out of scope - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - if (m_current_thread.get() == NULL) - { - // Figure out which thread is going to be our current thread. This is - // currently done by finding the first thread in the list that has a - // valid exception. - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->GetStopException().IsValid()) - { - m_current_thread = m_threads[idx]; - break; - } - } - } - thread_sp = m_current_thread; -} - -#endif - -void NativeThreadListDarwin::Dump(Stream &stream) const { - bool first = true; - - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp) { - // Handle newlines between thread entries. - if (first) - first = false; - else - stream.PutChar('\n'); - thread_sp->Dump(stream); - } - } -} - -void NativeThreadListDarwin::ProcessWillResume( - NativeProcessDarwin &process, const ResumeActionList &thread_actions) { - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - - // Update our thread list, because sometimes libdispatch or the kernel will - // spawn threads while a task is suspended. - NativeThreadListDarwin::collection new_threads; - -// TODO implement this. -#if 0 - // First figure out if we were planning on running only one thread, and if - // so, force that thread to resume. - bool run_one_thread; - thread_t solo_thread = THREAD_NULL; - if ((thread_actions.GetSize() > 0) && - (thread_actions.NumActionsWithState(eStateStepping) + - thread_actions.NumActionsWithState (eStateRunning) == 1)) - { - run_one_thread = true; - const DNBThreadResumeAction *action_ptr = thread_actions.GetFirst(); - size_t num_actions = thread_actions.GetSize(); - for (size_t i = 0; i < num_actions; i++, action_ptr++) - { - if (action_ptr->state == eStateStepping || action_ptr->state == eStateRunning) - { - solo_thread = action_ptr->tid; - break; - } - } - } - else - run_one_thread = false; -#endif - - UpdateThreadList(process, true, &new_threads); - -#if 0 - DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0, INVALID_NUB_ADDRESS }; - // If we are planning to run only one thread, any new threads should be - // suspended. - if (run_one_thread) - resume_new_threads.state = eStateSuspended; - - const size_t num_new_threads = new_threads.size(); - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - MachThread *thread = m_threads[idx].get(); - bool handled = false; - for (uint32_t new_idx = 0; new_idx < num_new_threads; ++new_idx) - { - if (thread == new_threads[new_idx].get()) - { - thread->ThreadWillResume(&resume_new_threads); - handled = true; - break; - } - } - - if (!handled) - { - const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true); - // There must always be a thread action for every thread. - assert (thread_action); - bool others_stopped = false; - if (solo_thread == thread->ThreadID()) - others_stopped = true; - thread->ThreadWillResume (thread_action, others_stopped); - } - } - - if (new_threads.size()) - { - for (uint32_t idx = 0; idx < num_new_threads; ++idx) - { - DNBLogThreadedIf (LOG_THREAD, "NativeThreadListDarwin::ProcessWillResume (pid = %4.4x) stop-id=%u, resuming newly discovered thread: 0x%8.8" PRIx64 ", thread-is-user-ready=%i)", - process->ProcessID(), - process->StopCount(), - new_threads[idx]->ThreadID(), - new_threads[idx]->IsUserReady()); - } - } -#endif -} - -uint32_t NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process) { - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - - // Update our thread list. - UpdateThreadList(process, true); - - for (auto thread_sp : m_threads) { - if (thread_sp) - thread_sp->ThreadDidStop(); - } - return (uint32_t)m_threads.size(); -} - -// Check each thread in our thread list to see if we should notify our client -// of the current halt in execution. -// -// Breakpoints can have callback functions associated with them than can return -// true to stop, or false to continue executing the inferior. -// -// RETURNS -// true if we should stop and notify our clients -// false if we should resume our child process and skip notification -bool NativeThreadListDarwin::ShouldStop(bool &step_more) { - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp && thread_sp->ShouldStop(step_more)) - return true; - } - return false; -} - -// Implement. -#if 0 - -void -NativeThreadListDarwin::NotifyBreakpointChanged (const DNBBreakpoint *bp) -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - m_threads[idx]->NotifyBreakpointChanged(bp); - } -} - - -uint32_t -NativeThreadListDarwin::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const -{ - if (bp != NULL) - { - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->EnableHardwareBreakpoint(bp); - } - return INVALID_NUB_HW_INDEX; -} - -bool -NativeThreadListDarwin::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const -{ - if (bp != NULL) - { - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->DisableHardwareBreakpoint(bp); - } - return false; -} - -// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> -// MachProcess::EnableWatchpoint() -> -// NativeThreadListDarwin::EnableHardwareWatchpoint(). -uint32_t -NativeThreadListDarwin::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const -{ - uint32_t hw_index = INVALID_NUB_HW_INDEX; - if (wp != NULL) - { - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - // On Mac OS X we have to prime the control registers for new threads. - // We do this using the control register data for the first thread, for - // lack of a better way of choosing. - bool also_set_on_task = true; - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp, also_set_on_task)) == INVALID_NUB_HW_INDEX) - { - // We know that idx failed for some reason. Let's rollback the - // transaction for [0, idx). - for (uint32_t i = 0; i < idx; ++i) - m_threads[i]->RollbackTransForHWP(); - return INVALID_NUB_HW_INDEX; - } - also_set_on_task = false; - } - // Notify each thread to commit the pending transaction. - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->FinishTransForHWP(); - - } - return hw_index; -} - -bool -NativeThreadListDarwin::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const -{ - if (wp != NULL) - { - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - - // On Mac OS X we have to prime the control registers for new threads. - // We do this using the control register data for the first thread, for - // lack of a better way of choosing. - bool also_set_on_task = true; - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if (!m_threads[idx]->DisableHardwareWatchpoint(wp, also_set_on_task)) - { - // We know that idx failed for some reason. Let's rollback the - // transaction for [0, idx). - for (uint32_t i = 0; i < idx; ++i) - m_threads[i]->RollbackTransForHWP(); - return false; - } - also_set_on_task = false; - } - // Notify each thread to commit the pending transaction. - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->FinishTransForHWP(); - - return true; - } - return false; -} - -uint32_t -NativeThreadListDarwin::NumSupportedHardwareWatchpoints () const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - // Use an arbitrary thread to retrieve the number of supported hardware - // watchpoints. - if (num_threads) - return m_threads[0]->NumSupportedHardwareWatchpoints(); - return 0; -} - -uint32_t -NativeThreadListDarwin::GetThreadIndexForThreadStoppedWithSignal (const int signo) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - uint32_t should_stop = false; - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx) - { - if (m_threads[idx]->GetStopException().SoftSignal () == signo) - return idx; - } - return UINT32_MAX; -} - -#endif diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h b/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h deleted file mode 100644 index 9ab0a7c8c802..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h +++ /dev/null @@ -1,138 +0,0 @@ -//===-- NativeThreadListDarwin.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 -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/19/07. -// -//===----------------------------------------------------------------------===// - -#ifndef __NativeThreadListDarwin_h__ -#define __NativeThreadListDarwin_h__ - -#include <memory> -#include <mutex> -#include <vector> - -#include "lldb/lldb-private-forward.h" -#include "lldb/lldb-types.h" - -#include "MachException.h" - -// #include "ThreadInfo.h" - -namespace lldb_private { -namespace process_darwin { - -class NativeBreakpointDarwin; -class NativeProcessDarwin; - -class NativeThreadDarwin; -using NativeThreadDarwinSP = std::shared_ptr<NativeThreadDarwin>; - -class NativeThreadListDarwin { -public: - NativeThreadListDarwin(); - ~NativeThreadListDarwin(); - - void Clear(); - - void Dump(Stream &stream) const; - -// These methods will be accessed directly from NativeThreadDarwin -#if 0 - bool GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value) const; - bool SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value) const; - nub_size_t GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len); - nub_size_t SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len); - uint32_t SaveRegisterState (nub_thread_t tid); - bool RestoreRegisterState (nub_thread_t tid, uint32_t save_id); -#endif - - const char *GetThreadInfo(lldb::tid_t tid) const; - - void ProcessWillResume(NativeProcessDarwin &process, - const ResumeActionList &thread_actions); - - uint32_t ProcessDidStop(NativeProcessDarwin &process); - - bool NotifyException(MachException::Data &exc); - - bool ShouldStop(bool &step_more); - -// These methods will be accessed directly from NativeThreadDarwin -#if 0 - const char * GetName (nub_thread_t tid); - nub_state_t GetState (nub_thread_t tid); - nub_thread_t SetCurrentThread (nub_thread_t tid); -#endif - -// TODO: figure out if we need to add this to NativeThreadDarwin yet. -#if 0 - ThreadInfo::QoS GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index); - nub_addr_t GetPThreadT (nub_thread_t tid); - nub_addr_t GetDispatchQueueT (nub_thread_t tid); - nub_addr_t GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size); -#endif - -// These methods will be accessed directly from NativeThreadDarwin -#if 0 - bool GetThreadStoppedReason (nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const; - void DumpThreadStoppedReason (nub_thread_t tid) const; - bool GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info); -#endif - - size_t GetNumberOfThreads() const; - - lldb::tid_t ThreadIDAtIndex(size_t idx) const; - - lldb::tid_t GetCurrentThreadID(); - - NativeThreadDarwinSP GetCurrentThread(); - - void NotifyBreakpointChanged(const NativeBreakpointDarwin *bp); - - uint32_t EnableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; - - bool DisableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; - - uint32_t EnableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; - - bool DisableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; - - uint32_t GetNumberOfSupportedHardwareWatchpoints() const; - - size_t GetThreadIndexForThreadStoppedWithSignal(const int signo) const; - - NativeThreadDarwinSP GetThreadByID(lldb::tid_t tid) const; - - NativeThreadDarwinSP - GetThreadByMachPortNumber(::thread_t mach_port_number) const; - - lldb::tid_t GetThreadIDByMachPortNumber(::thread_t mach_port_number) const; - - thread_t GetMachPortNumberByThreadID(lldb::tid_t globally_unique_id) const; - -protected: - typedef std::vector<NativeThreadDarwinSP> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - - // Consider having this return an lldb_private::Status. - uint32_t UpdateThreadList(NativeProcessDarwin &process, bool update, - collection *num_threads = nullptr); - - collection m_threads; - mutable std::recursive_mutex m_threads_mutex; - NativeThreadDarwinSP m_current_thread; - bool m_is_64_bit; -}; - -} // namespace process_darwin -} // namespace lldb_private - -#endif // #ifndef __NativeThreadListDarwin_h__ diff --git a/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp index 0a49f96f54a1..48dbddb86cca 100644 --- a/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp @@ -1,4 +1,4 @@ -//===-- FreeBSDThread.cpp ---------------------------------------*- C++ -*-===// +//===-- FreeBSDThread.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -14,9 +14,6 @@ #include <sys/types.h> #include <sys/user.h> -#include "lldb/Target/UnixSignals.h" -#include "lldb/Utility/State.h" - #include "FreeBSDThread.h" #include "POSIXStopInfo.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" @@ -26,7 +23,6 @@ #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" -#include "Plugins/Process/Utility/UnwindLLDB.h" #include "ProcessFreeBSD.h" #include "ProcessMonitor.h" #include "RegisterContextPOSIXProcessMonitor_arm.h" @@ -44,6 +40,8 @@ #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Target/Unwind.h" #include "lldb/Utility/State.h" #include "llvm/ADT/SmallString.h" @@ -166,7 +164,6 @@ lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() { assert(target_arch.GetTriple().getOS() == llvm::Triple::FreeBSD); switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: - reg_interface = new RegisterInfoPOSIX_arm64(target_arch); break; case llvm::Triple::arm: reg_interface = new RegisterInfoPOSIX_arm(target_arch); @@ -195,7 +192,8 @@ lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() { switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: { RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = - new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface); + new RegisterContextPOSIXProcessMonitor_arm64( + *this, std::make_unique<RegisterInfoPOSIX_arm64>(target_arch)); m_posix_thread = reg_ctx; m_reg_context_sp.reset(reg_ctx); break; @@ -254,8 +252,7 @@ FreeBSDThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) { if (concrete_frame_idx == 0) reg_ctx_sp = GetRegisterContext(); else { - assert(GetUnwinder()); - reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame); + reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); } return reg_ctx_sp; @@ -275,13 +272,6 @@ bool FreeBSDThread::CalculateStopInfo() { return true; } -Unwind *FreeBSDThread::GetUnwinder() { - if (!m_unwinder_up) - m_unwinder_up.reset(new UnwindLLDB(*this)); - - return m_unwinder_up.get(); -} - void FreeBSDThread::DidStop() { // Don't set the thread state to stopped unless we really stopped. } diff --git a/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h b/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h index 6d3c253a519e..774ffb511bc6 100644 --- a/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h +++ b/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h @@ -102,8 +102,6 @@ protected: void ExitNotify(const ProcessMessage &message); void ExecNotify(const ProcessMessage &message); - lldb_private::Unwind *GetUnwinder() override; - // FreeBSDThread internal API. // POSIXThread override diff --git a/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp b/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp index 71f012944a9a..4e6f3afda0ab 100644 --- a/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp @@ -1,4 +1,4 @@ -//===-- POSIXStopInfo.cpp ---------------------------------------*- C++ -*-===// +//===-- POSIXStopInfo.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index 32e3320150f8..a44080640f6c 100644 --- a/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -1,5 +1,4 @@ -//===-- ProcessFreeBSD.cpp ----------------------------------------*- C++ -//-*-===// +//===-- ProcessFreeBSD.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -57,6 +56,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ProcessFreeBSD) + namespace { UnixSignalsSP &GetFreeBSDSignals() { static UnixSignalsSP s_freebsd_signals_sp(new FreeBSDSignals()); @@ -379,7 +380,8 @@ Status ProcessFreeBSD::DoLaunch(Module *module, FileSpec stdout_file_spec{}; FileSpec stderr_file_spec{}; - const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL, 0)}; + const FileSpec dbg_pts_file_spec{ + launch_info.GetPTY().GetSecondaryName(NULL, 0)}; file_action = launch_info.GetFileActionForFD(STDIN_FILENO); stdin_file_spec = diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index ff3fb0a75e2d..6a9209d1214c 100644 --- a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -1,4 +1,4 @@ -//===-- ProcessMonitor.cpp ------------------------------------ -*- C++ -*-===// +//===-- ProcessMonitor.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -855,7 +855,7 @@ bool ProcessMonitor::Launch(LaunchArgs *args) { // terminal has already dupped the tty descriptors to stdin/out/err. This // closes original fd from which they were copied (and avoids leaking // descriptors to the debugged process. - terminal.CloseSlaveFileDescriptor(); + terminal.CloseSecondaryFileDescriptor(); // Do not inherit setgid powers. if (setgid(getgid()) != 0) @@ -939,7 +939,7 @@ bool ProcessMonitor::Launch(LaunchArgs *args) { #endif // Release the master terminal descriptor and pass it off to the // ProcessMonitor instance. Similarly stash the inferior pid. - monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor(); + monitor->m_terminal_fd = terminal.ReleasePrimaryFileDescriptor(); monitor->m_pid = pid; // Set the terminal fd to be in non blocking mode (it simplifies the diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp index f0c4526357cc..4216f68faf5c 100644 --- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm.cpp -----------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_arm.cpp ------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp index 147f4b56a804..d3eafae1e6de 100644 --- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm64.cpp -----------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_arm64.cpp ----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -22,9 +22,9 @@ using namespace lldb_private; RegisterContextPOSIXProcessMonitor_arm64:: RegisterContextPOSIXProcessMonitor_arm64( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info) {} + lldb_private::Thread &thread, + std::unique_ptr<RegisterInfoPOSIX_arm64> register_info) + : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {} ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() { lldb::ProcessSP base = CalculateProcess(); diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h index d54d34e89cad..f100d905e28f 100644 --- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h +++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h @@ -17,8 +17,8 @@ class RegisterContextPOSIXProcessMonitor_arm64 public POSIXBreakpointProtocol { public: RegisterContextPOSIXProcessMonitor_arm64( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); + lldb_private::Thread &thread, + std::unique_ptr<RegisterInfoPOSIX_arm64> register_info); protected: bool ReadGPR(); diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp index db9b5a6a038c..23c76f234c8e 100644 --- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXProcessMonitor_mips64.cpp -----------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_mips64.cpp ---------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp index 77694733fa39..f8342775a81b 100644 --- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXProcessMonitor_powerpc.cpp ----------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_powerpc.cpp --------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp index 3046d97f153c..b1739e1e3bd8 100644 --- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXProcessMonitor_x86.cpp --------------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_x86.cpp ------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index 4313d27e11e9..5109022d80dd 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -1,4 +1,4 @@ -//===-- NativeProcessNetBSD.cpp ------------------------------- -*- C++ -*-===// +//===-- NativeProcessNetBSD.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -95,7 +95,7 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, Info.GetArchitecture().GetArchitectureName()); std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD( - pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, + pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, Info.GetArchitecture(), mainloop)); // Enable event reporting diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp index a8afa0b20305..03b505c19890 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp @@ -1,4 +1,4 @@ -//===-- NativeRegisterContextNetBSD.cpp -------------------------*- C++ -*-===// +//===-- NativeRegisterContextNetBSD.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp index 05a35401da46..ca4706a65657 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- NativeRegisterContextNetBSD_x86_64.cpp ---------------*- C++ -*-===// +//===-- NativeRegisterContextNetBSD_x86_64.cpp ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#if defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #include "NativeRegisterContextNetBSD_x86_64.h" @@ -16,6 +16,7 @@ #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" +#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h" // clang-format off @@ -135,9 +136,84 @@ static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - k_num_dbr_registers_x86_64, "g_dbr_regnums_x86_64 has wrong number of register infos"); +// x86 32-bit general purpose registers. +const uint32_t g_gpr_regnums_i386[] = { + lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386, + lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386, + lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386, + lldb_gs_i386, lldb_ss_i386, lldb_ds_i386, lldb_es_i386, + lldb_ax_i386, lldb_bx_i386, lldb_cx_i386, lldb_dx_i386, + lldb_di_i386, lldb_si_i386, lldb_bp_i386, lldb_sp_i386, + lldb_ah_i386, lldb_bh_i386, lldb_ch_i386, lldb_dh_i386, + lldb_al_i386, lldb_bl_i386, lldb_cl_i386, lldb_dl_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - + 1 == + k_num_gpr_registers_i386, + "g_gpr_regnums_i386 has wrong number of register infos"); + +// x86 32-bit floating point registers. +const uint32_t g_fpu_regnums_i386[] = { + lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386, + lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386, + lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386, + lldb_st2_i386, lldb_st3_i386, lldb_st4_i386, lldb_st5_i386, + lldb_st6_i386, lldb_st7_i386, lldb_mm0_i386, lldb_mm1_i386, + lldb_mm2_i386, lldb_mm3_i386, lldb_mm4_i386, lldb_mm5_i386, + lldb_mm6_i386, lldb_mm7_i386, lldb_xmm0_i386, lldb_xmm1_i386, + lldb_xmm2_i386, lldb_xmm3_i386, lldb_xmm4_i386, lldb_xmm5_i386, + lldb_xmm6_i386, lldb_xmm7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - + 1 == + k_num_fpr_registers_i386, + "g_fpu_regnums_i386 has wrong number of register infos"); + +// x86 64-bit registers available via XState. +static const uint32_t g_xstate_regnums_i386[] = { + lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, + lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, + // Note: we currently do not provide them but this is needed to avoid + // unnamed groups in SBFrame::GetRegisterContext(). + lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, + lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_xstate_regnums_i386) / sizeof(g_xstate_regnums_i386[0])) - + 1 == + k_num_avx_registers_i386 + k_num_mpx_registers_i386, + "g_xstate_regnums_i386 has wrong number of register infos"); + +// x86 debug registers. +static const uint32_t g_dbr_regnums_i386[] = { + lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386, + lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) - + 1 == + k_num_dbr_registers_i386, + "g_dbr_regnums_i386 has wrong number of register infos"); + + // Number of register sets provided by this context. enum { k_num_register_sets = 4 }; +// Register sets for x86 32-bit. +static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_i386, + g_gpr_regnums_i386}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_i386, + g_fpu_regnums_i386}, + {"Extended State Registers", "xstate", + k_num_avx_registers_i386 + k_num_mpx_registers_i386, + g_xstate_regnums_i386}, + {"Debug Registers", "dbr", k_num_dbr_registers_i386, + g_dbr_regnums_i386}, +}; + // Register sets for x86 64-bit. static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, @@ -164,18 +240,23 @@ NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD( static RegisterInfoInterface * CreateRegisterInfoInterface(const ArchSpec &target_arch) { - assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && - "Register setting path assumes this is a 64-bit host"); - // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 - // register context. - return new RegisterContextNetBSD_x86_64(target_arch); + if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) { + // 32-bit hosts run with a RegisterContextNetBSD_i386 context. + return new RegisterContextNetBSD_i386(target_arch); + } else { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 + // register context. + return new RegisterContextNetBSD_x86_64(target_arch); + } } NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) : NativeRegisterContextNetBSD(native_thread, CreateRegisterInfoInterface(target_arch)), - m_gpr_x86_64(), m_fpr_x86_64(), m_dbr_x86_64() {} + m_gpr(), m_fpr(), m_dbr() {} // CONSIDER after local and llgs debugging are merged, register set support can // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual. @@ -192,6 +273,8 @@ uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const { const RegisterSet * NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const { switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + return &g_reg_sets_i386[set_index]; case llvm::Triple::x86_64: return &g_reg_sets_x86_64[set_index]; default: @@ -202,36 +285,162 @@ NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const { return nullptr; } +static constexpr int RegNumX86ToX86_64(int regnum) { + switch (regnum) { + case lldb_eax_i386: + return lldb_rax_x86_64; + case lldb_ebx_i386: + return lldb_rbx_x86_64; + case lldb_ecx_i386: + return lldb_rcx_x86_64; + case lldb_edx_i386: + return lldb_rdx_x86_64; + case lldb_edi_i386: + return lldb_rdi_x86_64; + case lldb_esi_i386: + return lldb_rsi_x86_64; + case lldb_ebp_i386: + return lldb_rbp_x86_64; + case lldb_esp_i386: + return lldb_rsp_x86_64; + case lldb_eip_i386: + return lldb_rip_x86_64; + case lldb_eflags_i386: + return lldb_rflags_x86_64; + case lldb_cs_i386: + return lldb_cs_x86_64; + case lldb_fs_i386: + return lldb_fs_x86_64; + case lldb_gs_i386: + return lldb_gs_x86_64; + case lldb_ss_i386: + return lldb_ss_x86_64; + case lldb_ds_i386: + return lldb_ds_x86_64; + case lldb_es_i386: + return lldb_es_x86_64; + case lldb_fctrl_i386: + return lldb_fctrl_x86_64; + case lldb_fstat_i386: + return lldb_fstat_x86_64; + case lldb_ftag_i386: + return lldb_fstat_x86_64; + case lldb_fop_i386: + return lldb_fop_x86_64; + case lldb_fiseg_i386: + return lldb_fiseg_x86_64; + case lldb_fioff_i386: + return lldb_fioff_x86_64; + case lldb_foseg_i386: + return lldb_foseg_x86_64; + case lldb_fooff_i386: + return lldb_fooff_x86_64; + case lldb_mxcsr_i386: + return lldb_mxcsr_x86_64; + case lldb_mxcsrmask_i386: + return lldb_mxcsrmask_x86_64; + case lldb_st0_i386: + case lldb_st1_i386: + case lldb_st2_i386: + case lldb_st3_i386: + case lldb_st4_i386: + case lldb_st5_i386: + case lldb_st6_i386: + case lldb_st7_i386: + return lldb_st0_x86_64 + regnum - lldb_st0_i386; + case lldb_mm0_i386: + case lldb_mm1_i386: + case lldb_mm2_i386: + case lldb_mm3_i386: + case lldb_mm4_i386: + case lldb_mm5_i386: + case lldb_mm6_i386: + case lldb_mm7_i386: + return lldb_mm0_x86_64 + regnum - lldb_mm0_i386; + case lldb_xmm0_i386: + case lldb_xmm1_i386: + case lldb_xmm2_i386: + case lldb_xmm3_i386: + case lldb_xmm4_i386: + case lldb_xmm5_i386: + case lldb_xmm6_i386: + case lldb_xmm7_i386: + return lldb_xmm0_x86_64 + regnum - lldb_xmm0_i386; + case lldb_ymm0_i386: + case lldb_ymm1_i386: + case lldb_ymm2_i386: + case lldb_ymm3_i386: + case lldb_ymm4_i386: + case lldb_ymm5_i386: + case lldb_ymm6_i386: + case lldb_ymm7_i386: + return lldb_ymm0_x86_64 + regnum - lldb_ymm0_i386; + case lldb_dr0_i386: + case lldb_dr1_i386: + case lldb_dr2_i386: + case lldb_dr3_i386: + case lldb_dr4_i386: + case lldb_dr5_i386: + case lldb_dr6_i386: + case lldb_dr7_i386: + return lldb_dr0_x86_64 + regnum - lldb_dr0_i386; + default: + assert(false && "Unhandled i386 register."); + return 0; + } +} + int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum( int reg_num) const { - if (reg_num <= k_last_gpr_x86_64) - return GPRegSet; - else if (reg_num <= k_last_fpr_x86_64) - return FPRegSet; - else if (reg_num <= k_last_avx_x86_64) - return XStateRegSet; // AVX - else if (reg_num <= k_last_mpxr_x86_64) - return -1; // MPXR - else if (reg_num <= k_last_mpxc_x86_64) - return -1; // MPXC - else if (reg_num <= lldb_dr7_x86_64) - return DBRegSet; // DBR - else + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + if (reg_num <= k_last_gpr_i386) + return GPRegSet; + else if (reg_num <= k_last_fpr_i386) + return FPRegSet; + else if (reg_num <= k_last_avx_i386) + return XStateRegSet; // AVX + else if (reg_num <= lldb_dr7_i386) + return DBRegSet; // DBR + else + return -1; + case llvm::Triple::x86_64: + if (reg_num <= k_last_gpr_x86_64) + return GPRegSet; + else if (reg_num <= k_last_fpr_x86_64) + return FPRegSet; + else if (reg_num <= k_last_avx_x86_64) + return XStateRegSet; // AVX + else if (reg_num <= k_last_mpxr_x86_64) + return -1; // MPXR + else if (reg_num <= k_last_mpxc_x86_64) + return -1; // MPXC + else if (reg_num <= lldb_dr7_x86_64) + return DBRegSet; // DBR + else + return -1; + default: + assert(false && "Unhandled target architecture."); return -1; + } } Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) { switch (set) { case GPRegSet: - return DoRegisterSet(PT_GETREGS, &m_gpr_x86_64); + return DoRegisterSet(PT_GETREGS, &m_gpr); case FPRegSet: - return DoRegisterSet(PT_GETFPREGS, &m_fpr_x86_64); +#if defined(__x86_64__) + return DoRegisterSet(PT_GETFPREGS, &m_fpr); +#else + return DoRegisterSet(PT_GETXMMREGS, &m_fpr); +#endif case DBRegSet: - return DoRegisterSet(PT_GETDBREGS, &m_dbr_x86_64); + return DoRegisterSet(PT_GETDBREGS, &m_dbr); case XStateRegSet: #ifdef HAVE_XSTATE { - struct iovec iov = {&m_xstate_x86_64, sizeof(m_xstate_x86_64)}; + struct iovec iov = {&m_xstate, sizeof(m_xstate)}; return DoRegisterSet(PT_GETXSTATE, &iov); } #else @@ -244,15 +453,19 @@ Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) { Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) { switch (set) { case GPRegSet: - return DoRegisterSet(PT_SETREGS, &m_gpr_x86_64); + return DoRegisterSet(PT_SETREGS, &m_gpr); case FPRegSet: - return DoRegisterSet(PT_SETFPREGS, &m_fpr_x86_64); +#if defined(__x86_64__) + return DoRegisterSet(PT_SETFPREGS, &m_fpr); +#else + return DoRegisterSet(PT_SETXMMREGS, &m_fpr); +#endif case DBRegSet: - return DoRegisterSet(PT_SETDBREGS, &m_dbr_x86_64); + return DoRegisterSet(PT_SETDBREGS, &m_dbr); case XStateRegSet: #ifdef HAVE_XSTATE { - struct iovec iov = {&m_xstate_x86_64, sizeof(m_xstate_x86_64)}; + struct iovec iov = {&m_xstate, sizeof(m_xstate)}; return DoRegisterSet(PT_SETXSTATE, &iov); } #else @@ -272,7 +485,7 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, return error; } - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg == LLDB_INVALID_REGNUM) { // This is likely an internal register for lldb use only and should not be // directly queried. @@ -291,112 +504,175 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, return error; } + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86_64: + break; + case llvm::Triple::x86: + reg = RegNumX86ToX86_64(reg); + break; + default: + assert(false && "Unhandled target architecture."); + error.SetErrorString("Unhandled target architecture."); + return error; + } + error = ReadRegisterSet(set); if (error.Fail()) return error; switch (reg) { +#if defined(__x86_64__) case lldb_rax_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX]; + reg_value = (uint64_t)m_gpr.regs[_REG_RAX]; break; case lldb_rbx_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX]; + reg_value = (uint64_t)m_gpr.regs[_REG_RBX]; break; case lldb_rcx_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX]; + reg_value = (uint64_t)m_gpr.regs[_REG_RCX]; break; case lldb_rdx_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX]; + reg_value = (uint64_t)m_gpr.regs[_REG_RDX]; break; case lldb_rdi_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI]; + reg_value = (uint64_t)m_gpr.regs[_REG_RDI]; break; case lldb_rsi_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI]; + reg_value = (uint64_t)m_gpr.regs[_REG_RSI]; break; case lldb_rbp_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP]; + reg_value = (uint64_t)m_gpr.regs[_REG_RBP]; break; case lldb_rsp_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP]; + reg_value = (uint64_t)m_gpr.regs[_REG_RSP]; break; case lldb_r8_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8]; + reg_value = (uint64_t)m_gpr.regs[_REG_R8]; break; case lldb_r9_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9]; + reg_value = (uint64_t)m_gpr.regs[_REG_R9]; break; case lldb_r10_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10]; + reg_value = (uint64_t)m_gpr.regs[_REG_R10]; break; case lldb_r11_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11]; + reg_value = (uint64_t)m_gpr.regs[_REG_R11]; break; case lldb_r12_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12]; + reg_value = (uint64_t)m_gpr.regs[_REG_R12]; break; case lldb_r13_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13]; + reg_value = (uint64_t)m_gpr.regs[_REG_R13]; break; case lldb_r14_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14]; + reg_value = (uint64_t)m_gpr.regs[_REG_R14]; break; case lldb_r15_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15]; + reg_value = (uint64_t)m_gpr.regs[_REG_R15]; break; case lldb_rip_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP]; + reg_value = (uint64_t)m_gpr.regs[_REG_RIP]; break; case lldb_rflags_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS]; + reg_value = (uint64_t)m_gpr.regs[_REG_RFLAGS]; break; case lldb_cs_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS]; + reg_value = (uint64_t)m_gpr.regs[_REG_CS]; break; case lldb_fs_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS]; + reg_value = (uint64_t)m_gpr.regs[_REG_FS]; break; case lldb_gs_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS]; + reg_value = (uint64_t)m_gpr.regs[_REG_GS]; break; case lldb_ss_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS]; + reg_value = (uint64_t)m_gpr.regs[_REG_SS]; break; case lldb_ds_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS]; + reg_value = (uint64_t)m_gpr.regs[_REG_DS]; break; case lldb_es_x86_64: - reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES]; + reg_value = (uint64_t)m_gpr.regs[_REG_ES]; + break; +#else + case lldb_rax_x86_64: + reg_value = (uint32_t)m_gpr.r_eax; break; + case lldb_rbx_x86_64: + reg_value = (uint32_t)m_gpr.r_ebx; + break; + case lldb_rcx_x86_64: + reg_value = (uint32_t)m_gpr.r_ecx; + break; + case lldb_rdx_x86_64: + reg_value = (uint32_t)m_gpr.r_edx; + break; + case lldb_rdi_x86_64: + reg_value = (uint32_t)m_gpr.r_edi; + break; + case lldb_rsi_x86_64: + reg_value = (uint32_t)m_gpr.r_esi; + break; + case lldb_rsp_x86_64: + reg_value = (uint32_t)m_gpr.r_esp; + break; + case lldb_rbp_x86_64: + reg_value = (uint32_t)m_gpr.r_ebp; + break; + case lldb_rip_x86_64: + reg_value = (uint32_t)m_gpr.r_eip; + break; + case lldb_rflags_x86_64: + reg_value = (uint32_t)m_gpr.r_eflags; + break; + case lldb_cs_x86_64: + reg_value = (uint32_t)m_gpr.r_cs; + break; + case lldb_fs_x86_64: + reg_value = (uint32_t)m_gpr.r_fs; + break; + case lldb_gs_x86_64: + reg_value = (uint32_t)m_gpr.r_gs; + break; + case lldb_ss_x86_64: + reg_value = (uint32_t)m_gpr.r_ss; + break; + case lldb_ds_x86_64: + reg_value = (uint32_t)m_gpr.r_ds; + break; + case lldb_es_x86_64: + reg_value = (uint32_t)m_gpr.r_es; + break; +#endif case lldb_fctrl_x86_64: - reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_cw; + reg_value = (uint16_t)m_fpr.fxstate.fx_cw; break; case lldb_fstat_x86_64: - reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_sw; + reg_value = (uint16_t)m_fpr.fxstate.fx_sw; break; case lldb_ftag_x86_64: - reg_value = (uint8_t)m_fpr_x86_64.fxstate.fx_tw; + reg_value = (uint8_t)m_fpr.fxstate.fx_tw; break; case lldb_fop_x86_64: - reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_opcode; + reg_value = (uint64_t)m_fpr.fxstate.fx_opcode; break; case lldb_fiseg_x86_64: - reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_ip.fa_64; + reg_value = (uint64_t)m_fpr.fxstate.fx_ip.fa_64; break; case lldb_fioff_x86_64: - reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off; + reg_value = (uint32_t)m_fpr.fxstate.fx_ip.fa_32.fa_off; break; case lldb_foseg_x86_64: - reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_dp.fa_64; + reg_value = (uint64_t)m_fpr.fxstate.fx_dp.fa_64; break; case lldb_fooff_x86_64: - reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off; + reg_value = (uint32_t)m_fpr.fxstate.fx_dp.fa_32.fa_off; break; case lldb_mxcsr_x86_64: - reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr; + reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr; break; case lldb_mxcsrmask_x86_64: - reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr_mask; + reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr_mask; break; case lldb_st0_x86_64: case lldb_st1_x86_64: @@ -406,7 +682,7 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, case lldb_st5_x86_64: case lldb_st6_x86_64: case lldb_st7_x86_64: - reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64], + reg_value.SetBytes(&m_fpr.fxstate.fx_87_ac[reg - lldb_st0_x86_64], reg_info->byte_size, endian::InlHostByteOrder()); break; case lldb_mm0_x86_64: @@ -417,7 +693,7 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, case lldb_mm5_x86_64: case lldb_mm6_x86_64: case lldb_mm7_x86_64: - reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], + reg_value.SetBytes(&m_fpr.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], reg_info->byte_size, endian::InlHostByteOrder()); break; case lldb_xmm0_x86_64: @@ -436,7 +712,7 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, case lldb_xmm13_x86_64: case lldb_xmm14_x86_64: case lldb_xmm15_x86_64: - reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], + reg_value.SetBytes(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], reg_info->byte_size, endian::InlHostByteOrder()); break; case lldb_ymm0_x86_64: @@ -456,15 +732,15 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, case lldb_ymm14_x86_64: case lldb_ymm15_x86_64: #ifdef HAVE_XSTATE - if (!(m_xstate_x86_64.xs_rfbm & XCR0_SSE) || - !(m_xstate_x86_64.xs_rfbm & XCR0_YMM_Hi128)) { + if (!(m_xstate.xs_rfbm & XCR0_SSE) || + !(m_xstate.xs_rfbm & XCR0_YMM_Hi128)) { error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel", reg_info->name); } else { uint32_t reg_index = reg - lldb_ymm0_x86_64; YMMReg ymm = XStateToYMM( - m_xstate_x86_64.xs_fxsave.fx_xmm[reg_index].xmm_bytes, - m_xstate_x86_64.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes); + m_xstate.xs_fxsave.fx_xmm[reg_index].xmm_bytes, + m_xstate.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes); reg_value.SetBytes(ymm.bytes, reg_info->byte_size, endian::InlHostByteOrder()); } @@ -480,7 +756,7 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, case lldb_dr5_x86_64: case lldb_dr6_x86_64: case lldb_dr7_x86_64: - reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64]; + reg_value = (uint64_t)m_dbr.dr[reg - lldb_dr0_x86_64]; break; } @@ -497,7 +773,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( return error; } - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg == LLDB_INVALID_REGNUM) { // This is likely an internal register for lldb use only and should not be // directly queried. @@ -516,112 +792,175 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( return error; } + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86_64: + break; + case llvm::Triple::x86: + reg = RegNumX86ToX86_64(reg); + break; + default: + assert(false && "Unhandled target architecture."); + error.SetErrorString("Unhandled target architecture."); + return error; + } + error = ReadRegisterSet(set); if (error.Fail()) return error; switch (reg) { +#if defined(__x86_64__) case lldb_rax_x86_64: - m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RAX] = reg_value.GetAsUInt64(); break; case lldb_rbx_x86_64: - m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RBX] = reg_value.GetAsUInt64(); break; case lldb_rcx_x86_64: - m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RCX] = reg_value.GetAsUInt64(); break; case lldb_rdx_x86_64: - m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RDX] = reg_value.GetAsUInt64(); break; case lldb_rdi_x86_64: - m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RDI] = reg_value.GetAsUInt64(); break; case lldb_rsi_x86_64: - m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RSI] = reg_value.GetAsUInt64(); break; case lldb_rbp_x86_64: - m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RBP] = reg_value.GetAsUInt64(); break; case lldb_rsp_x86_64: - m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RSP] = reg_value.GetAsUInt64(); break; case lldb_r8_x86_64: - m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_R8] = reg_value.GetAsUInt64(); break; case lldb_r9_x86_64: - m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_R9] = reg_value.GetAsUInt64(); break; case lldb_r10_x86_64: - m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_R10] = reg_value.GetAsUInt64(); break; case lldb_r11_x86_64: - m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_R11] = reg_value.GetAsUInt64(); break; case lldb_r12_x86_64: - m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_R12] = reg_value.GetAsUInt64(); break; case lldb_r13_x86_64: - m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_R13] = reg_value.GetAsUInt64(); break; case lldb_r14_x86_64: - m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_R14] = reg_value.GetAsUInt64(); break; case lldb_r15_x86_64: - m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_R15] = reg_value.GetAsUInt64(); break; case lldb_rip_x86_64: - m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RIP] = reg_value.GetAsUInt64(); break; case lldb_rflags_x86_64: - m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_RFLAGS] = reg_value.GetAsUInt64(); break; case lldb_cs_x86_64: - m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_CS] = reg_value.GetAsUInt64(); break; case lldb_fs_x86_64: - m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_FS] = reg_value.GetAsUInt64(); break; case lldb_gs_x86_64: - m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_GS] = reg_value.GetAsUInt64(); break; case lldb_ss_x86_64: - m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_SS] = reg_value.GetAsUInt64(); break; case lldb_ds_x86_64: - m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_DS] = reg_value.GetAsUInt64(); break; case lldb_es_x86_64: - m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64(); + m_gpr.regs[_REG_ES] = reg_value.GetAsUInt64(); break; +#else + case lldb_rax_x86_64: + m_gpr.r_eax = reg_value.GetAsUInt32(); + break; + case lldb_rbx_x86_64: + m_gpr.r_ebx = reg_value.GetAsUInt32(); + break; + case lldb_rcx_x86_64: + m_gpr.r_ecx = reg_value.GetAsUInt32(); + break; + case lldb_rdx_x86_64: + m_gpr.r_edx = reg_value.GetAsUInt32(); + break; + case lldb_rdi_x86_64: + m_gpr.r_edi = reg_value.GetAsUInt32(); + break; + case lldb_rsi_x86_64: + m_gpr.r_esi = reg_value.GetAsUInt32(); + break; + case lldb_rsp_x86_64: + m_gpr.r_esp = reg_value.GetAsUInt32(); + break; + case lldb_rbp_x86_64: + m_gpr.r_ebp = reg_value.GetAsUInt32(); + break; + case lldb_rip_x86_64: + m_gpr.r_eip = reg_value.GetAsUInt32(); + break; + case lldb_rflags_x86_64: + m_gpr.r_eflags = reg_value.GetAsUInt32(); + break; + case lldb_cs_x86_64: + m_gpr.r_cs = reg_value.GetAsUInt32(); + break; + case lldb_fs_x86_64: + m_gpr.r_fs = reg_value.GetAsUInt32(); + break; + case lldb_gs_x86_64: + m_gpr.r_gs = reg_value.GetAsUInt32(); + break; + case lldb_ss_x86_64: + m_gpr.r_ss = reg_value.GetAsUInt32(); + break; + case lldb_ds_x86_64: + m_gpr.r_ds = reg_value.GetAsUInt32(); + break; + case lldb_es_x86_64: + m_gpr.r_es = reg_value.GetAsUInt32(); + break; +#endif case lldb_fctrl_x86_64: - m_fpr_x86_64.fxstate.fx_cw = reg_value.GetAsUInt16(); + m_fpr.fxstate.fx_cw = reg_value.GetAsUInt16(); break; case lldb_fstat_x86_64: - m_fpr_x86_64.fxstate.fx_sw = reg_value.GetAsUInt16(); + m_fpr.fxstate.fx_sw = reg_value.GetAsUInt16(); break; case lldb_ftag_x86_64: - m_fpr_x86_64.fxstate.fx_tw = reg_value.GetAsUInt8(); + m_fpr.fxstate.fx_tw = reg_value.GetAsUInt8(); break; case lldb_fop_x86_64: - m_fpr_x86_64.fxstate.fx_opcode = reg_value.GetAsUInt16(); + m_fpr.fxstate.fx_opcode = reg_value.GetAsUInt16(); break; case lldb_fiseg_x86_64: - m_fpr_x86_64.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64(); + m_fpr.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64(); break; case lldb_fioff_x86_64: - m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32(); + m_fpr.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32(); break; case lldb_foseg_x86_64: - m_fpr_x86_64.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64(); + m_fpr.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64(); break; case lldb_fooff_x86_64: - m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32(); + m_fpr.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32(); break; case lldb_mxcsr_x86_64: - m_fpr_x86_64.fxstate.fx_mxcsr = reg_value.GetAsUInt32(); + m_fpr.fxstate.fx_mxcsr = reg_value.GetAsUInt32(); break; case lldb_mxcsrmask_x86_64: - m_fpr_x86_64.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32(); + m_fpr.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32(); break; case lldb_st0_x86_64: case lldb_st1_x86_64: @@ -631,7 +970,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( case lldb_st5_x86_64: case lldb_st6_x86_64: case lldb_st7_x86_64: - ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64], + ::memcpy(&m_fpr.fxstate.fx_87_ac[reg - lldb_st0_x86_64], reg_value.GetBytes(), reg_value.GetByteSize()); break; case lldb_mm0_x86_64: @@ -642,7 +981,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( case lldb_mm5_x86_64: case lldb_mm6_x86_64: case lldb_mm7_x86_64: - ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], + ::memcpy(&m_fpr.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], reg_value.GetBytes(), reg_value.GetByteSize()); break; case lldb_xmm0_x86_64: @@ -661,7 +1000,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( case lldb_xmm13_x86_64: case lldb_xmm14_x86_64: case lldb_xmm15_x86_64: - ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], + ::memcpy(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], reg_value.GetBytes(), reg_value.GetByteSize()); break; case lldb_ymm0_x86_64: @@ -681,8 +1020,8 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( case lldb_ymm14_x86_64: case lldb_ymm15_x86_64: #ifdef HAVE_XSTATE - if (!(m_xstate_x86_64.xs_rfbm & XCR0_SSE) || - !(m_xstate_x86_64.xs_rfbm & XCR0_YMM_Hi128)) { + if (!(m_xstate.xs_rfbm & XCR0_SSE) || + !(m_xstate.xs_rfbm & XCR0_YMM_Hi128)) { error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel", reg_info->name); } else { @@ -690,8 +1029,8 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( YMMReg ymm; ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize()); YMMToXState(ymm, - m_xstate_x86_64.xs_fxsave.fx_xmm[reg_index].xmm_bytes, - m_xstate_x86_64.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes); + m_xstate.xs_fxsave.fx_xmm[reg_index].xmm_bytes, + m_xstate.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes); } #else error.SetErrorString("XState not supported by the kernel"); @@ -705,7 +1044,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( case lldb_dr5_x86_64: case lldb_dr6_x86_64: case lldb_dr7_x86_64: - m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64(); + m_dbr.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64(); break; } @@ -722,7 +1061,7 @@ Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues( return error; uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize()); + ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize()); dst += GetRegisterInfoInterface().GetGPRSize(); return error; @@ -742,7 +1081,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { error.SetErrorStringWithFormat( "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, + "data size, expected %zu, actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); return error; } @@ -755,7 +1094,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( __FUNCTION__); return error; } - ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize()); + ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize()); error = WriteRegisterSet(GPRegSet); if (error.Fail()) @@ -765,13 +1104,25 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( return error; } +int NativeRegisterContextNetBSD_x86_64::GetDR(int num) const { + assert(num >= 0 && num <= 7); + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + return lldb_dr0_i386 + num; + case llvm::Triple::x86_64: + return lldb_dr0_x86_64 + num; + default: + return -1; + } +} + Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index, bool &is_hit) { if (wp_index >= NumSupportedHardwareWatchpoints()) return Status("Watchpoint index out of range"); RegisterValue reg_value; - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64); + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(6)); Status error = ReadRegister(reg_info, reg_value); if (error.Fail()) { is_hit = false; @@ -808,7 +1159,7 @@ Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index, return Status("Watchpoint index out of range"); RegisterValue reg_value; - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64); + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(7)); Status error = ReadRegister(reg_info, reg_value); if (error.Fail()) { is_vacant = false; @@ -848,8 +1199,7 @@ Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( if (!is_vacant) return Status("Watchpoint index not vacant"); - const RegisterInfo *const reg_info_dr7 = - GetRegisterInfoAtIndex(lldb_dr7_x86_64); + const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); RegisterValue dr7_value; error = ReadRegister(reg_info_dr7, dr7_value); if (error.Fail()) @@ -874,7 +1224,7 @@ Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( control_bits |= enable_bit | rw_bits | size_bits; const RegisterInfo *const reg_info_drN = - GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index); + GetRegisterInfoAtIndex(GetDR(wp_index)); RegisterValue drN_value; error = ReadRegister(reg_info_drN, drN_value); if (error.Fail()) @@ -906,8 +1256,7 @@ bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0-1, 2-3, 4-5 // or 6-7 of the debug control register (DR7) - const RegisterInfo *const reg_info_dr7 = - GetRegisterInfoAtIndex(lldb_dr7_x86_64); + const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); RegisterValue reg_value; Status error = ReadRegister(reg_info_dr7, reg_value); if (error.Fail()) @@ -924,8 +1273,7 @@ Status NativeRegisterContextNetBSD_x86_64::ClearWatchpointHit(uint32_t wp_index) // for watchpoints 0, 1, 2, or 3, respectively, check bits 0, 1, 2, or 3 of // the debug status register (DR6) - const RegisterInfo *const reg_info_dr6 = - GetRegisterInfoAtIndex(lldb_dr6_x86_64); + const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6)); RegisterValue reg_value; Status error = ReadRegister(reg_info_dr6, reg_value); if (error.Fail()) @@ -940,8 +1288,7 @@ Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() { RegisterValue reg_value; // clear bits {0-4} of the debug status register (DR6) - const RegisterInfo *const reg_info_dr6 = - GetRegisterInfoAtIndex(lldb_dr6_x86_64); + const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6)); Status error = ReadRegister(reg_info_dr6, reg_value); if (error.Fail()) return error; @@ -952,8 +1299,7 @@ Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() { return error; // clear bits {0-7,16-31} of the debug control register (DR7) - const RegisterInfo *const reg_info_dr7 = - GetRegisterInfoAtIndex(lldb_dr7_x86_64); + const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); error = ReadRegister(reg_info_dr7, reg_value); if (error.Fail()) return error; @@ -988,7 +1334,7 @@ NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) { return LLDB_INVALID_ADDRESS; RegisterValue reg_value; const RegisterInfo *const reg_info_drN = - GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index); + GetRegisterInfoAtIndex(GetDR(wp_index)); if (ReadRegister(reg_info_drN, reg_value).Fail()) return LLDB_INVALID_ADDRESS; return reg_value.GetAsUInt64(); @@ -1005,10 +1351,10 @@ Status NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom( Status res = r_source.ReadRegisterSet(DBRegSet); if (!res.Fail()) { // copy dbregs only if any watchpoints were set - if ((r_source.m_dbr_x86_64.dr[7] & 0xFF) == 0) + if ((r_source.m_dbr.dr[7] & 0xFF) == 0) return res; - m_dbr_x86_64 = r_source.m_dbr_x86_64; + m_dbr = r_source.m_dbr; res = WriteRegisterSet(DBRegSet); } return res; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h index 54b8a806267f..6c0632f3bce8 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#if defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #ifndef lldb_NativeRegisterContextNetBSD_x86_64_h #define lldb_NativeRegisterContextNetBSD_x86_64_h @@ -81,14 +81,19 @@ private: enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet }; // Private member variables. - struct reg m_gpr_x86_64; - struct fpreg m_fpr_x86_64; - struct dbreg m_dbr_x86_64; + struct reg m_gpr; +#if defined(__x86_64__) + struct fpreg m_fpr; +#else + struct xmmregs m_fpr; +#endif + struct dbreg m_dbr; #ifdef HAVE_XSTATE - struct xstate m_xstate_x86_64; + struct xstate m_xstate; #endif int GetSetForNativeRegNum(int reg_num) const; + int GetDR(int num) const; Status ReadRegisterSet(uint32_t set); Status WriteRegisterSet(uint32_t set); diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index dd2745d9330e..fe76fb40e0b3 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -1,4 +1,4 @@ -//===-- NativeThreadNetBSD.cpp -------------------------------- -*- C++ -*-===// +//===-- NativeThreadNetBSD.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp index b872269fdfe1..579077b45bf9 100644 --- a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp +++ b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp @@ -1,4 +1,4 @@ -//===-- CrashReason.cpp -----------------------------------------*- C++ -*-===// +//===-- CrashReason.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp index 058dc5ae2338..117d12101a0b 100644 --- a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp +++ b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp @@ -1,4 +1,4 @@ -//===-- NativeProcessELF.cpp ---------------------------------- -*- C++ -*-===// +//===-- NativeProcessELF.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -107,6 +107,11 @@ lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() { return LLDB_INVALID_ADDRESS; } +template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress< + llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>(); +template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress< + llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>(); + template <typename T> llvm::Expected<SVR4LibraryInfo> NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) { diff --git a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h index 4fb513baebf0..dcfa9290ff50 100644 --- a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h +++ b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h @@ -48,6 +48,14 @@ protected: llvm::Optional<lldb::addr_t> m_shared_library_info_addr; }; +// Explicitly declare the two 32/64 bit templates that NativeProcessELF.cpp will +// define. This allows us to keep the template definition here and usable +// elsewhere. +extern template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress< + llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>(); +extern template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress< + llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>(); + } // namespace lldb_private -#endif
\ No newline at end of file +#endif diff --git a/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp b/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp index 66286dd3d9e3..4e8c6f1ba2d2 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp +++ b/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp @@ -1,4 +1,4 @@ -//===-- ProcessMessage.cpp --------------------------------------*- C++ -*-===// +//===-- ProcessMessage.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp index a17558bfe7c6..f4d0803b264a 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp @@ -1,5 +1,4 @@ -//===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++ -//-*-===// +//===-- ProcessPOSIXLog.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/ARMDefines.h b/lldb/source/Plugins/Process/Utility/ARMDefines.h index 1f7eb54d10e7..fd3965fade19 100644 --- a/lldb/source/Plugins/Process/Utility/ARMDefines.h +++ b/lldb/source/Plugins/Process/Utility/ARMDefines.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_ARMDefines_h_ -#define lldb_ARMDefines_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMDEFINES_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMDEFINES_H #include "llvm/Support/ErrorHandling.h" @@ -188,4 +188,4 @@ static inline bool ARMConditionPassed(const uint32_t condition, } // namespace lldb_private -#endif // lldb_ARMDefines_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMDEFINES_H diff --git a/lldb/source/Plugins/Process/Utility/ARMUtils.h b/lldb/source/Plugins/Process/Utility/ARMUtils.h index d860348818d3..bbe4c9a35fa6 100644 --- a/lldb/source/Plugins/Process/Utility/ARMUtils.h +++ b/lldb/source/Plugins/Process/Utility/ARMUtils.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_ARMUtils_h_ -#define lldb_ARMUtils_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H #include "ARMDefines.h" #include "InstructionUtils.h" @@ -371,4 +371,4 @@ static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; } } // namespace lldb_private -#endif // lldb_ARMUtils_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.cpp b/lldb/source/Plugins/Process/Utility/AuxVector.cpp index 25a1d0b5af06..685d9d0824f6 100644 --- a/lldb/source/Plugins/Process/Utility/AuxVector.cpp +++ b/lldb/source/Plugins/Process/Utility/AuxVector.cpp @@ -1,4 +1,4 @@ -//===-- AuxVector.cpp -------------------------------------------*- C++ -*-===// +//===-- AuxVector.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h index c16be68aedb1..c8c8b1249413 100644 --- a/lldb/source/Plugins/Process/Utility/AuxVector.h +++ b/lldb/source/Plugins/Process/Utility/AuxVector.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_AuxVector_H_ -#define liblldb_AuxVector_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_AUXVECTOR_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_AUXVECTOR_H #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index a86880af2260..443638aa39f6 100644 --- a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -1,4 +1,4 @@ -//===-- DynamicRegisterInfo.cpp ----------------------------*- C++ -*-===// +//===-- DynamicRegisterInfo.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -742,6 +742,8 @@ const lldb_private::RegisterInfo *DynamicRegisterInfo::GetRegisterInfo( for (auto ®_info : m_regs) { // We can use pointer comparison since we used a ConstString to set the // "name" member in AddRegister() + assert(ConstString(reg_info.name).GetCString() == reg_info.name && + "reg_info.name not from a ConstString?"); if (reg_info.name == reg_name.GetCString()) { return ®_info; } diff --git a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h index aacf547e187d..48939375a504 100644 --- a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_DynamicRegisterInfo_h_ -#define lldb_DynamicRegisterInfo_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H #include <map> #include <vector> @@ -90,4 +90,4 @@ protected: // all registers bool m_finalized = false; }; -#endif // lldb_DynamicRegisterInfo_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H diff --git a/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp index 9f63a594e054..0a4bdc72b364 100644 --- a/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp @@ -1,4 +1,4 @@ -//===-- FreeBSDSignals.cpp --------------------------------------*- C++ -*-===// +//===-- FreeBSDSignals.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h b/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h index 75462f3c76ff..c4c810e54985 100644 --- a/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h +++ b/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_FreeBSDSignals_H_ -#define liblldb_FreeBSDSignals_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_FREEBSDSIGNALS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_FREEBSDSIGNALS_H #include "lldb/Target/UnixSignals.h" @@ -24,4 +24,4 @@ private: } // namespace lldb_private -#endif // liblldb_FreeBSDSignals_H_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_FREEBSDSIGNALS_H diff --git a/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp b/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp index ed35273ce3fe..427225c14d3b 100644 --- a/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteSignals.cpp ------------------------------------*- C++ -*-===// +//===-- GDBRemoteSignals.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h b/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h index a02dd0604e67..d37757ab60a5 100644 --- a/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h +++ b/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteSignals_H_ -#define liblldb_GDBRemoteSignals_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_GDBREMOTESIGNALS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_GDBREMOTESIGNALS_H #include "lldb/Target/UnixSignals.h" @@ -26,4 +26,4 @@ private: } // namespace lldb_private -#endif // liblldb_GDBRemoteSignals_H_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_GDBREMOTESIGNALS_H diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp index 295c17e474fb..d73b132539f1 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp @@ -1,4 +1,4 @@ -//===-- HistoryThread.cpp ---------------------------------------*- C++ -*-===// +//===-- HistoryThread.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -25,12 +25,14 @@ using namespace lldb_private; // Constructor HistoryThread::HistoryThread(lldb_private::Process &process, lldb::tid_t tid, - std::vector<lldb::addr_t> pcs) + std::vector<lldb::addr_t> pcs, + bool pcs_are_call_addresses) : Thread(process, tid, true), m_framelist_mutex(), m_framelist(), m_pcs(pcs), m_extended_unwind_token(LLDB_INVALID_ADDRESS), m_queue_name(), m_thread_name(), m_originating_unique_thread_id(tid), m_queue_id(LLDB_INVALID_QUEUE_ID) { - m_unwinder_up.reset(new HistoryUnwind(*this, pcs)); + m_unwinder_up = + std::make_unique<HistoryUnwind>(*this, pcs, pcs_are_call_addresses); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); LLDB_LOGF(log, "%p HistoryThread::HistoryThread", static_cast<void *>(this)); } diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.h b/lldb/source/Plugins/Process/Utility/HistoryThread.h index 1e2658640172..a66e0f2d4207 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryThread.h +++ b/lldb/source/Plugins/Process/Utility/HistoryThread.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_HistoryThread_h_ -#define liblldb_HistoryThread_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYTHREAD_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYTHREAD_H #include <mutex> @@ -33,7 +33,8 @@ namespace lldb_private { class HistoryThread : public lldb_private::Thread { public: HistoryThread(lldb_private::Process &process, lldb::tid_t tid, - std::vector<lldb::addr_t> pcs); + std::vector<lldb::addr_t> pcs, + bool pcs_are_call_addresses = false); ~HistoryThread() override; @@ -88,4 +89,4 @@ protected: } // namespace lldb_private -#endif // liblldb_HistoryThread_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYTHREAD_H diff --git a/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp b/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp index 83fdb011f5a1..9b9522955de9 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp +++ b/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -1,4 +1,4 @@ -//===-- HistoryUnwind.cpp ---------------------------------------*- C++ -*-===// +//===-- HistoryUnwind.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -23,8 +23,10 @@ using namespace lldb_private; // Constructor -HistoryUnwind::HistoryUnwind(Thread &thread, std::vector<lldb::addr_t> pcs) - : Unwind(thread), m_pcs(pcs) {} +HistoryUnwind::HistoryUnwind(Thread &thread, std::vector<lldb::addr_t> pcs, + bool pcs_are_call_addresses) + : Unwind(thread), m_pcs(pcs), + m_pcs_are_call_addresses(pcs_are_call_addresses) {} // Destructor @@ -59,7 +61,10 @@ bool HistoryUnwind::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, if (frame_idx < m_pcs.size()) { cfa = frame_idx; pc = m_pcs[frame_idx]; - behaves_like_zeroth_frame = (frame_idx == 0); + if (m_pcs_are_call_addresses) + behaves_like_zeroth_frame = true; + else + behaves_like_zeroth_frame = (frame_idx == 0); return true; } return false; diff --git a/lldb/source/Plugins/Process/Utility/HistoryUnwind.h b/lldb/source/Plugins/Process/Utility/HistoryUnwind.h index 4d16608bd8c2..cb72b5d0a176 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryUnwind.h +++ b/lldb/source/Plugins/Process/Utility/HistoryUnwind.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_HistoryUnwind_h_ -#define liblldb_HistoryUnwind_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYUNWIND_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYUNWIND_H #include <vector> @@ -18,7 +18,8 @@ namespace lldb_private { class HistoryUnwind : public lldb_private::Unwind { public: - HistoryUnwind(Thread &thread, std::vector<lldb::addr_t> pcs); + HistoryUnwind(Thread &thread, std::vector<lldb::addr_t> pcs, + bool pcs_are_call_addresses = false); ~HistoryUnwind() override; @@ -35,8 +36,11 @@ protected: private: std::vector<lldb::addr_t> m_pcs; + /// This boolean indicates that the PCs in the non-0 frames are call + /// addresses and not return addresses. + bool m_pcs_are_call_addresses; }; } // namespace lldb_private -#endif // liblldb_HistoryUnwind_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYUNWIND_H diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index ee939b01d350..0f331933f2ea 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -1,4 +1,4 @@ -//===-- InferiorCallPOSIX.cpp -----------------------------------*- C++ -*-===// +//===-- InferiorCallPOSIX.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h index 2008c5fe0b91..3623e10194f9 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_InferiorCallPOSIX_h_ -#define lldb_InferiorCallPOSIX_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INFERIORCALLPOSIX_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INFERIORCALLPOSIX_H // Inferior execution of POSIX functions. @@ -32,4 +32,4 @@ bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length); } // namespace lldb_private -#endif // lldb_InferiorCallPOSIX_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INFERIORCALLPOSIX_H diff --git a/lldb/source/Plugins/Process/Utility/InstructionUtils.h b/lldb/source/Plugins/Process/Utility/InstructionUtils.h index f74933e691ee..55b89440700b 100644 --- a/lldb/source/Plugins/Process/Utility/InstructionUtils.h +++ b/lldb/source/Plugins/Process/Utility/InstructionUtils.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_InstructionUtils_h_ -#define lldb_InstructionUtils_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INSTRUCTIONUTILS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INSTRUCTIONUTILS_H #include <cassert> #include <cstdint> @@ -113,4 +113,4 @@ static inline int64_t SignedBits(const uint64_t value, const uint64_t msbit, } // namespace lldb_private -#endif // lldb_InstructionUtils_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INSTRUCTIONUTILS_H diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp index 1ba432aa542b..0c7d9ddc5ac6 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp @@ -1,4 +1,4 @@ -//===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===// +//===-- LinuxProcMaps.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h index e1f0e48ac5c9..363f248fd416 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h +++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_LinuxProcMaps_H_ -#define liblldb_LinuxProcMaps_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCMAPS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCMAPS_H #include "lldb/lldb-forward.h" #include "llvm/ADT/StringRef.h" @@ -24,4 +24,4 @@ void ParseLinuxMapRegions(llvm::StringRef linux_map, } // namespace lldb_private -#endif // liblldb_LinuxProcMaps_H_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCMAPS_H diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index bef47cd26307..4dd619e3bade 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -1,4 +1,4 @@ -//===-- LinuxSignals.cpp ----------------------------------------*- C++ -*-===// +//===-- LinuxSignals.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.h b/lldb/source/Plugins/Process/Utility/LinuxSignals.h index 7ad8cfcbef68..32c4744a96d0 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.h +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_LinuxSignals_H_ -#define liblldb_LinuxSignals_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXSIGNALS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXSIGNALS_H #include "lldb/Target/UnixSignals.h" @@ -24,4 +24,4 @@ private: } // namespace lldb_private -#endif // liblldb_LinuxSignals_H_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXSIGNALS_H diff --git a/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp index d8e5426ab5a5..8f75844277c0 100644 --- a/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp @@ -1,5 +1,4 @@ -//===-- MipsLinuxSignals.cpp ----------------------------------------*- C++ -//-*-===// +//===-- MipsLinuxSignals.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.h b/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.h index b5e3ed86f568..6b78fc72a91c 100644 --- a/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.h +++ b/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_MipsLinuxSignals_H_ -#define liblldb_MipsLinuxSignals_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MIPSLINUXSIGNALS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MIPSLINUXSIGNALS_H #include "lldb/Target/UnixSignals.h" @@ -25,4 +25,4 @@ private: } // namespace lldb_private -#endif // liblldb_MipsLinuxSignals_H_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MIPSLINUXSIGNALS_H diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp index be61cfdd7374..3a875f7bb39b 100644 --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp @@ -1,4 +1,4 @@ -//===-- NativeRegisterContextRegisterInfo.cpp -------------------*- C++ -*-===// +//===-- NativeRegisterContextRegisterInfo.cpp -----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h index b285c477cd96..0e96841fd909 100644 --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_PROCESS_UTIILTY_NATIVE_REGISTER_CONTEXT_REGISTER_INFO -#define LLDB_PLUGINS_PROCESS_UTIILTY_NATIVE_REGISTER_CONTEXT_REGISTER_INFO +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NATIVEREGISTERCONTEXTREGISTERINFO_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NATIVEREGISTERCONTEXTREGISTERINFO_H #include <memory> @@ -33,7 +33,7 @@ public: const RegisterInfoInterface &GetRegisterInfoInterface() const; -private: +protected: std::unique_ptr<RegisterInfoInterface> m_register_info_interface_up; }; } diff --git a/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp b/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp index 29967deb7e9b..ffdfd19b4efe 100644 --- a/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp @@ -1,4 +1,4 @@ -//===-- NetBSDSignals.cpp --------------------------------------*- C++ -*-===// +//===-- NetBSDSignals.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/NetBSDSignals.h b/lldb/source/Plugins/Process/Utility/NetBSDSignals.h index bf7399a89060..e6740a304a02 100644 --- a/lldb/source/Plugins/Process/Utility/NetBSDSignals.h +++ b/lldb/source/Plugins/Process/Utility/NetBSDSignals.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_NetBSDSignals_H_ -#define liblldb_NetBSDSignals_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NETBSDSIGNALS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NETBSDSIGNALS_H #include "lldb/Target/UnixSignals.h" @@ -24,4 +24,4 @@ private: } // namespace lldb_private -#endif // liblldb_NetBSDSignals_H_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NETBSDSIGNALS_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h b/lldb/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h index ef40162984f1..21582df91fb0 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_REGISTERCONTEXTDARWINCONSTANTS_H -#define LLDB_REGISTERCONTEXTDARWINCONSTANTS_H +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWINCONSTANTS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWINCONSTANTS_H namespace lldb_private { @@ -22,4 +22,4 @@ namespace lldb_private { } // namespace lldb_private -#endif // LLDB_REGISTERCONTEXTDARWINCONSTANTS_H +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWINCONSTANTS_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp index 173e66904151..eef4541e7edd 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextDarwin_arm.cpp ---------------------------*- C++ -*-===// +//===-- RegisterContextDarwin_arm.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h index d7c1809a3222..1bd60f756487 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextDarwin_arm_h_ -#define liblldb_RegisterContextDarwin_arm_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM_H #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" @@ -261,4 +261,4 @@ protected: static const lldb_private::RegisterInfo *GetRegisterInfos(); }; -#endif // liblldb_RegisterContextDarwin_arm_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp index fa5197cd6bf4..9fc275276699 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -1,5 +1,4 @@ -//===-- RegisterContextDarwin_arm64.cpp ---------------------------*- C++ -//-*-===// +//===-- RegisterContextDarwin_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. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h index abb87e3c2348..010e566be32c 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextDarwin_arm64_h_ -#define liblldb_RegisterContextDarwin_arm64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" @@ -228,4 +228,4 @@ protected: static const lldb_private::RegisterInfo *GetRegisterInfos(); }; -#endif // liblldb_RegisterContextDarwin_arm64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp index 959b04700b17..c5ebddc56b6c 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextDarwin_i386.cpp --------------------------*- C++ -*-===// +//===-- RegisterContextDarwin_i386.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h index e52f0fe63250..9c759c31caed 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextDarwin_i386_h_ -#define liblldb_RegisterContextDarwin_i386_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_I386_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_I386_H #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" @@ -205,4 +205,4 @@ protected: static const lldb_private::RegisterInfo *GetRegisterInfos(); }; -#endif // liblldb_RegisterContextDarwin_i386_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_I386_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp index 22088a7d6448..38cd00aea9cc 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextDarwin_x86_64.cpp ------------------------*- C++ -*-===// +//===-- RegisterContextDarwin_x86_64.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h index 1a65a4f28b33..d9ba8d0b2319 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextDarwin_x86_64_h_ -#define liblldb_RegisterContextDarwin_x86_64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_X86_64_H #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" @@ -210,4 +210,4 @@ protected: static const lldb_private::RegisterInfo *GetRegisterInfos(); }; -#endif // liblldb_RegisterContextDarwin_x86_64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_X86_64_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp index 6832b6095931..4c2e291c62d6 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp @@ -1,5 +1,4 @@ -//===-- RegisterContextDummy.cpp ---------------------------------*- C++ -//-*-===// +//===-- RegisterContextDummy.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h b/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h index bdaa2217d207..de98767693fe 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_RegisterContextDummy_h_ -#define lldb_RegisterContextDummy_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDUMMY_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDUMMY_H #include <vector> @@ -56,9 +56,10 @@ private: lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only) lldb_private::RegisterInfo m_pc_reg_info; - DISALLOW_COPY_AND_ASSIGN(RegisterContextDummy); + RegisterContextDummy(const RegisterContextDummy &) = delete; + const RegisterContextDummy &operator=(const RegisterContextDummy &) = delete; }; } // namespace lldb_private -#endif // lldb_RegisterContextDummy_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDUMMY_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp index b90b38108267..10d346a3cb7e 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextFreeBSD_i386.cpp ------------------------*- C++ -*-===// +//===-- RegisterContextFreeBSD_i386.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h index 7aadf3a0a4c9..5a3e5b0551d6 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextFreeBSD_i386_H_ -#define liblldb_RegisterContextFreeBSD_i386_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_I386_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_I386_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp index 4331ef5ad14e..0c5d34f345db 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextFreeBSD_mips64.cpp ----------------------*- C++ -*-===// +//===-- RegisterContextFreeBSD_mips64.cpp ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h index 96f02b4440c5..39968eacf475 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextFreeBSD_mips64_H_ -#define liblldb_RegisterContextFreeBSD_mips64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_MIPS64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_MIPS64_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp index 4f869eb3b177..9fe6255d698e 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextFreeBSD_powerpc.cpp ----------------------*- C++ -*-===// +//===-- RegisterContextFreeBSD_powerpc.cpp --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h index ba2751194d16..7e4c43ba908a 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextFreeBSD_powerpc_h_ -#define liblldb_RegisterContextFreeBSD_powerpc_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_POWERPC_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_POWERPC_H #include "RegisterInfoInterface.h" @@ -49,4 +49,4 @@ public: uint32_t GetRegisterCount() const override; }; -#endif // liblldb_RegisterContextFreeBSD_powerpc_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_POWERPC_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp index bcf3951ee077..c1f390ade9b9 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextFreeBSD_x86_64.cpp ----------------------*- C++ -*-===// +//===-- RegisterContextFreeBSD_x86_64.cpp ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h index c379e1a5cd75..d0f69fde1817 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextFreeBSD_x86_64_H_ -#define liblldb_RegisterContextFreeBSD_x86_64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_X86_64_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp index c19a2bfae668..577958738900 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp @@ -1,5 +1,4 @@ -//===-- RegisterContextHistory.cpp ---------------------------------*- C++ -//-*-===// +//===-- RegisterContextHistory.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h b/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h index 952e4263d955..407640d2bdb9 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_RegisterContextHistory_h_ -#define lldb_RegisterContextHistory_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTHISTORY_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTHISTORY_H #include <vector> @@ -58,8 +58,10 @@ private: lldb::addr_t m_pc_value; - DISALLOW_COPY_AND_ASSIGN(RegisterContextHistory); + RegisterContextHistory(const RegisterContextHistory &) = delete; + const RegisterContextHistory & + operator=(const RegisterContextHistory &) = delete; }; } // namespace lldb_private -#endif // lldb_RegisterContextHistory_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTHISTORY_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp deleted file mode 100644 index 49a589f14989..000000000000 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ /dev/null @@ -1,2198 +0,0 @@ -//===-- RegisterContextLLDB.cpp --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Core/Address.h" -#include "lldb/Core/AddressRange.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/Value.h" -#include "lldb/Expression/DWARFExpression.h" -#include "lldb/Symbol/ArmUnwindInfo.h" -#include "lldb/Symbol/CallFrameInfo.h" -#include "lldb/Symbol/DWARFCallFrameInfo.h" -#include "lldb/Symbol/FuncUnwinders.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/Symbol.h" -#include "lldb/Symbol/SymbolContext.h" -#include "lldb/Symbol/SymbolFile.h" -#include "lldb/Target/ABI.h" -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Platform.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/SectionLoadList.h" -#include "lldb/Target/StackFrame.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/lldb-private.h" - -#include "RegisterContextLLDB.h" - -#include <memory> - -using namespace lldb; -using namespace lldb_private; - -static ConstString GetSymbolOrFunctionName(const SymbolContext &sym_ctx) { - if (sym_ctx.symbol) - return sym_ctx.symbol->GetName(); - else if (sym_ctx.function) - return sym_ctx.function->GetName(); - return ConstString(); -} - -RegisterContextLLDB::RegisterContextLLDB(Thread &thread, - const SharedPtr &next_frame, - SymbolContext &sym_ctx, - uint32_t frame_number, - UnwindLLDB &unwind_lldb) - : RegisterContext(thread, frame_number), m_thread(thread), - m_fast_unwind_plan_sp(), m_full_unwind_plan_sp(), - m_fallback_unwind_plan_sp(), m_all_registers_available(false), - m_frame_type(-1), m_cfa(LLDB_INVALID_ADDRESS), - m_afa(LLDB_INVALID_ADDRESS), m_start_pc(), - m_current_pc(), m_current_offset(0), m_current_offset_backed_up_one(0), - m_sym_ctx(sym_ctx), m_sym_ctx_valid(false), m_frame_number(frame_number), - m_registers(), m_parent_unwind(unwind_lldb) { - m_sym_ctx.Clear(false); - m_sym_ctx_valid = false; - - if (IsFrameZero()) { - InitializeZerothFrame(); - } else { - InitializeNonZerothFrame(); - } - - // This same code exists over in the GetFullUnwindPlanForFrame() but it may - // not have been executed yet - if (IsFrameZero() || next_frame->m_frame_type == eTrapHandlerFrame || - next_frame->m_frame_type == eDebuggerFrame) { - m_all_registers_available = true; - } -} - -bool RegisterContextLLDB::IsUnwindPlanValidForCurrentPC( - lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset) { - if (!unwind_plan_sp) - return false; - - // check if m_current_pc is valid - if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { - // yes - current offset can be used as is - valid_pc_offset = m_current_offset; - return true; - } - - // if m_current_offset <= 0, we've got nothing else to try - if (m_current_offset <= 0) - return false; - - // check pc - 1 to see if it's valid - Address pc_minus_one(m_current_pc); - pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1); - if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one)) { - // *valid_pc_offset = m_current_offset - 1; - valid_pc_offset = m_current_pc.GetOffset() - 1; - return true; - } - - return false; -} - -// Initialize a RegisterContextLLDB which is the first frame of a stack -- the -// zeroth frame or currently executing frame. - -void RegisterContextLLDB::InitializeZerothFrame() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - ExecutionContext exe_ctx(m_thread.shared_from_this()); - RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext(); - - if (reg_ctx_sp.get() == nullptr) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg("frame does not have a register context"); - return; - } - - addr_t current_pc = reg_ctx_sp->GetPC(); - - if (current_pc == LLDB_INVALID_ADDRESS) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg("frame does not have a pc"); - return; - } - - Process *process = exe_ctx.GetProcessPtr(); - - // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs - // this will strip bit zero in case we read a PC from memory or from the LR. - // (which would be a no-op in frame 0 where we get it from the register set, - // but still a good idea to make the call here for other ABIs that may - // exist.) - ABI *abi = process->GetABI().get(); - if (abi) - current_pc = abi->FixCodeAddress(current_pc); - - // Initialize m_current_pc, an Address object, based on current_pc, an - // addr_t. - m_current_pc.SetLoadAddress(current_pc, &process->GetTarget()); - - // If we don't have a Module for some reason, we're not going to find - // symbol/function information - just stick in some reasonable defaults and - // hope we can unwind past this frame. - ModuleSP pc_module_sp(m_current_pc.GetModule()); - if (!m_current_pc.IsValid() || !pc_module_sp) { - UnwindLogMsg("using architectural default unwind method"); - } - - AddressRange addr_range; - m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range); - - if (m_sym_ctx.symbol) { - UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'", - current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); - } else if (m_sym_ctx.function) { - UnwindLogMsg("with pc value of 0x%" PRIx64 ", function name is '%s'", - current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); - } else { - UnwindLogMsg("with pc value of 0x%" PRIx64 - ", no symbol/function name is known.", - current_pc); - } - - if (IsTrapHandlerSymbol(process, m_sym_ctx)) { - m_frame_type = eTrapHandlerFrame; - } else { - // FIXME: Detect eDebuggerFrame here. - m_frame_type = eNormalFrame; - } - - // If we were able to find a symbol/function, set addr_range to the bounds of - // that symbol/function. else treat the current pc value as the start_pc and - // record no offset. - if (addr_range.GetBaseAddress().IsValid()) { - m_start_pc = addr_range.GetBaseAddress(); - if (m_current_pc.GetSection() == m_start_pc.GetSection()) { - m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset(); - } else if (m_current_pc.GetModule() == m_start_pc.GetModule()) { - // This means that whatever symbol we kicked up isn't really correct --- - // we should not cross section boundaries ... We really should NULL out - // the function/symbol in this case unless there is a bad assumption here - // due to inlined functions? - m_current_offset = - m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress(); - } - m_current_offset_backed_up_one = m_current_offset; - } else { - m_start_pc = m_current_pc; - m_current_offset = -1; - m_current_offset_backed_up_one = -1; - } - - // We've set m_frame_type and m_sym_ctx before these calls. - - m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame(); - m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - - UnwindPlan::RowSP active_row; - lldb::RegisterKind row_register_kind = eRegisterKindGeneric; - if (m_full_unwind_plan_sp && - m_full_unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { - active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - row_register_kind = m_full_unwind_plan_sp->GetRegisterKind(); - if (active_row.get() && log) { - StreamString active_row_strm; - active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, - m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); - UnwindLogMsg("%s", active_row_strm.GetData()); - } - } - - if (!active_row.get()) { - UnwindLogMsg("could not find an unwindplan row for this frame's pc"); - m_frame_type = eNotAValidFrame; - return; - } - - if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) { - // Try the fall back unwind plan since the - // full unwind plan failed. - FuncUnwindersSP func_unwinders_sp; - UnwindPlanSP call_site_unwind_plan; - bool cfa_status = false; - - if (m_sym_ctx_valid) { - func_unwinders_sp = - pc_module_sp->GetUnwindTable().GetFuncUnwindersContainingAddress( - m_current_pc, m_sym_ctx); - } - - if (func_unwinders_sp.get() != nullptr) - call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite( - process->GetTarget(), m_thread); - - if (call_site_unwind_plan.get() != nullptr) { - m_fallback_unwind_plan_sp = call_site_unwind_plan; - if (TryFallbackUnwindPlan()) - cfa_status = true; - } - if (!cfa_status) { - UnwindLogMsg("could not read CFA value for first frame."); - m_frame_type = eNotAValidFrame; - return; - } - } else - ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa); - - UnwindLogMsg("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 - " afa is 0x%" PRIx64 " using %s UnwindPlan", - (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), - (uint64_t)m_cfa, - (uint64_t)m_afa, - m_full_unwind_plan_sp->GetSourceName().GetCString()); -} - -// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the -// RegisterContextLLDB "below" it to provide things like its current pc value. - -void RegisterContextLLDB::InitializeNonZerothFrame() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (IsFrameZero()) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg("non-zeroth frame tests positive for IsFrameZero -- that " - "shouldn't happen."); - return; - } - - if (!GetNextFrame().get() || !GetNextFrame()->IsValid()) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg("Could not get next frame, marking this frame as invalid."); - return; - } - if (!m_thread.GetRegisterContext()) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg("Could not get register context for this thread, marking this " - "frame as invalid."); - return; - } - - addr_t pc; - if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) { - UnwindLogMsg("could not get pc value"); - m_frame_type = eNotAValidFrame; - return; - } - - ExecutionContext exe_ctx(m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs - // this will strip bit zero in case we read a PC from memory or from the LR. - ABI *abi = process->GetABI().get(); - if (abi) - pc = abi->FixCodeAddress(pc); - - if (log) { - UnwindLogMsg("pc = 0x%" PRIx64, pc); - addr_t reg_val; - if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) - UnwindLogMsg("fp = 0x%" PRIx64, reg_val); - if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) - UnwindLogMsg("sp = 0x%" PRIx64, reg_val); - } - - // A pc of 0x0 means it's the end of the stack crawl unless we're above a trap - // handler function - bool above_trap_handler = false; - if (GetNextFrame().get() && GetNextFrame()->IsValid() && - GetNextFrame()->IsTrapHandlerFrame()) - above_trap_handler = true; - - if (pc == 0 || pc == 0x1) { - if (!above_trap_handler) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg("this frame has a pc of 0x0"); - return; - } - } - - const bool allow_section_end = true; - m_current_pc.SetLoadAddress(pc, &process->GetTarget(), allow_section_end); - - // If we don't have a Module for some reason, we're not going to find - // symbol/function information - just stick in some reasonable defaults and - // hope we can unwind past this frame. - ModuleSP pc_module_sp(m_current_pc.GetModule()); - if (!m_current_pc.IsValid() || !pc_module_sp) { - UnwindLogMsg("using architectural default unwind method"); - - // Test the pc value to see if we know it's in an unmapped/non-executable - // region of memory. - uint32_t permissions; - if (process->GetLoadAddressPermissions(pc, permissions) && - (permissions & ePermissionsExecutable) == 0) { - // If this is the second frame off the stack, we may have unwound the - // first frame incorrectly. But using the architecture default unwind - // plan may get us back on track -- albeit possibly skipping a real - // frame. Give this frame a clearly-invalid pc and see if we can get any - // further. - if (GetNextFrame().get() && GetNextFrame()->IsValid() && - GetNextFrame()->IsFrameZero()) { - UnwindLogMsg("had a pc of 0x%" PRIx64 " which is not in executable " - "memory but on frame 1 -- " - "allowing it once.", - (uint64_t)pc); - m_frame_type = eSkipFrame; - } else { - // anywhere other than the second frame, a non-executable pc means - // we're off in the weeds -- stop now. - m_frame_type = eNotAValidFrame; - UnwindLogMsg("pc is in a non-executable section of memory and this " - "isn't the 2nd frame in the stack walk."); - return; - } - } - - if (abi) { - m_fast_unwind_plan_sp.reset(); - m_full_unwind_plan_sp = - std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric); - abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp); - if (m_frame_type != eSkipFrame) // don't override eSkipFrame - { - m_frame_type = eNormalFrame; - } - m_all_registers_available = false; - m_current_offset = -1; - m_current_offset_backed_up_one = -1; - RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind(); - UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0); - if (row.get()) { - if (!ReadFrameAddress(row_register_kind, row->GetCFAValue(), m_cfa)) { - UnwindLogMsg("failed to get cfa value"); - if (m_frame_type != eSkipFrame) // don't override eSkipFrame - { - m_frame_type = eNotAValidFrame; - } - return; - } - - ReadFrameAddress(row_register_kind, row->GetAFAValue(), m_afa); - - // A couple of sanity checks.. - if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == 0 || m_cfa == 1) { - UnwindLogMsg("could not find a valid cfa address"); - m_frame_type = eNotAValidFrame; - return; - } - - // m_cfa should point into the stack memory; if we can query memory - // region permissions, see if the memory is allocated & readable. - if (process->GetLoadAddressPermissions(m_cfa, permissions) && - (permissions & ePermissionsReadable) == 0) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg( - "the CFA points to a region of memory that is not readable"); - return; - } - } else { - UnwindLogMsg("could not find a row for function offset zero"); - m_frame_type = eNotAValidFrame; - return; - } - - if (CheckIfLoopingStack()) { - TryFallbackUnwindPlan(); - if (CheckIfLoopingStack()) { - UnwindLogMsg("same CFA address as next frame, assuming the unwind is " - "looping - stopping"); - m_frame_type = eNotAValidFrame; - return; - } - } - - UnwindLogMsg("initialized frame cfa is 0x%" PRIx64 " afa is 0x%" PRIx64, - (uint64_t)m_cfa, (uint64_t)m_afa); - return; - } - m_frame_type = eNotAValidFrame; - UnwindLogMsg("could not find any symbol for this pc, or a default unwind " - "plan, to continue unwind."); - return; - } - - AddressRange addr_range; - m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range); - - if (m_sym_ctx.symbol) { - UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'", pc, - GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); - } else if (m_sym_ctx.function) { - UnwindLogMsg("with pc value of 0x%" PRIx64 ", function name is '%s'", pc, - GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); - } else { - UnwindLogMsg("with pc value of 0x%" PRIx64 - ", no symbol/function name is known.", - pc); - } - - bool decr_pc_and_recompute_addr_range; - - if (!m_sym_ctx_valid) { - // Always decrement and recompute if the symbol lookup failed - decr_pc_and_recompute_addr_range = true; - } else if (GetNextFrame()->m_frame_type == eTrapHandlerFrame || - GetNextFrame()->m_frame_type == eDebuggerFrame) { - // Don't decrement if we're "above" an asynchronous event like - // sigtramp. - decr_pc_and_recompute_addr_range = false; - } else if (!addr_range.GetBaseAddress().IsValid() || - addr_range.GetBaseAddress().GetSection() != m_current_pc.GetSection() || - addr_range.GetBaseAddress().GetOffset() != m_current_pc.GetOffset()) { - // If our "current" pc isn't the start of a function, no need - // to decrement and recompute. - decr_pc_and_recompute_addr_range = false; - } else if (IsTrapHandlerSymbol(process, m_sym_ctx)) { - // Signal dispatch may set the return address of the handler it calls to - // point to the first byte of a return trampoline (like __kernel_rt_sigreturn), - // so do not decrement and recompute if the symbol we already found is a trap - // handler. - decr_pc_and_recompute_addr_range = false; - } else { - // Decrement to find the function containing the call. - decr_pc_and_recompute_addr_range = true; - } - - // We need to back up the pc by 1 byte and re-search for the Symbol to handle - // the case where the "saved pc" value is pointing to the next function, e.g. - // if a function ends with a CALL instruction. - // FIXME this may need to be an architectural-dependent behavior; if so we'll - // need to add a member function - // to the ABI plugin and consult that. - if (decr_pc_and_recompute_addr_range) { - UnwindLogMsg("Backing up the pc value of 0x%" PRIx64 - " by 1 and re-doing symbol lookup; old symbol was %s", - pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); - Address temporary_pc; - temporary_pc.SetLoadAddress(pc - 1, &process->GetTarget()); - m_sym_ctx.Clear(false); - m_sym_ctx_valid = temporary_pc.ResolveFunctionScope(m_sym_ctx, &addr_range); - - UnwindLogMsg("Symbol is now %s", - GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); - } - - // If we were able to find a symbol/function, set addr_range_ptr to the - // bounds of that symbol/function. else treat the current pc value as the - // start_pc and record no offset. - if (addr_range.GetBaseAddress().IsValid()) { - m_start_pc = addr_range.GetBaseAddress(); - m_current_offset = pc - m_start_pc.GetLoadAddress(&process->GetTarget()); - m_current_offset_backed_up_one = m_current_offset; - if (decr_pc_and_recompute_addr_range && - m_current_offset_backed_up_one > 0) { - m_current_offset_backed_up_one--; - if (m_sym_ctx_valid) { - m_current_pc.SetLoadAddress(pc - 1, &process->GetTarget()); - } - } - } else { - m_start_pc = m_current_pc; - m_current_offset = -1; - m_current_offset_backed_up_one = -1; - } - - if (IsTrapHandlerSymbol(process, m_sym_ctx)) { - m_frame_type = eTrapHandlerFrame; - } else { - // FIXME: Detect eDebuggerFrame here. - if (m_frame_type != eSkipFrame) // don't override eSkipFrame - { - m_frame_type = eNormalFrame; - } - } - - // We've set m_frame_type and m_sym_ctx before this call. - m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame(); - - UnwindPlan::RowSP active_row; - RegisterKind row_register_kind = eRegisterKindGeneric; - - // Try to get by with just the fast UnwindPlan if possible - the full - // UnwindPlan may be expensive to get (e.g. if we have to parse the entire - // eh_frame section of an ObjectFile for the first time.) - - if (m_fast_unwind_plan_sp && - m_fast_unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { - active_row = - m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind(); - PropagateTrapHandlerFlagFromUnwindPlan(m_fast_unwind_plan_sp); - if (active_row.get() && log) { - StreamString active_row_strm; - active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, - m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); - UnwindLogMsg("active row: %s", active_row_strm.GetData()); - } - } else { - m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - int valid_offset = -1; - if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) { - active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset(valid_offset); - row_register_kind = m_full_unwind_plan_sp->GetRegisterKind(); - PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp); - if (active_row.get() && log) { - StreamString active_row_strm; - active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), - &m_thread, - m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); - UnwindLogMsg("active row: %s", active_row_strm.GetData()); - } - } - } - - if (!active_row.get()) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg("could not find unwind row for this pc"); - return; - } - - if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) { - UnwindLogMsg("failed to get cfa"); - m_frame_type = eNotAValidFrame; - return; - } - - ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa); - - UnwindLogMsg("m_cfa = 0x%" PRIx64 " m_afa = 0x%" PRIx64, m_cfa, m_afa); - - if (CheckIfLoopingStack()) { - TryFallbackUnwindPlan(); - if (CheckIfLoopingStack()) { - UnwindLogMsg("same CFA address as next frame, assuming the unwind is " - "looping - stopping"); - m_frame_type = eNotAValidFrame; - return; - } - } - - UnwindLogMsg("initialized frame current pc is 0x%" PRIx64 - " cfa is 0x%" PRIx64 " afa is 0x%" PRIx64, - (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), - (uint64_t)m_cfa, - (uint64_t)m_afa); -} - -bool RegisterContextLLDB::CheckIfLoopingStack() { - // If we have a bad stack setup, we can get the same CFA value multiple times - // -- or even more devious, we can actually oscillate between two CFA values. - // Detect that here and break out to avoid a possible infinite loop in lldb - // trying to unwind the stack. To detect when we have the same CFA value - // multiple times, we compare the - // CFA of the current - // frame with the 2nd next frame because in some specail case (e.g. signal - // hanlders, hand written assembly without ABI compiance) we can have 2 - // frames with the same - // CFA (in theory we - // can have arbitrary number of frames with the same CFA, but more then 2 is - // very very unlikely) - - RegisterContextLLDB::SharedPtr next_frame = GetNextFrame(); - if (next_frame) { - RegisterContextLLDB::SharedPtr next_next_frame = next_frame->GetNextFrame(); - addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS; - if (next_next_frame && next_next_frame->GetCFA(next_next_frame_cfa)) { - if (next_next_frame_cfa == m_cfa) { - // We have a loop in the stack unwind - return true; - } - } - } - return false; -} - -bool RegisterContextLLDB::IsFrameZero() const { return m_frame_number == 0; } - -// Find a fast unwind plan for this frame, if possible. -// -// On entry to this method, -// -// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame -// if either of those are correct, -// 2. m_sym_ctx should already be filled in, and -// 3. m_current_pc should have the current pc value for this frame -// 4. m_current_offset_backed_up_one should have the current byte offset into -// the function, maybe backed up by 1, -1 if unknown - -UnwindPlanSP RegisterContextLLDB::GetFastUnwindPlanForFrame() { - UnwindPlanSP unwind_plan_sp; - ModuleSP pc_module_sp(m_current_pc.GetModule()); - - if (!m_current_pc.IsValid() || !pc_module_sp || - pc_module_sp->GetObjectFile() == nullptr) - return unwind_plan_sp; - - if (IsFrameZero()) - return unwind_plan_sp; - - FuncUnwindersSP func_unwinders_sp( - pc_module_sp->GetUnwindTable().GetFuncUnwindersContainingAddress( - m_current_pc, m_sym_ctx)); - if (!func_unwinders_sp) - return unwind_plan_sp; - - // If we're in _sigtramp(), unwinding past this frame requires special - // knowledge. - if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame) - return unwind_plan_sp; - - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind( - *m_thread.CalculateTarget(), m_thread); - if (unwind_plan_sp) { - if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (log && log->GetVerbose()) { - if (m_fast_unwind_plan_sp) - UnwindLogMsgVerbose("frame, and has a fast UnwindPlan"); - else - UnwindLogMsgVerbose("frame"); - } - m_frame_type = eNormalFrame; - return unwind_plan_sp; - } else { - unwind_plan_sp.reset(); - } - } - return unwind_plan_sp; -} - -// On entry to this method, -// -// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame -// if either of those are correct, -// 2. m_sym_ctx should already be filled in, and -// 3. m_current_pc should have the current pc value for this frame -// 4. m_current_offset_backed_up_one should have the current byte offset into -// the function, maybe backed up by 1, -1 if unknown - -UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { - UnwindPlanSP unwind_plan_sp; - UnwindPlanSP arch_default_unwind_plan_sp; - ExecutionContext exe_ctx(m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - ABI *abi = process ? process->GetABI().get() : nullptr; - if (abi) { - arch_default_unwind_plan_sp = - std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric); - abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp); - } else { - UnwindLogMsg( - "unable to get architectural default UnwindPlan from ABI plugin"); - } - - bool behaves_like_zeroth_frame = false; - if (IsFrameZero() || GetNextFrame()->m_frame_type == eTrapHandlerFrame || - GetNextFrame()->m_frame_type == eDebuggerFrame) { - behaves_like_zeroth_frame = true; - // If this frame behaves like a 0th frame (currently executing or - // interrupted asynchronously), all registers can be retrieved. - m_all_registers_available = true; - } - - // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) - // so the pc is 0x0 in the zeroth frame, we need to use the "unwind at first - // instruction" arch default UnwindPlan Also, if this Process can report on - // memory region attributes, any non-executable region means we jumped - // through a bad function pointer - handle the same way as 0x0. Note, if we - // have a symbol context & a symbol, we don't want to follow this code path. - // This is for jumping to memory regions without any information available. - - if ((!m_sym_ctx_valid || - (m_sym_ctx.function == nullptr && m_sym_ctx.symbol == nullptr)) && - behaves_like_zeroth_frame && m_current_pc.IsValid()) { - uint32_t permissions; - addr_t current_pc_addr = - m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()); - if (current_pc_addr == 0 || - (process && - process->GetLoadAddressPermissions(current_pc_addr, permissions) && - (permissions & ePermissionsExecutable) == 0)) { - if (abi) { - unwind_plan_sp = - std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric); - abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp); - m_frame_type = eNormalFrame; - return unwind_plan_sp; - } - } - } - - // No Module for the current pc, try using the architecture default unwind. - ModuleSP pc_module_sp(m_current_pc.GetModule()); - if (!m_current_pc.IsValid() || !pc_module_sp || - pc_module_sp->GetObjectFile() == nullptr) { - m_frame_type = eNormalFrame; - return arch_default_unwind_plan_sp; - } - - FuncUnwindersSP func_unwinders_sp; - if (m_sym_ctx_valid) { - func_unwinders_sp = - pc_module_sp->GetUnwindTable().GetFuncUnwindersContainingAddress( - m_current_pc, m_sym_ctx); - } - - // No FuncUnwinders available for this pc (stripped function symbols, lldb - // could not augment its function table with another source, like - // LC_FUNCTION_STARTS or eh_frame in ObjectFileMachO). See if eh_frame or the - // .ARM.exidx tables have unwind information for this address, else fall back - // to the architectural default unwind. - if (!func_unwinders_sp) { - m_frame_type = eNormalFrame; - - if (!pc_module_sp || !pc_module_sp->GetObjectFile() || - !m_current_pc.IsValid()) - return arch_default_unwind_plan_sp; - - // Even with -fomit-frame-pointer, we can try eh_frame to get back on - // track. - DWARFCallFrameInfo *eh_frame = - pc_module_sp->GetUnwindTable().GetEHFrameInfo(); - if (eh_frame) { - unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric); - if (eh_frame->GetUnwindPlan(m_current_pc, *unwind_plan_sp)) - return unwind_plan_sp; - else - unwind_plan_sp.reset(); - } - - ArmUnwindInfo *arm_exidx = - pc_module_sp->GetUnwindTable().GetArmUnwindInfo(); - if (arm_exidx) { - unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric); - if (arm_exidx->GetUnwindPlan(exe_ctx.GetTargetRef(), m_current_pc, - *unwind_plan_sp)) - return unwind_plan_sp; - else - unwind_plan_sp.reset(); - } - - CallFrameInfo *object_file_unwind = - pc_module_sp->GetUnwindTable().GetObjectFileUnwindInfo(); - if (object_file_unwind) { - unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric); - if (object_file_unwind->GetUnwindPlan(m_current_pc, *unwind_plan_sp)) - return unwind_plan_sp; - else - unwind_plan_sp.reset(); - } - - return arch_default_unwind_plan_sp; - } - - // If we're in _sigtramp(), unwinding past this frame requires special - // knowledge. On Mac OS X this knowledge is properly encoded in the eh_frame - // section, so prefer that if available. On other platforms we may need to - // provide a platform-specific UnwindPlan which encodes the details of how to - // unwind out of sigtramp. - if (m_frame_type == eTrapHandlerFrame && process) { - m_fast_unwind_plan_sp.reset(); - unwind_plan_sp = - func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget()); - if (!unwind_plan_sp) - unwind_plan_sp = - func_unwinders_sp->GetObjectFileUnwindPlan(process->GetTarget()); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc) && - unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) { - return unwind_plan_sp; - } - } - - // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame - // even when it's frame zero This comes up if we have hand-written functions - // in a Module and hand-written eh_frame. The assembly instruction - // inspection may fail and the eh_frame CFI were probably written with some - // care to do the right thing. It'd be nice if there was a way to ask the - // eh_frame directly if it is asynchronous (can be trusted at every - // instruction point) or synchronous (the normal case - only at call sites). - // But there is not. - if (process && process->GetDynamicLoader() && - process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo(m_sym_ctx)) { - // We must specifically call the GetEHFrameUnwindPlan() method here -- - // normally we would call GetUnwindPlanAtCallSite() -- because CallSite may - // return an unwind plan sourced from either eh_frame (that's what we - // intend) or compact unwind (this won't work) - unwind_plan_sp = - func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget()); - if (!unwind_plan_sp) - unwind_plan_sp = - func_unwinders_sp->GetObjectFileUnwindPlan(process->GetTarget()); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { - UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because the " - "DynamicLoader suggested we prefer it", - unwind_plan_sp->GetSourceName().GetCString()); - return unwind_plan_sp; - } - } - - // Typically the NonCallSite UnwindPlan is the unwind created by inspecting - // the assembly language instructions - if (behaves_like_zeroth_frame && process) { - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite( - process->GetTarget(), m_thread); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { - if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) { - // We probably have an UnwindPlan created by inspecting assembly - // instructions. The assembly profilers work really well with compiler- - // generated functions but hand- written assembly can be problematic. - // We set the eh_frame based unwind plan as our fallback unwind plan if - // instruction emulation doesn't work out even for non call sites if it - // is available and use the architecture default unwind plan if it is - // not available. The eh_frame unwind plan is more reliable even on non - // call sites then the architecture default plan and for hand written - // assembly code it is often written in a way that it valid at all - // location what helps in the most common cases when the instruction - // emulation fails. - UnwindPlanSP call_site_unwind_plan = - func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(), - m_thread); - if (call_site_unwind_plan && - call_site_unwind_plan.get() != unwind_plan_sp.get() && - call_site_unwind_plan->GetSourceName() != - unwind_plan_sp->GetSourceName()) { - m_fallback_unwind_plan_sp = call_site_unwind_plan; - } else { - m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; - } - } - UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because this " - "is the non-call site unwind plan and this is a " - "zeroth frame", - unwind_plan_sp->GetSourceName().GetCString()); - return unwind_plan_sp; - } - - // If we're on the first instruction of a function, and we have an - // architectural default UnwindPlan for the initial instruction of a - // function, use that. - if (m_current_offset == 0) { - unwind_plan_sp = - func_unwinders_sp->GetUnwindPlanArchitectureDefaultAtFunctionEntry( - m_thread); - if (unwind_plan_sp) { - UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because we are at " - "the first instruction of a function", - unwind_plan_sp->GetSourceName().GetCString()); - return unwind_plan_sp; - } - } - } - - // Typically this is unwind info from an eh_frame section intended for - // exception handling; only valid at call sites - if (process) { - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite( - process->GetTarget(), m_thread); - } - int valid_offset = -1; - if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { - UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because this " - "is the call-site unwind plan", - unwind_plan_sp->GetSourceName().GetCString()); - return unwind_plan_sp; - } - - // We'd prefer to use an UnwindPlan intended for call sites when we're at a - // call site but if we've struck out on that, fall back to using the non- - // call-site assembly inspection UnwindPlan if possible. - if (process) { - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite( - process->GetTarget(), m_thread); - } - if (unwind_plan_sp && - unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) { - // We probably have an UnwindPlan created by inspecting assembly - // instructions. The assembly profilers work really well with compiler- - // generated functions but hand- written assembly can be problematic. We - // set the eh_frame based unwind plan as our fallback unwind plan if - // instruction emulation doesn't work out even for non call sites if it is - // available and use the architecture default unwind plan if it is not - // available. The eh_frame unwind plan is more reliable even on non call - // sites then the architecture default plan and for hand written assembly - // code it is often written in a way that it valid at all location what - // helps in the most common cases when the instruction emulation fails. - UnwindPlanSP call_site_unwind_plan = - func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(), - m_thread); - if (call_site_unwind_plan && - call_site_unwind_plan.get() != unwind_plan_sp.get() && - call_site_unwind_plan->GetSourceName() != - unwind_plan_sp->GetSourceName()) { - m_fallback_unwind_plan_sp = call_site_unwind_plan; - } else { - m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; - } - } - - if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { - UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because we " - "failed to find a call-site unwind plan that would work", - unwind_plan_sp->GetSourceName().GetCString()); - return unwind_plan_sp; - } - - // If nothing else, use the architectural default UnwindPlan and hope that - // does the job. - if (arch_default_unwind_plan_sp) - UnwindLogMsgVerbose( - "frame uses %s for full UnwindPlan because we are falling back " - "to the arch default plan", - arch_default_unwind_plan_sp->GetSourceName().GetCString()); - else - UnwindLogMsg( - "Unable to find any UnwindPlan for full unwind of this frame."); - - return arch_default_unwind_plan_sp; -} - -void RegisterContextLLDB::InvalidateAllRegisters() { - m_frame_type = eNotAValidFrame; -} - -size_t RegisterContextLLDB::GetRegisterCount() { - return m_thread.GetRegisterContext()->GetRegisterCount(); -} - -const RegisterInfo *RegisterContextLLDB::GetRegisterInfoAtIndex(size_t reg) { - return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg); -} - -size_t RegisterContextLLDB::GetRegisterSetCount() { - return m_thread.GetRegisterContext()->GetRegisterSetCount(); -} - -const RegisterSet *RegisterContextLLDB::GetRegisterSet(size_t reg_set) { - return m_thread.GetRegisterContext()->GetRegisterSet(reg_set); -} - -uint32_t RegisterContextLLDB::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber( - kind, num); -} - -bool RegisterContextLLDB::ReadRegisterValueFromRegisterLocation( - lldb_private::UnwindLLDB::RegisterLocation regloc, - const RegisterInfo *reg_info, RegisterValue &value) { - if (!IsValid()) - return false; - bool success = false; - - switch (regloc.type) { - case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext: { - const RegisterInfo *other_reg_info = - GetRegisterInfoAtIndex(regloc.location.register_number); - - if (!other_reg_info) - return false; - - success = - m_thread.GetRegisterContext()->ReadRegister(other_reg_info, value); - } break; - case UnwindLLDB::RegisterLocation::eRegisterInRegister: { - const RegisterInfo *other_reg_info = - GetRegisterInfoAtIndex(regloc.location.register_number); - - if (!other_reg_info) - return false; - - if (IsFrameZero()) { - success = - m_thread.GetRegisterContext()->ReadRegister(other_reg_info, value); - } else { - success = GetNextFrame()->ReadRegister(other_reg_info, value); - } - } break; - case UnwindLLDB::RegisterLocation::eRegisterValueInferred: - success = - value.SetUInt(regloc.location.inferred_value, reg_info->byte_size); - break; - - case UnwindLLDB::RegisterLocation::eRegisterNotSaved: - break; - case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation: - llvm_unreachable("FIXME debugger inferior function call unwind"); - case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: { - Status error(ReadRegisterValueFromMemory( - reg_info, regloc.location.target_memory_location, reg_info->byte_size, - value)); - success = error.Success(); - } break; - default: - llvm_unreachable("Unknown RegisterLocation type."); - } - return success; -} - -bool RegisterContextLLDB::WriteRegisterValueToRegisterLocation( - lldb_private::UnwindLLDB::RegisterLocation regloc, - const RegisterInfo *reg_info, const RegisterValue &value) { - if (!IsValid()) - return false; - - bool success = false; - - switch (regloc.type) { - case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext: { - const RegisterInfo *other_reg_info = - GetRegisterInfoAtIndex(regloc.location.register_number); - success = - m_thread.GetRegisterContext()->WriteRegister(other_reg_info, value); - } break; - case UnwindLLDB::RegisterLocation::eRegisterInRegister: { - const RegisterInfo *other_reg_info = - GetRegisterInfoAtIndex(regloc.location.register_number); - if (IsFrameZero()) { - success = - m_thread.GetRegisterContext()->WriteRegister(other_reg_info, value); - } else { - success = GetNextFrame()->WriteRegister(other_reg_info, value); - } - } break; - case UnwindLLDB::RegisterLocation::eRegisterValueInferred: - case UnwindLLDB::RegisterLocation::eRegisterNotSaved: - break; - case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation: - llvm_unreachable("FIXME debugger inferior function call unwind"); - case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: { - Status error(WriteRegisterValueToMemory( - reg_info, regloc.location.target_memory_location, reg_info->byte_size, - value)); - success = error.Success(); - } break; - default: - llvm_unreachable("Unknown RegisterLocation type."); - } - return success; -} - -bool RegisterContextLLDB::IsValid() const { - return m_frame_type != eNotAValidFrame; -} - -// After the final stack frame in a stack walk we'll get one invalid -// (eNotAValidFrame) stack frame -- one past the end of the stack walk. But -// higher-level code will need to tell the differnece between "the unwind plan -// below this frame failed" versus "we successfully completed the stack walk" -// so this method helps to disambiguate that. - -bool RegisterContextLLDB::IsTrapHandlerFrame() const { - return m_frame_type == eTrapHandlerFrame; -} - -// A skip frame is a bogus frame on the stack -- but one where we're likely to -// find a real frame farther -// up the stack if we keep looking. It's always the second frame in an unwind -// (i.e. the first frame after frame zero) where unwinding can be the -// trickiest. Ideally we'll mark up this frame in some way so the user knows -// we're displaying bad data and we may have skipped one frame of their real -// program in the process of getting back on track. - -bool RegisterContextLLDB::IsSkipFrame() const { - return m_frame_type == eSkipFrame; -} - -bool RegisterContextLLDB::IsTrapHandlerSymbol( - lldb_private::Process *process, - const lldb_private::SymbolContext &m_sym_ctx) const { - PlatformSP platform_sp(process->GetTarget().GetPlatform()); - if (platform_sp) { - const std::vector<ConstString> trap_handler_names( - platform_sp->GetTrapHandlerSymbolNames()); - for (ConstString name : trap_handler_names) { - if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || - (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) { - return true; - } - } - } - const std::vector<ConstString> user_specified_trap_handler_names( - m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames()); - for (ConstString name : user_specified_trap_handler_names) { - if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || - (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) { - return true; - } - } - - return false; -} - -// Answer the question: Where did THIS frame save the CALLER frame ("previous" -// frame)'s register value? - -enum UnwindLLDB::RegisterSearchResult -RegisterContextLLDB::SavedLocationForRegister( - uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { - RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); - - // Have we already found this register location? - if (!m_registers.empty()) { - std::map<uint32_t, - lldb_private::UnwindLLDB::RegisterLocation>::const_iterator - iterator; - iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); - if (iterator != m_registers.end()) { - regloc = iterator->second; - UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - - // Look through the available UnwindPlans for the register location. - - UnwindPlan::Row::RegisterLocation unwindplan_regloc; - bool have_unwindplan_regloc = false; - RegisterKind unwindplan_registerkind = kNumRegisterKinds; - - if (m_fast_unwind_plan_sp) { - UnwindPlan::RowSP active_row = - m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind(); - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { - UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind " - "reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using FastUnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; - } - } - - if (!have_unwindplan_regloc) { - // m_full_unwind_plan_sp being NULL means that we haven't tried to find a - // full UnwindPlan yet - if (!m_full_unwind_plan_sp) - m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - - if (m_full_unwind_plan_sp) { - RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); - - UnwindPlan::RowSP active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); - - RegisterNumber return_address_reg; - - // If we're fetching the saved pc and this UnwindPlan defines a - // ReturnAddress register (e.g. lr on arm), look for the return address - // register number in the UnwindPlan's row. - if (pc_regnum.IsValid() && pc_regnum == regnum && - m_full_unwind_plan_sp->GetReturnAddressRegister() != - LLDB_INVALID_REGNUM) { - - return_address_reg.init( - m_thread, m_full_unwind_plan_sp->GetRegisterKind(), - m_full_unwind_plan_sp->GetReturnAddressRegister()); - regnum = return_address_reg; - UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " - "RA reg; getting %s (%d) instead", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - } else { - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { - if (unwindplan_registerkind == eRegisterKindGeneric) { - UnwindLogMsg("could not convert lldb regnum %s (%d) into " - "eRegisterKindGeneric reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { - UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " - "RegisterKind reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - } - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - } - - if (regnum.IsValid() && - active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - have_unwindplan_regloc = true; - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using %s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - } - - // This is frame 0 and we're retrieving the PC and it's saved in a Return - // Address register and it hasn't been saved anywhere yet -- that is, - // it's still live in the actual register. Handle this specially. - - if (!have_unwindplan_regloc && return_address_reg.IsValid() && - IsFrameZero()) { - if (return_address_reg.GetAsKind(eRegisterKindLLDB) != - LLDB_INVALID_REGNUM) { - lldb_private::UnwindLLDB::RegisterLocation new_regloc; - new_regloc.type = - UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; - new_regloc.location.register_number = - return_address_reg.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0, saved in %d", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - - // If this architecture stores the return address in a register (it - // defines a Return Address register) and we're on a non-zero stack frame - // and the Full UnwindPlan says that the pc is stored in the - // RA registers (e.g. lr on arm), then we know that the full unwindplan is - // not trustworthy -- this - // is an impossible situation and the instruction emulation code has - // likely been misled. If this stack frame meets those criteria, we need - // to throw away the Full UnwindPlan that the instruction emulation came - // up with and fall back to the architecture's Default UnwindPlan so the - // stack walk can get past this point. - - // Special note: If the Full UnwindPlan was generated from the compiler, - // don't second-guess it when we're at a call site location. - - // arch_default_ra_regnum is the return address register # in the Full - // UnwindPlan register numbering - RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_RA); - - if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() && - unwindplan_regloc.GetRegisterNumber() == - arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) && - m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes && - !m_all_registers_available) { - UnwindLogMsg("%s UnwindPlan tried to restore the pc from the link " - "register but this is a non-zero frame", - m_full_unwind_plan_sp->GetSourceName().GetCString()); - - // Throw away the full unwindplan; install the arch default unwindplan - if (ForceSwitchToFallbackUnwindPlan()) { - // Update for the possibly new unwind plan - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); - UnwindPlan::RowSP active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - - // Sanity check: Verify that we can fetch a pc value and CFA value - // with this unwind plan - - RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); - bool can_fetch_pc_value = false; - bool can_fetch_cfa = false; - addr_t cfa_value; - if (active_row) { - if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - active_row->GetRegisterInfo( - arch_default_pc_reg.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - can_fetch_pc_value = true; - } - if (ReadFrameAddress(unwindplan_registerkind, - active_row->GetCFAValue(), cfa_value)) { - can_fetch_cfa = true; - } - } - - have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa; - } else { - // We were unable to fall back to another unwind plan - have_unwindplan_regloc = false; - } - } - } - } - - ExecutionContext exe_ctx(m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - if (!have_unwindplan_regloc) { - // If the UnwindPlan failed to give us an unwind location for this - // register, we may be able to fall back to some ABI-defined default. For - // example, some ABIs allow to determine the caller's SP via the CFA. Also, - // the ABI may set volatile registers to the undefined state. - ABI *abi = process ? process->GetABI().get() : nullptr; - if (abi) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); - if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using ABI default", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; - } - } - } - - if (!have_unwindplan_regloc) { - if (IsFrameZero()) { - // This is frame 0 - we should return the actual live register context - // value - lldb_private::UnwindLLDB::RegisterLocation new_regloc; - new_regloc.type = - UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; - new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else { - std::string unwindplan_name(""); - if (m_full_unwind_plan_sp) { - unwindplan_name += "via '"; - unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); - unwindplan_name += "'"; - } - UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), - regnum.GetAsKind(eRegisterKindLLDB), - unwindplan_name.c_str()); - } - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - - // unwindplan_regloc has valid contents about where to retrieve the register - if (unwindplan_regloc.IsUnspecified()) { - lldb_private::UnwindLLDB::RegisterLocation new_regloc; - new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved; - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - UnwindLogMsg("save location for %s (%d) is unspecified, continue searching", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - - if (unwindplan_regloc.IsUndefined()) { - UnwindLogMsg( - "did not supply reg location for %s (%d) because it is volatile", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; - } - - if (unwindplan_regloc.IsSame()) { - if (!IsFrameZero() && - (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC || - regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) { - UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or " - "return address reg on a non-zero frame -- treat as if we " - "have no information", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } else { - regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; - regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg( - "supplying caller's register %s (%d), saved in register %s (%d)", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - - if (unwindplan_regloc.IsCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); - regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; - regloc.location.inferred_value = m_cfa + offset; - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg("supplying caller's register %s (%d), value is CFA plus " - "offset %d [value is 0x%" PRIx64 "]", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset, - regloc.location.inferred_value); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - - if (unwindplan_regloc.IsAtCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); - regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; - regloc.location.target_memory_location = m_cfa + offset; - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the stack, saved at " - "CFA plus offset %d [saved at 0x%" PRIx64 "]", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset, - regloc.location.target_memory_location); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - - if (unwindplan_regloc.IsAFAPlusOffset()) { - if (m_afa == LLDB_INVALID_ADDRESS) - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - - int offset = unwindplan_regloc.GetOffset(); - regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; - regloc.location.inferred_value = m_afa + offset; - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg("supplying caller's register %s (%d), value is AFA plus " - "offset %d [value is 0x%" PRIx64 "]", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset, - regloc.location.inferred_value); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - - if (unwindplan_regloc.IsAtAFAPlusOffset()) { - if (m_afa == LLDB_INVALID_ADDRESS) - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - - int offset = unwindplan_regloc.GetOffset(); - regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; - regloc.location.target_memory_location = m_afa + offset; - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the stack, saved at " - "AFA plus offset %d [saved at 0x%" PRIx64 "]", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset, - regloc.location.target_memory_location); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - - if (unwindplan_regloc.IsInOtherRegister()) { - uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber(); - RegisterNumber row_regnum(m_thread, unwindplan_registerkind, - unwindplan_regnum); - if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) { - UnwindLogMsg("could not supply caller's %s (%d) location - was saved in " - "another reg but couldn't convert that regnum", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; - regloc.location.register_number = row_regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg( - "supplying caller's register %s (%d), saved in register %s (%d)", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - row_regnum.GetName(), row_regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - - if (unwindplan_regloc.IsDWARFExpression() || - unwindplan_regloc.IsAtDWARFExpression()) { - DataExtractor dwarfdata(unwindplan_regloc.GetDWARFExpressionBytes(), - unwindplan_regloc.GetDWARFExpressionLength(), - process->GetByteOrder(), - process->GetAddressByteSize()); - ModuleSP opcode_ctx; - DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr); - dwarfexpr.SetRegisterKind(unwindplan_registerkind); - Value cfa_val = Scalar(m_cfa); - cfa_val.SetValueType(Value::eValueTypeLoadAddress); - Value result; - Status error; - if (dwarfexpr.Evaluate(&exe_ctx, this, 0, &cfa_val, nullptr, result, - &error)) { - addr_t val; - val = result.GetScalar().ULongLong(); - if (unwindplan_regloc.IsDWARFExpression()) { - regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; - regloc.location.inferred_value = val; - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg("supplying caller's register %s (%d) via DWARF expression " - "(IsDWARFExpression)", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else { - regloc.type = - UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; - regloc.location.target_memory_location = val; - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg("supplying caller's register %s (%d) via DWARF expression " - "(IsAtDWARFExpression)", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - UnwindLogMsg("tried to use IsDWARFExpression or IsAtDWARFExpression for %s " - "(%d) but failed", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - - UnwindLogMsg("no save location for %s (%d) in this stack frame", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - - // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are - // unsupported. - - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; -} - -// TryFallbackUnwindPlan() -- this method is a little tricky. -// -// When this is called, the frame above -- the caller frame, the "previous" -// frame -- is invalid or bad. -// -// Instead of stopping the stack walk here, we'll try a different UnwindPlan -// and see if we can get a valid frame above us. -// -// This most often happens when an unwind plan based on assembly instruction -// inspection is not correct -- mostly with hand-written assembly functions or -// functions where the stack frame is set up "out of band", e.g. the kernel -// saved the register context and then called an asynchronous trap handler like -// _sigtramp. -// -// Often in these cases, if we just do a dumb stack walk we'll get past this -// tricky frame and our usual techniques can continue to be used. - -bool RegisterContextLLDB::TryFallbackUnwindPlan() { - if (m_fallback_unwind_plan_sp.get() == nullptr) - return false; - - if (m_full_unwind_plan_sp.get() == nullptr) - return false; - - if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() || - m_full_unwind_plan_sp->GetSourceName() == - m_fallback_unwind_plan_sp->GetSourceName()) { - return false; - } - - // If a compiler generated unwind plan failed, trying the arch default - // unwindplan isn't going to do any better. - if (m_full_unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) - return false; - - // Get the caller's pc value and our own CFA value. Swap in the fallback - // unwind plan, re-fetch the caller's pc value and CFA value. If they're the - // same, then the fallback unwind plan provides no benefit. - - RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); - - addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS; - addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS; - UnwindLLDB::RegisterLocation regloc; - if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB), - regloc) == - UnwindLLDB::RegisterSearchResult::eRegisterFound) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(pc_regnum.GetAsKind(eRegisterKindLLDB)); - if (reg_info) { - RegisterValue reg_value; - if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { - old_caller_pc_value = reg_value.GetAsUInt64(); - } - } - } - - // This is a tricky wrinkle! If SavedLocationForRegister() detects a really - // impossible register location for the full unwind plan, it may call - // ForceSwitchToFallbackUnwindPlan() which in turn replaces the full - // unwindplan with the fallback... in short, we're done, we're using the - // fallback UnwindPlan. We checked if m_fallback_unwind_plan_sp was nullptr - // at the top -- the only way it became nullptr since then is via - // SavedLocationForRegister(). - if (m_fallback_unwind_plan_sp.get() == nullptr) - return true; - - // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide - // this isn't working, we need to restore. We'll also need to save & restore - // the value of the m_cfa ivar. Save is down below a bit in 'old_cfa'. - UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp; - addr_t old_cfa = m_cfa; - addr_t old_afa = m_afa; - - m_registers.clear(); - - m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; - - UnwindPlan::RowSP active_row = - m_fallback_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - - if (active_row && - active_row->GetCFAValue().GetValueType() != - UnwindPlan::Row::FAValue::unspecified) { - addr_t new_cfa; - if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(), - active_row->GetCFAValue(), new_cfa) || - new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) { - UnwindLogMsg("failed to get cfa with fallback unwindplan"); - m_fallback_unwind_plan_sp.reset(); - m_full_unwind_plan_sp = original_full_unwind_plan_sp; - return false; - } - m_cfa = new_cfa; - - ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(), - active_row->GetAFAValue(), m_afa); - - if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB), - regloc) == - UnwindLLDB::RegisterSearchResult::eRegisterFound) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(pc_regnum.GetAsKind(eRegisterKindLLDB)); - if (reg_info) { - RegisterValue reg_value; - if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, - reg_value)) { - new_caller_pc_value = reg_value.GetAsUInt64(); - } - } - } - - if (new_caller_pc_value == LLDB_INVALID_ADDRESS) { - UnwindLogMsg("failed to get a pc value for the caller frame with the " - "fallback unwind plan"); - m_fallback_unwind_plan_sp.reset(); - m_full_unwind_plan_sp = original_full_unwind_plan_sp; - m_cfa = old_cfa; - m_afa = old_afa; - return false; - } - - if (old_caller_pc_value == new_caller_pc_value && - m_cfa == old_cfa && - m_afa == old_afa) { - UnwindLogMsg("fallback unwind plan got the same values for this frame " - "CFA and caller frame pc, not using"); - m_fallback_unwind_plan_sp.reset(); - m_full_unwind_plan_sp = original_full_unwind_plan_sp; - return false; - } - - UnwindLogMsg("trying to unwind from this function with the UnwindPlan '%s' " - "because UnwindPlan '%s' failed.", - m_fallback_unwind_plan_sp->GetSourceName().GetCString(), - original_full_unwind_plan_sp->GetSourceName().GetCString()); - - // We've copied the fallback unwind plan into the full - now clear the - // fallback. - m_fallback_unwind_plan_sp.reset(); - PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp); - } - - return true; -} - -bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() { - if (m_fallback_unwind_plan_sp.get() == nullptr) - return false; - - if (m_full_unwind_plan_sp.get() == nullptr) - return false; - - if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() || - m_full_unwind_plan_sp->GetSourceName() == - m_fallback_unwind_plan_sp->GetSourceName()) { - return false; - } - - UnwindPlan::RowSP active_row = - m_fallback_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - - if (active_row && - active_row->GetCFAValue().GetValueType() != - UnwindPlan::Row::FAValue::unspecified) { - addr_t new_cfa; - if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(), - active_row->GetCFAValue(), new_cfa) || - new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) { - UnwindLogMsg("failed to get cfa with fallback unwindplan"); - m_fallback_unwind_plan_sp.reset(); - return false; - } - - ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(), - active_row->GetAFAValue(), m_afa); - - m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; - m_fallback_unwind_plan_sp.reset(); - - m_registers.clear(); - - m_cfa = new_cfa; - - PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp); - - UnwindLogMsg("switched unconditionally to the fallback unwindplan %s", - m_full_unwind_plan_sp->GetSourceName().GetCString()); - return true; - } - return false; -} - -void RegisterContextLLDB::PropagateTrapHandlerFlagFromUnwindPlan( - lldb::UnwindPlanSP unwind_plan) { - if (unwind_plan->GetUnwindPlanForSignalTrap() != eLazyBoolYes) { - // Unwind plan does not indicate trap handler. Do nothing. We may - // already be flagged as trap handler flag due to the symbol being - // in the trap handler symbol list, and that should take precedence. - return; - } else if (m_frame_type != eNormalFrame) { - // If this is already a trap handler frame, nothing to do. - // If this is a skip or debug or invalid frame, don't override that. - return; - } - - m_frame_type = eTrapHandlerFrame; - - if (m_current_offset_backed_up_one != m_current_offset) { - // We backed up the pc by 1 to compute the symbol context, but - // now need to undo that because the pc of the trap handler - // frame may in fact be the first instruction of a signal return - // trampoline, rather than the instruction after a call. This - // happens on systems where the signal handler dispatch code, rather - // than calling the handler and being returned to, jumps to the - // handler after pushing the address of a return trampoline on the - // stack -- on these systems, when the handler returns, control will - // be transferred to the return trampoline, so that's the best - // symbol we can present in the callstack. - UnwindLogMsg("Resetting current offset and re-doing symbol lookup; " - "old symbol was %s", - GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); - m_current_offset_backed_up_one = m_current_offset; - - AddressRange addr_range; - m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range); - - UnwindLogMsg("Symbol is now %s", - GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); - - ExecutionContext exe_ctx(m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - Target *target = &process->GetTarget(); - - m_start_pc = addr_range.GetBaseAddress(); - m_current_offset = - m_current_pc.GetLoadAddress(target) - m_start_pc.GetLoadAddress(target); - } -} - -bool RegisterContextLLDB::ReadFrameAddress( - lldb::RegisterKind row_register_kind, UnwindPlan::Row::FAValue &fa, - addr_t &address) { - RegisterValue reg_value; - - address = LLDB_INVALID_ADDRESS; - addr_t cfa_reg_contents; - - switch (fa.GetValueType()) { - case UnwindPlan::Row::FAValue::isRegisterDereferenced: { - RegisterNumber cfa_reg(m_thread, row_register_kind, - fa.GetRegisterNumber()); - if (ReadGPRValue(cfa_reg, cfa_reg_contents)) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(cfa_reg.GetAsKind(eRegisterKindLLDB)); - RegisterValue reg_value; - if (reg_info) { - Status error = ReadRegisterValueFromMemory( - reg_info, cfa_reg_contents, reg_info->byte_size, reg_value); - if (error.Success()) { - address = reg_value.GetAsUInt64(); - UnwindLogMsg( - "CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 - ", CFA value is 0x%" PRIx64, - cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), - cfa_reg_contents, address); - return true; - } else { - UnwindLogMsg("Tried to deref reg %s (%d) [0x%" PRIx64 - "] but memory read failed.", - cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), - cfa_reg_contents); - } - } - } - break; - } - case UnwindPlan::Row::FAValue::isRegisterPlusOffset: { - RegisterNumber cfa_reg(m_thread, row_register_kind, - fa.GetRegisterNumber()); - if (ReadGPRValue(cfa_reg, cfa_reg_contents)) { - if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || - cfa_reg_contents == 1) { - UnwindLogMsg( - "Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64, - cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), - cfa_reg_contents); - cfa_reg_contents = LLDB_INVALID_ADDRESS; - return false; - } - address = cfa_reg_contents + fa.GetOffset(); - UnwindLogMsg( - "CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 - ", offset is %d", - address, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), - cfa_reg_contents, fa.GetOffset()); - return true; - } - break; - } - case UnwindPlan::Row::FAValue::isDWARFExpression: { - ExecutionContext exe_ctx(m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - DataExtractor dwarfdata(fa.GetDWARFExpressionBytes(), - fa.GetDWARFExpressionLength(), - process->GetByteOrder(), - process->GetAddressByteSize()); - ModuleSP opcode_ctx; - DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr); - dwarfexpr.SetRegisterKind(row_register_kind); - Value result; - Status error; - if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result, - &error)) { - address = result.GetScalar().ULongLong(); - - UnwindLogMsg("CFA value set by DWARF expression is 0x%" PRIx64, - address); - return true; - } - UnwindLogMsg("Failed to set CFA value via DWARF expression: %s", - error.AsCString()); - break; - } - case UnwindPlan::Row::FAValue::isRaSearch: { - Process &process = *m_thread.GetProcess(); - lldb::addr_t return_address_hint = GetReturnAddressHint(fa.GetOffset()); - if (return_address_hint == LLDB_INVALID_ADDRESS) - return false; - const unsigned max_iterations = 256; - for (unsigned i = 0; i < max_iterations; ++i) { - Status st; - lldb::addr_t candidate_addr = - return_address_hint + i * process.GetAddressByteSize(); - lldb::addr_t candidate = - process.ReadPointerFromMemory(candidate_addr, st); - if (st.Fail()) { - UnwindLogMsg("Cannot read memory at 0x%" PRIx64 ": %s", candidate_addr, - st.AsCString()); - return false; - } - Address addr; - uint32_t permissions; - if (process.GetLoadAddressPermissions(candidate, permissions) && - permissions & lldb::ePermissionsExecutable) { - address = candidate_addr; - UnwindLogMsg("Heuristically found CFA: 0x%" PRIx64, address); - return true; - } - } - UnwindLogMsg("No suitable CFA found"); - break; - } - default: - return false; - } - return false; -} - -lldb::addr_t RegisterContextLLDB::GetReturnAddressHint(int32_t plan_offset) { - addr_t hint; - if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, hint)) - return LLDB_INVALID_ADDRESS; - if (!m_sym_ctx.module_sp || !m_sym_ctx.symbol) - return LLDB_INVALID_ADDRESS; - - hint += plan_offset; - - if (auto next = GetNextFrame()) { - if (!next->m_sym_ctx.module_sp || !next->m_sym_ctx.symbol) - return LLDB_INVALID_ADDRESS; - if (auto expected_size = - next->m_sym_ctx.module_sp->GetSymbolFile()->GetParameterStackSize( - *next->m_sym_ctx.symbol)) - hint += *expected_size; - else { - UnwindLogMsgVerbose("Could not retrieve parameter size: %s", - llvm::toString(expected_size.takeError()).c_str()); - return LLDB_INVALID_ADDRESS; - } - } - return hint; -} - -// Retrieve a general purpose register value for THIS frame, as saved by the -// NEXT frame, i.e. the frame that -// this frame called. e.g. -// -// foo () { } -// bar () { foo (); } -// main () { bar (); } -// -// stopped in foo() so -// frame 0 - foo -// frame 1 - bar -// frame 2 - main -// and this RegisterContext is for frame 1 (bar) - if we want to get the pc -// value for frame 1, we need to ask -// where frame 0 (the "next" frame) saved that and retrieve the value. - -bool RegisterContextLLDB::ReadGPRValue(lldb::RegisterKind register_kind, - uint32_t regnum, addr_t &value) { - if (!IsValid()) - return false; - - uint32_t lldb_regnum; - if (register_kind == eRegisterKindLLDB) { - lldb_regnum = regnum; - } else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds( - register_kind, regnum, eRegisterKindLLDB, lldb_regnum)) { - return false; - } - - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum); - RegisterValue reg_value; - // if this is frame 0 (currently executing frame), get the requested reg - // contents from the actual thread registers - if (IsFrameZero()) { - if (m_thread.GetRegisterContext()->ReadRegister(reg_info, reg_value)) { - value = reg_value.GetAsUInt64(); - return true; - } - return false; - } - - bool pc_register = false; - uint32_t generic_regnum; - if (register_kind == eRegisterKindGeneric && - (regnum == LLDB_REGNUM_GENERIC_PC || regnum == LLDB_REGNUM_GENERIC_RA)) { - pc_register = true; - } else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds( - register_kind, regnum, eRegisterKindGeneric, generic_regnum) && - (generic_regnum == LLDB_REGNUM_GENERIC_PC || - generic_regnum == LLDB_REGNUM_GENERIC_RA)) { - pc_register = true; - } - - lldb_private::UnwindLLDB::RegisterLocation regloc; - if (!m_parent_unwind.SearchForSavedLocationForRegister( - lldb_regnum, regloc, m_frame_number - 1, pc_register)) { - return false; - } - if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { - value = reg_value.GetAsUInt64(); - return true; - } - return false; -} - -bool RegisterContextLLDB::ReadGPRValue(const RegisterNumber ®num, - addr_t &value) { - return ReadGPRValue(regnum.GetRegisterKind(), regnum.GetRegisterNumber(), - value); -} - -// Find the value of a register in THIS frame - -bool RegisterContextLLDB::ReadRegister(const RegisterInfo *reg_info, - RegisterValue &value) { - if (!IsValid()) - return false; - - const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB]; - UnwindLogMsgVerbose("looking for register saved location for reg %d", - lldb_regnum); - - // If this is the 0th frame, hand this over to the live register context - if (IsFrameZero()) { - UnwindLogMsgVerbose("passing along to the live register context for reg %d", - lldb_regnum); - return m_thread.GetRegisterContext()->ReadRegister(reg_info, value); - } - - bool is_pc_regnum = false; - if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC || - reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA) { - is_pc_regnum = true; - } - - lldb_private::UnwindLLDB::RegisterLocation regloc; - // Find out where the NEXT frame saved THIS frame's register contents - if (!m_parent_unwind.SearchForSavedLocationForRegister( - lldb_regnum, regloc, m_frame_number - 1, is_pc_regnum)) - return false; - - return ReadRegisterValueFromRegisterLocation(regloc, reg_info, value); -} - -bool RegisterContextLLDB::WriteRegister(const RegisterInfo *reg_info, - const RegisterValue &value) { - if (!IsValid()) - return false; - - const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB]; - UnwindLogMsgVerbose("looking for register saved location for reg %d", - lldb_regnum); - - // If this is the 0th frame, hand this over to the live register context - if (IsFrameZero()) { - UnwindLogMsgVerbose("passing along to the live register context for reg %d", - lldb_regnum); - return m_thread.GetRegisterContext()->WriteRegister(reg_info, value); - } - - lldb_private::UnwindLLDB::RegisterLocation regloc; - // Find out where the NEXT frame saved THIS frame's register contents - if (!m_parent_unwind.SearchForSavedLocationForRegister( - lldb_regnum, regloc, m_frame_number - 1, false)) - return false; - - return WriteRegisterValueToRegisterLocation(regloc, reg_info, value); -} - -// Don't need to implement this one -bool RegisterContextLLDB::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) { - return false; -} - -// Don't need to implement this one -bool RegisterContextLLDB::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - return false; -} - -// Retrieve the pc value for THIS from - -bool RegisterContextLLDB::GetCFA(addr_t &cfa) { - if (!IsValid()) { - return false; - } - if (m_cfa == LLDB_INVALID_ADDRESS) { - return false; - } - cfa = m_cfa; - return true; -} - -RegisterContextLLDB::SharedPtr RegisterContextLLDB::GetNextFrame() const { - RegisterContextLLDB::SharedPtr regctx; - if (m_frame_number == 0) - return regctx; - return m_parent_unwind.GetRegisterContextForFrameNum(m_frame_number - 1); -} - -RegisterContextLLDB::SharedPtr RegisterContextLLDB::GetPrevFrame() const { - RegisterContextLLDB::SharedPtr regctx; - return m_parent_unwind.GetRegisterContextForFrameNum(m_frame_number + 1); -} - -// Retrieve the address of the start of the function of THIS frame - -bool RegisterContextLLDB::GetStartPC(addr_t &start_pc) { - if (!IsValid()) - return false; - - if (!m_start_pc.IsValid()) { - bool read_successfully = ReadPC (start_pc); - if (read_successfully) - { - ProcessSP process_sp (m_thread.GetProcess()); - if (process_sp) - { - ABI *abi = process_sp->GetABI().get(); - if (abi) - start_pc = abi->FixCodeAddress(start_pc); - } - } - return read_successfully; - } - start_pc = m_start_pc.GetLoadAddress(CalculateTarget().get()); - return true; -} - -// Retrieve the current pc value for THIS frame, as saved by the NEXT frame. - -bool RegisterContextLLDB::ReadPC(addr_t &pc) { - if (!IsValid()) - return false; - - bool above_trap_handler = false; - if (GetNextFrame().get() && GetNextFrame()->IsValid() && - GetNextFrame()->IsTrapHandlerFrame()) - above_trap_handler = true; - - if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) { - // A pc value of 0 or 1 is impossible in the middle of the stack -- it - // indicates the end of a stack walk. - // On the currently executing frame (or such a frame interrupted - // asynchronously by sigtramp et al) this may occur if code has jumped - // through a NULL pointer -- we want to be able to unwind past that frame - // to help find the bug. - - ProcessSP process_sp (m_thread.GetProcess()); - if (process_sp) - { - ABI *abi = process_sp->GetABI().get(); - if (abi) - pc = abi->FixCodeAddress(pc); - } - - return !(m_all_registers_available == false && - above_trap_handler == false && (pc == 0 || pc == 1)); - } else { - return false; - } -} - -void RegisterContextLLDB::UnwindLogMsg(const char *fmt, ...) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (log) { - va_list args; - va_start(args, fmt); - - char *logmsg; - if (vasprintf(&logmsg, fmt, args) == -1 || logmsg == nullptr) { - if (logmsg) - free(logmsg); - va_end(args); - return; - } - va_end(args); - - LLDB_LOGF(log, "%*sth%d/fr%u %s", - m_frame_number < 100 ? m_frame_number : 100, "", - m_thread.GetIndexID(), m_frame_number, logmsg); - free(logmsg); - } -} - -void RegisterContextLLDB::UnwindLogMsgVerbose(const char *fmt, ...) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (log && log->GetVerbose()) { - va_list args; - va_start(args, fmt); - - char *logmsg; - if (vasprintf(&logmsg, fmt, args) == -1 || logmsg == nullptr) { - if (logmsg) - free(logmsg); - va_end(args); - return; - } - va_end(args); - - LLDB_LOGF(log, "%*sth%d/fr%u %s", - m_frame_number < 100 ? m_frame_number : 100, "", - m_thread.GetIndexID(), m_frame_number, logmsg); - free(logmsg); - } -} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h deleted file mode 100644 index 114ac35591e7..000000000000 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ /dev/null @@ -1,259 +0,0 @@ -//===-- RegisterContextLLDB.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_RegisterContextLLDB_h_ -#define lldb_RegisterContextLLDB_h_ - -#include <vector> - -#include "UnwindLLDB.h" -#include "lldb/Symbol/SymbolContext.h" -#include "lldb/Symbol/UnwindPlan.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/RegisterNumber.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { - -class UnwindLLDB; - -class RegisterContextLLDB : public lldb_private::RegisterContext { -public: - typedef std::shared_ptr<RegisterContextLLDB> SharedPtr; - - RegisterContextLLDB(lldb_private::Thread &thread, const SharedPtr &next_frame, - lldb_private::SymbolContext &sym_ctx, - uint32_t frame_number, - lldb_private::UnwindLLDB &unwind_lldb); - - ~RegisterContextLLDB() override = default; - - void InvalidateAllRegisters() override; - - size_t GetRegisterCount() override; - - const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; - - size_t GetRegisterSetCount() override; - - const lldb_private::RegisterSet *GetRegisterSet(size_t reg_set) override; - - bool ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value) override; - - bool WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value) override; - - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - - bool IsValid() const; - - bool IsTrapHandlerFrame() const; - - bool GetCFA(lldb::addr_t &cfa); - - bool GetStartPC(lldb::addr_t &start_pc); - - bool ReadPC(lldb::addr_t &start_pc); - -private: - enum FrameType { - eNormalFrame, - eTrapHandlerFrame, - eDebuggerFrame, // a debugger inferior function call frame; we get caller's - // registers from debugger - eSkipFrame, // The unwind resulted in a bogus frame but may get back on - // track so we don't want to give up yet - eNotAValidFrame // this frame is invalid for some reason - most likely it is - // past the top (end) of the stack - }; - - // UnwindLLDB needs to pass around references to RegisterLocations - friend class UnwindLLDB; - - // Returns true if we have an unwind loop -- the same stack frame unwinding - // multiple times. - bool CheckIfLoopingStack(); - - // Indicates whether this frame is frame zero -- the currently - // executing frame -- or not. - bool IsFrameZero() const; - - void InitializeZerothFrame(); - - void InitializeNonZerothFrame(); - - SharedPtr GetNextFrame() const; - - SharedPtr GetPrevFrame() const; - - // A SkipFrame occurs when the unwind out of frame 0 didn't go right -- we've - // got one bogus frame at frame #1. - // There is a good chance we'll get back on track if we follow the frame - // pointer chain (or whatever is appropriate - // on this ABI) so we allow one invalid frame to be in the stack. Ideally - // we'll mark this frame specially at some - // point and indicate to the user that the unwinder had a hiccup. Often when - // this happens we will miss a frame of - // the program's actual stack in the unwind and we want to flag that for the - // user somehow. - bool IsSkipFrame() const; - - /// Determines if a SymbolContext is a trap handler or not - /// - /// Given a SymbolContext, determines if this is a trap handler function - /// aka asynchronous signal handler. - /// - /// \return - /// Returns true if the SymbolContext is a trap handler. - bool IsTrapHandlerSymbol(lldb_private::Process *process, - const lldb_private::SymbolContext &m_sym_ctx) const; - - /// Check if the given unwind plan indicates a signal trap handler, and - /// update frame type and symbol context if so. - void PropagateTrapHandlerFlagFromUnwindPlan(lldb::UnwindPlanSP unwind_plan); - - // Provide a location for where THIS function saved the CALLER's register - // value - // Or a frame "below" this one saved it, i.e. a function called by this one, - // preserved a register that this - // function didn't modify/use. - // - // The RegisterLocation type may be set to eRegisterNotAvailable -- this will - // happen for a volatile register - // being queried mid-stack. Instead of floating frame 0's contents of that - // register up the stack (which may - // or may not be the value of that reg when the function was executing), we - // won't return any value. - // - // If a non-volatile register (a "preserved" register) is requested mid-stack - // and no frames "below" the requested - // stack have saved the register anywhere, it is safe to assume that frame 0's - // register values are still the same - // as the requesting frame's. - lldb_private::UnwindLLDB::RegisterSearchResult - SavedLocationForRegister(uint32_t lldb_regnum, - lldb_private::UnwindLLDB::RegisterLocation ®loc); - - bool ReadRegisterValueFromRegisterLocation( - lldb_private::UnwindLLDB::RegisterLocation regloc, - const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value); - - bool WriteRegisterValueToRegisterLocation( - lldb_private::UnwindLLDB::RegisterLocation regloc, - const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value); - - /// If the unwind has to the caller frame has failed, try something else - /// - /// If lldb is using an assembly language based UnwindPlan for a frame and - /// the unwind to the caller frame fails, try falling back to a generic - /// UnwindPlan (architecture default unwindplan) to see if that might work - /// better. This is mostly helping to work around problems where the - /// assembly language inspection fails on hand-written assembly code. - /// - /// \return - /// Returns true if a fallback unwindplan was found & was installed. - bool TryFallbackUnwindPlan(); - - /// Switch to the fallback unwind plan unconditionally without any safety - /// checks that it is providing better results than the normal unwind plan. - /// - /// The only time it is valid to call this method is if the full unwindplan is - /// found to be fundamentally incorrect/impossible. - /// - /// Returns true if it was able to install the fallback unwind plan. - bool ForceSwitchToFallbackUnwindPlan(); - - // Get the contents of a general purpose (address-size) register for this - // frame - // (usually retrieved from the next frame) - bool ReadGPRValue(lldb::RegisterKind register_kind, uint32_t regnum, - lldb::addr_t &value); - - bool ReadGPRValue(const RegisterNumber ®_num, lldb::addr_t &value); - - // Get the Frame Address register for a given frame. - bool ReadFrameAddress(lldb::RegisterKind register_kind, - UnwindPlan::Row::FAValue &fa, lldb::addr_t &address); - - lldb::UnwindPlanSP GetFastUnwindPlanForFrame(); - - lldb::UnwindPlanSP GetFullUnwindPlanForFrame(); - - void UnwindLogMsg(const char *fmt, ...) __attribute__((format(printf, 2, 3))); - - void UnwindLogMsgVerbose(const char *fmt, ...) - __attribute__((format(printf, 2, 3))); - - bool IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, - int &valid_pc_offset); - - lldb::addr_t GetReturnAddressHint(int32_t plan_offset); - - lldb_private::Thread &m_thread; - - /// - // The following tell us how to retrieve the CALLER's register values (ie the - // "previous" frame, aka the frame above) - // i.e. where THIS frame saved them - /// - - lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL - lldb::UnwindPlanSP m_full_unwind_plan_sp; - lldb::UnwindPlanSP m_fallback_unwind_plan_sp; // may be NULL - - bool m_all_registers_available; // Can we retrieve all regs or just - // nonvolatile regs? - int m_frame_type; // enum FrameType - - lldb::addr_t m_cfa; - lldb::addr_t m_afa; - lldb_private::Address m_start_pc; - lldb_private::Address m_current_pc; - - int m_current_offset; // how far into the function we've executed; -1 if - // unknown - // 0 if no instructions have been executed yet. - - int m_current_offset_backed_up_one; // how far into the function we've - // executed; -1 if unknown - // 0 if no instructions have been executed yet. - // On architectures where the return address on the stack points - // to the instruction after the CALL, this value will have 1 - // subtracted from it. Else a function that ends in a CALL will - // have an offset pointing into the next function's address range. - // m_current_pc has the actual address of the "current" pc. - - lldb_private::SymbolContext &m_sym_ctx; - bool m_sym_ctx_valid; // if ResolveSymbolContextForAddress fails, don't try to - // use m_sym_ctx - - uint32_t m_frame_number; // What stack frame this RegisterContext is - - std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation> - m_registers; // where to find reg values for this frame - - lldb_private::UnwindLLDB &m_parent_unwind; // The UnwindLLDB that is creating - // this RegisterContextLLDB - - // For RegisterContextLLDB only - - DISALLOW_COPY_AND_ASSIGN(RegisterContextLLDB); -}; - -} // namespace lldb_private - -#endif // lldb_RegisterContextLLDB_h_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp index 79979639dc7e..518dc273faf4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextLinux_i386.cpp --------------------------*- C++ -*-===// +//===-- RegisterContextLinux_i386.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h index 5567a1ac42e5..ef731a5a7994 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextLinux_i386_H_ -#define liblldb_RegisterContextLinux_i386_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_I386_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_I386_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp index fc60fea79176..837549e2a495 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextLinux_mips.cpp ------------------------*- C++ -*-===// +//===-- RegisterContextLinux_mips.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h index e637dfc15e4d..9b59ab421ff4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextLinux_mips_H_ -#define liblldb_RegisterContextLinux_mips_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_MIPS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_MIPS_H #include "RegisterInfoInterface.h" #include "lldb/lldb-private.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp index 3927883c47a4..432a78129fde 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextLinux_mips64.cpp ------------------------*- C++ -*-===// +//===-- RegisterContextLinux_mips64.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h index ca0f0140a22d..899f0a40e4ae 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextLinux_mips64_H_ -#define liblldb_RegisterContextLinux_mips64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_MIPS64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_MIPS64_H #include "RegisterInfoInterface.h" #include "lldb/lldb-private.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp index d6401d788ab2..7a8989cd1225 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextLinux_s390x.cpp --------------------------*- C++ -*-===// +//===-- RegisterContextLinux_s390x.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.h b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.h index 10810c97af80..f381f38ecbf9 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextLinux_s390x_h_ -#define liblldb_RegisterContextLinux_s390x_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_S390X_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_S390X_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp index 640d5bc02256..f9d4e23fcde2 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextLinux_x86_64.cpp ------------------------*- C++ -*-===// +//===-- RegisterContextLinux_x86_64.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h index 02f273cb02c9..ea21b913d5c5 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextLinux_x86_64_H_ -#define liblldb_RegisterContextLinux_x86_64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_X86_64_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp deleted file mode 100644 index bc78c1d6160c..000000000000 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ /dev/null @@ -1,160 +0,0 @@ -//===-- RegisterContextMacOSXFrameBackchain.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 "RegisterContextMacOSXFrameBackchain.h" - -#include "lldb/Target/Thread.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Scalar.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/Utility/StringExtractorGDBRemote.h" - -using namespace lldb; -using namespace lldb_private; - -// RegisterContextMacOSXFrameBackchain constructor -RegisterContextMacOSXFrameBackchain::RegisterContextMacOSXFrameBackchain( - Thread &thread, uint32_t concrete_frame_idx, - const UnwindMacOSXFrameBackchain::Cursor &cursor) - : RegisterContext(thread, concrete_frame_idx), m_cursor(cursor), - m_cursor_is_valid(true) {} - -// Destructor -RegisterContextMacOSXFrameBackchain::~RegisterContextMacOSXFrameBackchain() {} - -void RegisterContextMacOSXFrameBackchain::InvalidateAllRegisters() { - m_cursor_is_valid = false; -} - -size_t RegisterContextMacOSXFrameBackchain::GetRegisterCount() { - return m_thread.GetRegisterContext()->GetRegisterCount(); -} - -const RegisterInfo * -RegisterContextMacOSXFrameBackchain::GetRegisterInfoAtIndex(size_t reg) { - return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg); -} - -size_t RegisterContextMacOSXFrameBackchain::GetRegisterSetCount() { - return m_thread.GetRegisterContext()->GetRegisterSetCount(); -} - -const RegisterSet * -RegisterContextMacOSXFrameBackchain::GetRegisterSet(size_t reg_set) { - return m_thread.GetRegisterContext()->GetRegisterSet(reg_set); -} - -bool RegisterContextMacOSXFrameBackchain::ReadRegister( - const RegisterInfo *reg_info, RegisterValue &value) { - if (!m_cursor_is_valid) - return false; - - uint64_t reg_value = LLDB_INVALID_ADDRESS; - - switch (reg_info->kinds[eRegisterKindGeneric]) { - case LLDB_REGNUM_GENERIC_PC: - if (m_cursor.pc == LLDB_INVALID_ADDRESS) - return false; - reg_value = m_cursor.pc; - break; - - case LLDB_REGNUM_GENERIC_FP: - if (m_cursor.fp == LLDB_INVALID_ADDRESS) - return false; - reg_value = m_cursor.fp; - break; - - default: - return false; - } - - switch (reg_info->encoding) { - case eEncodingInvalid: - case eEncodingVector: - break; - - case eEncodingUint: - case eEncodingSint: - value.SetUInt(reg_value, reg_info->byte_size); - return true; - - case eEncodingIEEE754: - switch (reg_info->byte_size) { - case sizeof(float): - if (sizeof(float) == sizeof(uint32_t)) { - value.SetUInt32(reg_value, RegisterValue::eTypeFloat); - return true; - } else if (sizeof(float) == sizeof(uint64_t)) { - value.SetUInt64(reg_value, RegisterValue::eTypeFloat); - return true; - } - break; - - case sizeof(double): - if (sizeof(double) == sizeof(uint32_t)) { - value.SetUInt32(reg_value, RegisterValue::eTypeDouble); - return true; - } else if (sizeof(double) == sizeof(uint64_t)) { - value.SetUInt64(reg_value, RegisterValue::eTypeDouble); - return true; - } - break; - -// TOOD: need a better way to detect when "long double" types are -// the same bytes size as "double" -#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && \ - !defined(_MSC_VER) && !defined(__mips__) && !defined(__powerpc__) && \ - !defined(__ANDROID__) - case sizeof(long double): - if (sizeof(long double) == sizeof(uint32_t)) { - value.SetUInt32(reg_value, RegisterValue::eTypeLongDouble); - return true; - } else if (sizeof(long double) == sizeof(uint64_t)) { - value.SetUInt64(reg_value, RegisterValue::eTypeLongDouble); - return true; - } - break; -#endif - } - break; - } - return false; -} - -bool RegisterContextMacOSXFrameBackchain::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue &value) { - // Not supported yet. We could easily add support for this by remembering the - // address of each entry (it would need to be part of the cursor) - return false; -} - -bool RegisterContextMacOSXFrameBackchain::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - // libunwind frames can't handle this it doesn't always have all register - // values. This call should only be called on frame zero anyway so there - // shouldn't be any problem - return false; -} - -bool RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - // Since this class doesn't respond to "ReadAllRegisterValues()", it must not - // have been the one that saved all the register values. So we just let the - // thread's register context (the register context for frame zero) do the - // writing. - return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp); -} - -uint32_t -RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber( - kind, num); -} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h deleted file mode 100644 index 36e5538daa8a..000000000000 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h +++ /dev/null @@ -1,56 +0,0 @@ -//===-- RegisterContextMacOSXFrameBackchain.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_RegisterContextMacOSXFrameBackchain_h_ -#define lldb_RegisterContextMacOSXFrameBackchain_h_ - -#include "lldb/Target/RegisterContext.h" -#include "lldb/lldb-private.h" - -#include "UnwindMacOSXFrameBackchain.h" - -class RegisterContextMacOSXFrameBackchain - : public lldb_private::RegisterContext { -public: - RegisterContextMacOSXFrameBackchain( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - const UnwindMacOSXFrameBackchain::Cursor &cursor); - - ~RegisterContextMacOSXFrameBackchain() override; - - void InvalidateAllRegisters() override; - - size_t GetRegisterCount() override; - - const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; - - size_t GetRegisterSetCount() override; - - const lldb_private::RegisterSet *GetRegisterSet(size_t reg_set) override; - - bool ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value) override; - - bool WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value) override; - - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - -private: - UnwindMacOSXFrameBackchain::Cursor m_cursor; - bool m_cursor_is_valid; - - DISALLOW_COPY_AND_ASSIGN(RegisterContextMacOSXFrameBackchain); -}; - -#endif // lldb_RegisterContextMacOSXFrameBackchain_h_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp index c7042ab5137a..1394cb7f00a1 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextMach_arm.cpp -----------------------------*- C++ -*-===// +//===-- RegisterContextMach_arm.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h index 8b2425a193be..e7c180dbdd27 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h @@ -6,9 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextMach_arm_h_ -#define liblldb_RegisterContextMach_arm_h_ - +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H #include "RegisterContextDarwin_arm.h" @@ -37,4 +36,4 @@ protected: int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg); }; -#endif // liblldb_RegisterContextMach_arm_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp index e631ab9bb26c..b97166b6eebe 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextMach_i386.cpp ----------------------------*- C++ -*-===// +//===-- RegisterContextMach_i386.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h index b8835561e98c..09966be60c92 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextMach_i386_h_ -#define liblldb_RegisterContextMach_i386_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H #include "RegisterContextDarwin_i386.h" @@ -32,4 +32,4 @@ protected: int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); }; -#endif // liblldb_RegisterContextMach_i386_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp index db17d7d88778..8933f136789f 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextMach_x86_64.cpp --------------------------*- C++ -*-===// +//===-- RegisterContextMach_x86_64.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h index 688009aef8af..2a8a2cca2f8a 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextMach_x86_64_h_ -#define liblldb_RegisterContextMach_x86_64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H #include "RegisterContextDarwin_x86_64.h" @@ -33,4 +33,4 @@ protected: int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); }; -#endif // liblldb_RegisterContextMach_x86_64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp index 946d4fa9f8e5..f2d230b54053 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextMemory.cpp -------------------------------*- C++ -*-===// +//===-- RegisterContextMemory.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h b/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h index 68223eaeffd7..764ee9b97211 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_RegisterContextMemory_h_ -#define lldb_RegisterContextMemory_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMEMORY_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMEMORY_H #include <vector> @@ -67,7 +67,9 @@ protected: // context that is stored in memmory private: - DISALLOW_COPY_AND_ASSIGN(RegisterContextMemory); + RegisterContextMemory(const RegisterContextMemory &) = delete; + const RegisterContextMemory & + operator=(const RegisterContextMemory &) = delete; }; -#endif // lldb_RegisterContextMemory_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMEMORY_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp new file mode 100644 index 000000000000..bd7830e42b42 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp @@ -0,0 +1,96 @@ +//===-- 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" + +using namespace lldb_private; +using namespace lldb; + +// this needs to match 'struct reg' +struct GPR { + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t eip; + uint32_t eflags; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t es; + uint32_t fs; + uint32_t gs; +}; + +struct FPR_i386 { + uint16_t fctrl; // FPU Control Word (fcw) + uint16_t fstat; // FPU Status Word (fsw) + uint16_t ftag; // FPU Tag Word (ftw) + uint16_t fop; // Last Instruction Opcode (fop) + union { + struct { + uint64_t fip; // Instruction Pointer + uint64_t fdp; // Data Pointer + } x86_64; + struct { + uint32_t fioff; // FPU IP Offset (fip) + uint32_t fiseg; // FPU IP Selector (fcs) + uint32_t fooff; // FPU Operand Pointer Offset (foo) + uint32_t foseg; // FPU Operand Pointer Selector (fos) + } i386_; // Added _ in the end to avoid error with gcc defining i386 in some + // cases + } ptr; + uint32_t mxcsr; // MXCSR Register State + uint32_t mxcsrmask; // MXCSR Mask + MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes + XMMReg xmm[8]; // 8*16 bytes for each XMM-reg = 128 bytes + uint32_t padding[56]; +}; + +struct UserArea { + GPR gpr; + FPR_i386 i387; + uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7). + uint32_t tlsbase; +}; + +#define DR_SIZE sizeof(((UserArea *)NULL)->u_debugreg[0]) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) + +// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. +#define DECLARE_REGISTER_INFOS_I386_STRUCT +#include "RegisterInfos_i386.h" +#undef DECLARE_REGISTER_INFOS_I386_STRUCT + +RegisterContextNetBSD_i386::RegisterContextNetBSD_i386( + const ArchSpec &target_arch) + : RegisterInfoInterface(target_arch) {} + +size_t RegisterContextNetBSD_i386::GetGPRSize() const { return sizeof(GPR); } + +const RegisterInfo *RegisterContextNetBSD_i386::GetRegisterInfo() const { + switch (m_target_arch.GetMachine()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return g_register_infos_i386; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } +} + +uint32_t RegisterContextNetBSD_i386::GetRegisterCount() const { + return static_cast<uint32_t>(sizeof(g_register_infos_i386) / + sizeof(g_register_infos_i386[0])); +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.h b/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.h new file mode 100644 index 000000000000..742bb18b8306 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.h @@ -0,0 +1,25 @@ +//===-- RegisterContextNetBSD_i386.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_REGISTERCONTEXTNETBSD_I386_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTNETBSD_I386_H + +#include "RegisterInfoInterface.h" + +class RegisterContextNetBSD_i386 : public lldb_private::RegisterInfoInterface { +public: + RegisterContextNetBSD_i386(const lldb_private::ArchSpec &target_arch); + + size_t GetGPRSize() const override; + + const lldb_private::RegisterInfo *GetRegisterInfo() const override; + + uint32_t GetRegisterCount() const override; +}; + +#endif diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp index e620ff66c922..21aad92ecda8 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextNetBSD_x86_64.cpp ------------------------*- C++ -*-===// +//===-- RegisterContextNetBSD_x86_64.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "RegisterContextNetBSD_x86_64.h" +#include "RegisterContextNetBSD_i386.h" #include "RegisterContextPOSIX_x86.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Compiler.h" @@ -83,9 +84,40 @@ struct UserArea { #include "RegisterInfos_x86_64.h" #undef DECLARE_REGISTER_INFOS_X86_64_STRUCT +static std::vector<lldb_private::RegisterInfo> &GetPrivateRegisterInfoVector() { + static std::vector<lldb_private::RegisterInfo> g_register_infos; + return g_register_infos; +} + +static const RegisterInfo * +GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) { + std::vector<lldb_private::RegisterInfo> &g_register_infos = + GetPrivateRegisterInfoVector(); + + // Allocate RegisterInfo only once + if (g_register_infos.empty()) { + // Copy the register information from base class + std::unique_ptr<RegisterContextNetBSD_i386> reg_interface( + new RegisterContextNetBSD_i386(arch)); + const RegisterInfo *base_info = reg_interface->GetRegisterInfo(); + g_register_infos.insert(g_register_infos.end(), &base_info[0], + &base_info[k_num_registers_i386]); + +// Include RegisterInfos_x86_64 to update the g_register_infos structure +// with x86_64 offsets. +#define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS +#include "RegisterInfos_x86_64.h" +#undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS + } + + return &g_register_infos[0]; +} + static const RegisterInfo * PrivateGetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + case llvm::Triple::x86: + return GetRegisterInfo_i386(target_arch); case llvm::Triple::x86_64: return g_register_infos_x86_64; default: @@ -97,6 +129,11 @@ PrivateGetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { static uint32_t PrivateGetRegisterCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + case llvm::Triple::x86: { + assert(!GetPrivateRegisterInfoVector().empty() && + "i386 register info not yet filled."); + return static_cast<uint32_t>(GetPrivateRegisterInfoVector().size()); + } case llvm::Triple::x86_64: return static_cast<uint32_t>(sizeof(g_register_infos_x86_64) / sizeof(g_register_infos_x86_64[0])); @@ -106,11 +143,25 @@ PrivateGetRegisterCount(const lldb_private::ArchSpec &target_arch) { } } +static uint32_t +PrivateGetUserRegisterCount(const lldb_private::ArchSpec &target_arch) { + switch (target_arch.GetMachine()) { + case llvm::Triple::x86: + return static_cast<uint32_t>(k_num_user_registers_i386); + case llvm::Triple::x86_64: + return static_cast<uint32_t>(k_num_user_registers_x86_64); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + RegisterContextNetBSD_x86_64::RegisterContextNetBSD_x86_64( const ArchSpec &target_arch) : lldb_private::RegisterInfoInterface(target_arch), m_register_info_p(PrivateGetRegisterInfoPtr(target_arch)), - m_register_count(PrivateGetRegisterCount(target_arch)) {} + m_register_count(PrivateGetRegisterCount(target_arch)), + m_user_register_count(PrivateGetUserRegisterCount(target_arch)) {} size_t RegisterContextNetBSD_x86_64::GetGPRSize() const { return sizeof(GPR); } @@ -121,3 +172,7 @@ const RegisterInfo *RegisterContextNetBSD_x86_64::GetRegisterInfo() const { uint32_t RegisterContextNetBSD_x86_64::GetRegisterCount() const { return m_register_count; } + +uint32_t RegisterContextNetBSD_x86_64::GetUserRegisterCount() const { + return m_user_register_count; +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h index 4820ef8d17ba..b7b8d33b7c37 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextNetBSD_x86_64_H_ -#define liblldb_RegisterContextNetBSD_x86_64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTNETBSD_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTNETBSD_X86_64_H #include "RegisterInfoInterface.h" @@ -22,9 +22,12 @@ public: uint32_t GetRegisterCount() const override; + uint32_t GetUserRegisterCount() const override; + private: const lldb_private::RegisterInfo *m_register_info_p; const uint32_t m_register_count; + const uint32_t m_user_register_count; }; #endif diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp index 06eac6f7f991..7183ffcfd0f6 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextOpenBSD_i386.cpp ------------------------*- C++ -*-===// +//===-- RegisterContextOpenBSD_i386.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h b/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h index 992ce0959fdf..e6e24525b7fd 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextOpenBSD_i386_H_ -#define liblldb_RegisterContextOpenBSD_i386_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTOPENBSD_I386_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTOPENBSD_I386_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp index e210196d921d..05c1f83efded 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextOpenBSD_x86_64.cpp ----------------------*- C++ -*-===// +//===-- RegisterContextOpenBSD_x86_64.cpp ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h index 9c76e7211132..b399c721546a 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextOpenBSD_x86_64_H_ -#define liblldb_RegisterContextOpenBSD_x86_64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTOPENBSD_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTOPENBSD_X86_64_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp index 821e2aa73b5b..617893b6b3b0 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIX_arm.cpp --------------------------*- C++ -*-===// +//===-- RegisterContextPOSIX_arm.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -178,35 +178,6 @@ const char *RegisterContextPOSIX_arm::GetRegisterName(unsigned reg) { return GetRegisterInfo()[reg].name; } -lldb::ByteOrder RegisterContextPOSIX_arm::GetByteOrder() { - // Get the target process whose privileged thread was used for the register - // read. - lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; - lldb_private::Process *process = CalculateProcess().get(); - - if (process) - byte_order = process->GetByteOrder(); - return byte_order; -} - bool RegisterContextPOSIX_arm::IsRegisterSetAvailable(size_t set_index) { return set_index < k_num_register_sets; } - -// Used when parsing DWARF and EH frame information and any other object file -// sections that contain register numbers in them. -uint32_t RegisterContextPOSIX_arm::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - const uint32_t num_regs = GetRegisterCount(); - - assert(kind < lldb::kNumRegisterKinds); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { - const lldb_private::RegisterInfo *reg_info = - GetRegisterInfoAtIndex(reg_idx); - - if (reg_info->kinds[kind] == num) - return reg_idx; - } - - return LLDB_INVALID_REGNUM; -} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h index 603ba76430e6..d6967f05ed48 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextPOSIX_arm_h_ -#define liblldb_RegisterContextPOSIX_arm_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H #include "RegisterInfoInterface.h" #include "lldb-arm-register-enums.h" @@ -44,9 +44,6 @@ public: const char *GetRegisterName(unsigned reg); - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - protected: struct RegInfo { uint32_t num_registers; @@ -95,12 +92,10 @@ protected: bool IsFPR(unsigned reg); - lldb::ByteOrder GetByteOrder(); - virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool WriteGPR() = 0; virtual bool WriteFPR() = 0; }; -#endif // liblldb_RegisterContextPOSIX_arm_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp index db1aa1b8b093..8ef587f13e3a 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIX_arm64.cpp --------------------------*- C++ -*-===// +//===-- RegisterContextPOSIX_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. @@ -25,105 +25,25 @@ using namespace lldb; using namespace lldb_private; -// ARM64 general purpose registers. -const uint32_t g_gpr_regnums_arm64[] = { - gpr_x0_arm64, gpr_x1_arm64, gpr_x2_arm64, gpr_x3_arm64, - gpr_x4_arm64, gpr_x5_arm64, gpr_x6_arm64, gpr_x7_arm64, - gpr_x8_arm64, gpr_x9_arm64, gpr_x10_arm64, gpr_x11_arm64, - gpr_x12_arm64, gpr_x13_arm64, gpr_x14_arm64, gpr_x15_arm64, - gpr_x16_arm64, gpr_x17_arm64, gpr_x18_arm64, gpr_x19_arm64, - gpr_x20_arm64, gpr_x21_arm64, gpr_x22_arm64, gpr_x23_arm64, - gpr_x24_arm64, gpr_x25_arm64, gpr_x26_arm64, gpr_x27_arm64, - gpr_x28_arm64, gpr_fp_arm64, gpr_lr_arm64, gpr_sp_arm64, - gpr_pc_arm64, gpr_cpsr_arm64, gpr_w0_arm64, gpr_w1_arm64, - gpr_w2_arm64, gpr_w3_arm64, gpr_w4_arm64, gpr_w5_arm64, - gpr_w6_arm64, gpr_w7_arm64, gpr_w8_arm64, gpr_w9_arm64, - gpr_w10_arm64, gpr_w11_arm64, gpr_w12_arm64, gpr_w13_arm64, - gpr_w14_arm64, gpr_w15_arm64, gpr_w16_arm64, gpr_w17_arm64, - gpr_w18_arm64, gpr_w19_arm64, gpr_w20_arm64, gpr_w21_arm64, - gpr_w22_arm64, gpr_w23_arm64, gpr_w24_arm64, gpr_w25_arm64, - gpr_w26_arm64, gpr_w27_arm64, gpr_w28_arm64, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - - 1) == k_num_gpr_registers_arm64, - "g_gpr_regnums_arm64 has wrong number of register infos"); - -// ARM64 floating point registers. -static const uint32_t g_fpu_regnums_arm64[] = { - fpu_v0_arm64, fpu_v1_arm64, fpu_v2_arm64, fpu_v3_arm64, - fpu_v4_arm64, fpu_v5_arm64, fpu_v6_arm64, fpu_v7_arm64, - fpu_v8_arm64, fpu_v9_arm64, fpu_v10_arm64, fpu_v11_arm64, - fpu_v12_arm64, fpu_v13_arm64, fpu_v14_arm64, fpu_v15_arm64, - fpu_v16_arm64, fpu_v17_arm64, fpu_v18_arm64, fpu_v19_arm64, - fpu_v20_arm64, fpu_v21_arm64, fpu_v22_arm64, fpu_v23_arm64, - fpu_v24_arm64, fpu_v25_arm64, fpu_v26_arm64, fpu_v27_arm64, - fpu_v28_arm64, fpu_v29_arm64, fpu_v30_arm64, fpu_v31_arm64, - fpu_s0_arm64, fpu_s1_arm64, fpu_s2_arm64, fpu_s3_arm64, - fpu_s4_arm64, fpu_s5_arm64, fpu_s6_arm64, fpu_s7_arm64, - fpu_s8_arm64, fpu_s9_arm64, fpu_s10_arm64, fpu_s11_arm64, - fpu_s12_arm64, fpu_s13_arm64, fpu_s14_arm64, fpu_s15_arm64, - fpu_s16_arm64, fpu_s17_arm64, fpu_s18_arm64, fpu_s19_arm64, - fpu_s20_arm64, fpu_s21_arm64, fpu_s22_arm64, fpu_s23_arm64, - fpu_s24_arm64, fpu_s25_arm64, fpu_s26_arm64, fpu_s27_arm64, - fpu_s28_arm64, fpu_s29_arm64, fpu_s30_arm64, fpu_s31_arm64, - - fpu_d0_arm64, fpu_d1_arm64, fpu_d2_arm64, fpu_d3_arm64, - fpu_d4_arm64, fpu_d5_arm64, fpu_d6_arm64, fpu_d7_arm64, - fpu_d8_arm64, fpu_d9_arm64, fpu_d10_arm64, fpu_d11_arm64, - fpu_d12_arm64, fpu_d13_arm64, fpu_d14_arm64, fpu_d15_arm64, - fpu_d16_arm64, fpu_d17_arm64, fpu_d18_arm64, fpu_d19_arm64, - fpu_d20_arm64, fpu_d21_arm64, fpu_d22_arm64, fpu_d23_arm64, - fpu_d24_arm64, fpu_d25_arm64, fpu_d26_arm64, fpu_d27_arm64, - fpu_d28_arm64, fpu_d29_arm64, fpu_d30_arm64, fpu_d31_arm64, - fpu_fpsr_arm64, fpu_fpcr_arm64, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - - 1) == k_num_fpr_registers_arm64, - "g_fpu_regnums_arm64 has wrong number of register infos"); - -// Number of register sets provided by this context. -enum { k_num_register_sets = 2 }; - -// Register sets for ARM64. -static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_arm64, - g_gpr_regnums_arm64}, - {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64, - g_fpu_regnums_arm64}}; - bool RegisterContextPOSIX_arm64::IsGPR(unsigned reg) { - return reg <= m_reg_info.last_gpr; // GPR's come first. + if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm64::GPRegSet) + return true; + return false; } bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg) { - return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); + if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm64::FPRegSet) + return true; + return false; } RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : lldb_private::RegisterContext(thread, concrete_frame_idx) { - m_register_info_up.reset(register_info); - - switch (register_info->m_target_arch.GetMachine()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - m_reg_info.num_registers = k_num_registers_arm64; - m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; - m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; - m_reg_info.last_gpr = k_last_gpr_arm64; - m_reg_info.first_fpr = k_first_fpr_arm64; - m_reg_info.last_fpr = k_last_fpr_arm64; - m_reg_info.first_fpr_v = fpu_v0_arm64; - m_reg_info.last_fpr_v = fpu_v31_arm64; - m_reg_info.gpr_flags = gpr_cpsr_arm64; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } + lldb_private::Thread &thread, + std::unique_ptr<RegisterInfoPOSIX_arm64> register_info) + : lldb_private::RegisterContext(thread, 0), + m_register_info_up(std::move(register_info)) { ::memset(&m_fpr, 0, sizeof m_fpr); } @@ -135,19 +55,15 @@ void RegisterContextPOSIX_arm64::Invalidate() {} void RegisterContextPOSIX_arm64::InvalidateAllRegisters() {} unsigned RegisterContextPOSIX_arm64::GetRegisterOffset(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register number."); - return GetRegisterInfo()[reg].byte_offset; + return m_register_info_up->GetRegisterInfo()[reg].byte_offset; } unsigned RegisterContextPOSIX_arm64::GetRegisterSize(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register number."); - return GetRegisterInfo()[reg].byte_size; + return m_register_info_up->GetRegisterInfo()[reg].byte_size; } size_t RegisterContextPOSIX_arm64::GetRegisterCount() { - size_t num_registers = - m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers; - return num_registers; + return m_register_info_up->GetRegisterCount(); } size_t RegisterContextPOSIX_arm64::GetGPRSize() { @@ -164,71 +80,23 @@ RegisterContextPOSIX_arm64::GetRegisterInfo() { const lldb_private::RegisterInfo * RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg) { - if (reg < m_reg_info.num_registers) + if (reg < GetRegisterCount()) return &GetRegisterInfo()[reg]; else return nullptr; } size_t RegisterContextPOSIX_arm64::GetRegisterSetCount() { - size_t sets = 0; - for (size_t set = 0; set < k_num_register_sets; ++set) { - if (IsRegisterSetAvailable(set)) - ++sets; - } - - return sets; + return m_register_info_up->GetRegisterSetCount(); } const lldb_private::RegisterSet * RegisterContextPOSIX_arm64::GetRegisterSet(size_t set) { - if (IsRegisterSetAvailable(set)) { - switch (m_register_info_up->m_target_arch.GetMachine()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - return &g_reg_sets_arm64[set]; - default: - assert(false && "Unhandled target architecture."); - return nullptr; - } - } - return nullptr; + return m_register_info_up->GetRegisterSet(set); } const char *RegisterContextPOSIX_arm64::GetRegisterName(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register offset."); - return GetRegisterInfo()[reg].name; -} - -lldb::ByteOrder RegisterContextPOSIX_arm64::GetByteOrder() { - // Get the target process whose privileged thread was used for the register - // read. - lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; - lldb_private::Process *process = CalculateProcess().get(); - - if (process) - byte_order = process->GetByteOrder(); - return byte_order; -} - -bool RegisterContextPOSIX_arm64::IsRegisterSetAvailable(size_t set_index) { - return set_index < k_num_register_sets; -} - -// Used when parsing DWARF and EH frame information and any other object file -// sections that contain register numbers in them. -uint32_t RegisterContextPOSIX_arm64::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - const uint32_t num_regs = GetRegisterCount(); - - assert(kind < lldb::kNumRegisterKinds); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { - const lldb_private::RegisterInfo *reg_info = - GetRegisterInfoAtIndex(reg_idx); - - if (reg_info->kinds[kind] == num) - return reg_idx; - } - - return LLDB_INVALID_REGNUM; + if (reg < GetRegisterCount()) + return GetRegisterInfo()[reg].name; + return nullptr; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h index 49a49b69da6b..c2d5aee7f73c 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -6,10 +6,11 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextPOSIX_arm64_h_ -#define liblldb_RegisterContextPOSIX_arm64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM64_H #include "RegisterInfoInterface.h" +#include "RegisterInfoPOSIX_arm64.h" #include "lldb-arm64-register-enums.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" @@ -19,8 +20,8 @@ class ProcessMonitor; class RegisterContextPOSIX_arm64 : public lldb_private::RegisterContext { public: RegisterContextPOSIX_arm64( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); + lldb_private::Thread &thread, + std::unique_ptr<RegisterInfoPOSIX_arm64> register_info); ~RegisterContextPOSIX_arm64() override; @@ -44,50 +45,15 @@ public: const char *GetRegisterName(unsigned reg); - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - protected: - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - - uint32_t first_fpr_v; - uint32_t last_fpr_v; - - uint32_t gpr_flags; - }; - - // based on RegisterContextDarwin_arm64.h - struct VReg { - uint8_t bytes[16]; - }; - - // based on RegisterContextDarwin_arm64.h - struct FPU { - VReg v[32]; - uint32_t fpsr; - uint32_t fpcr; - }; - uint64_t m_gpr_arm64[lldb_private::k_num_gpr_registers_arm64]; // 64-bit // general // purpose // registers. - RegInfo m_reg_info; - struct RegisterContextPOSIX_arm64::FPU - m_fpr; // floating-point registers including extended register sets. - std::unique_ptr<lldb_private::RegisterInfoInterface> - m_register_info_up; // Register Info Interface (FreeBSD or Linux) - // Determines if an extended register set is supported on the processor - // running the inferior process. - virtual bool IsRegisterSetAvailable(size_t set_index); + struct RegisterInfoPOSIX_arm64::FPU + m_fpr; // floating-point registers including extended register sets. + std::unique_ptr<RegisterInfoPOSIX_arm64> m_register_info_up; virtual const lldb_private::RegisterInfo *GetRegisterInfo(); @@ -95,7 +61,7 @@ protected: bool IsFPR(unsigned reg); - lldb::ByteOrder GetByteOrder(); + size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm64::FPU); } virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; @@ -103,4 +69,4 @@ protected: virtual bool WriteFPR() = 0; }; -#endif // liblldb_RegisterContextPOSIX_arm64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM64_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp index f1fa3035b2ef..c41c4bd7a7ea 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIX_mips64.cpp -------------------------*- C++ -*-===// +//===-- RegisterContextPOSIX_mips64.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -149,17 +149,6 @@ const char *RegisterContextPOSIX_mips64::GetRegisterName(unsigned reg) { return GetRegisterInfo()[reg].name; } -lldb::ByteOrder RegisterContextPOSIX_mips64::GetByteOrder() { - // Get the target process whose privileged thread was used for the register - // read. - lldb::ByteOrder byte_order = eByteOrderInvalid; - Process *process = CalculateProcess().get(); - - if (process) - byte_order = process->GetByteOrder(); - return byte_order; -} - bool RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index) { size_t num_sets = GetRegisterSetCount(); diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h index c507e14bd5b6..1843a2a6aff3 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextPOSIX_mips64_h_ -#define liblldb_RegisterContextPOSIX_mips64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_MIPS64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_MIPS64_H #include "RegisterContext_mips.h" #include "RegisterInfoInterface.h" @@ -73,12 +73,10 @@ protected: bool IsFPR(unsigned reg); - lldb::ByteOrder GetByteOrder(); - virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool WriteGPR() = 0; virtual bool WriteFPR() = 0; }; -#endif // liblldb_RegisterContextPOSIX_mips64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_MIPS64_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp index a78e9ed37947..cd65b96d373e 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp @@ -1,5 +1,4 @@ -//===-- RegisterContextPOSIX_powerpc.cpp -------------------------*- C++ -//-*-===// +//===-- RegisterContextPOSIX_powerpc.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -158,36 +157,8 @@ const char *RegisterContextPOSIX_powerpc::GetRegisterName(unsigned reg) { return GetRegisterInfo()[reg].name; } -lldb::ByteOrder RegisterContextPOSIX_powerpc::GetByteOrder() { - // Get the target process whose privileged thread was used for the register - // read. - lldb::ByteOrder byte_order = eByteOrderInvalid; - Process *process = CalculateProcess().get(); - - if (process) - byte_order = process->GetByteOrder(); - return byte_order; -} - bool RegisterContextPOSIX_powerpc::IsRegisterSetAvailable(size_t set_index) { size_t num_sets = k_num_register_sets; return (set_index < num_sets); } - -// Used when parsing DWARF and EH frame information and any other object file -// sections that contain register numbers in them. -uint32_t RegisterContextPOSIX_powerpc::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - const uint32_t num_regs = GetRegisterCount(); - - assert(kind < kNumRegisterKinds); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); - - if (reg_info->kinds[kind] == num) - return reg_idx; - } - - return LLDB_INVALID_REGNUM; -} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h index 1a21a717b22b..e2c33461c8f1 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextPOSIX_powerpc_h_ -#define liblldb_RegisterContextPOSIX_powerpc_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_POWERPC_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_POWERPC_H #include "RegisterContext_powerpc.h" #include "RegisterInfoInterface.h" @@ -165,9 +165,6 @@ public: const char *GetRegisterName(unsigned reg); - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - protected: uint64_t m_gpr_powerpc[k_num_gpr_registers_powerpc]; // general purpose registers. @@ -189,8 +186,6 @@ protected: bool IsVMX(unsigned reg); - lldb::ByteOrder GetByteOrder(); - virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool ReadVMX() = 0; @@ -199,4 +194,4 @@ protected: virtual bool WriteVMX() = 0; }; -#endif // liblldb_RegisterContextPOSIX_powerpc_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_POWERPC_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp index 02546c0ed16f..f670be2ef3c4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIX_ppc64le.cpp -------------------------*- C++-*-===// +//===-- RegisterContextPOSIX_ppc64le.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -176,36 +176,8 @@ const char *RegisterContextPOSIX_ppc64le::GetRegisterName(unsigned reg) { return GetRegisterInfo()[reg].name; } -lldb::ByteOrder RegisterContextPOSIX_ppc64le::GetByteOrder() { - // Get the target process whose privileged thread was used for the register - // read. - lldb::ByteOrder byte_order = eByteOrderInvalid; - Process *process = CalculateProcess().get(); - - if (process) - byte_order = process->GetByteOrder(); - return byte_order; -} - bool RegisterContextPOSIX_ppc64le::IsRegisterSetAvailable(size_t set_index) { size_t num_sets = k_num_register_sets; return (set_index < num_sets); } - -// Used when parsing DWARF and EH frame information and any other object file -// sections that contain register numbers in them. -uint32_t RegisterContextPOSIX_ppc64le::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - const uint32_t num_regs = GetRegisterCount(); - - assert(kind < kNumRegisterKinds); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); - - if (reg_info->kinds[kind] == num) - return reg_idx; - } - - return LLDB_INVALID_REGNUM; -} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h index 37079775a3c7..66794ec9e9ca 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextPOSIX_ppc64le_h_ -#define liblldb_RegisterContextPOSIX_ppc64le_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_PPC64LE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_PPC64LE_H #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #include "RegisterInfoInterface.h" @@ -39,9 +39,6 @@ public: const char *GetRegisterName(unsigned reg); - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - protected: // 64-bit general purpose registers. uint64_t m_gpr_ppc64le[k_num_gpr_registers_ppc64le]; @@ -71,7 +68,6 @@ protected: bool IsVSX(unsigned reg); - lldb::ByteOrder GetByteOrder(); }; -#endif // liblldb_RegisterContextPOSIX_ppc64le_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_PPC64LE_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp index e040e5075721..e746ec642b38 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIX_s390x.cpp --------------------------*- C++ -*-===// +//===-- RegisterContextPOSIX_s390x.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -161,31 +161,3 @@ const RegisterSet *RegisterContextPOSIX_s390x::GetRegisterSet(size_t set) { } return nullptr; } - -lldb::ByteOrder RegisterContextPOSIX_s390x::GetByteOrder() { - // Get the target process whose privileged thread was used for the register - // read. - lldb::ByteOrder byte_order = eByteOrderInvalid; - Process *process = CalculateProcess().get(); - - if (process) - byte_order = process->GetByteOrder(); - return byte_order; -} - -// Used when parsing DWARF and EH frame information and any other object file -// sections that contain register numbers in them. -uint32_t RegisterContextPOSIX_s390x::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - const uint32_t num_regs = GetRegisterCount(); - - assert(kind < kNumRegisterKinds); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); - - if (reg_info->kinds[kind] == num) - return reg_idx; - } - - return LLDB_INVALID_REGNUM; -} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h index 54993ce6c3ec..7df732d13ffa 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextPOSIX_s390x_h_ -#define liblldb_RegisterContextPOSIX_s390x_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_S390X_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_S390X_H #include "RegisterContext_s390x.h" #include "RegisterInfoInterface.h" @@ -43,9 +43,6 @@ public: const char *GetRegisterName(unsigned reg); - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - protected: struct RegInfo { uint32_t num_registers; @@ -68,12 +65,10 @@ protected: bool IsFPR(unsigned reg); - lldb::ByteOrder GetByteOrder(); - virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool WriteGPR() = 0; virtual bool WriteFPR() = 0; }; -#endif // liblldb_RegisterContextPOSIX_s390x_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_S390X_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index 4d5991f08f1d..ac271a90d6a1 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIX_x86.cpp ----------------------------*- C++ -*-===// +//===-- RegisterContextPOSIX_x86.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -456,17 +456,6 @@ const char *RegisterContextPOSIX_x86::GetRegisterName(unsigned reg) { return GetRegisterInfo()[reg].name; } -lldb::ByteOrder RegisterContextPOSIX_x86::GetByteOrder() { - // Get the target process whose privileged thread was used for the register - // read. - lldb::ByteOrder byte_order = eByteOrderInvalid; - Process *process = CalculateProcess().get(); - - if (process) - byte_order = process->GetByteOrder(); - return byte_order; -} - // Parse ymm registers and into xmm.bytes and ymmh.bytes. bool RegisterContextPOSIX_x86::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order) { @@ -509,20 +498,3 @@ bool RegisterContextPOSIX_x86::IsRegisterSetAvailable(size_t set_index) { ++num_sets; return (set_index < num_sets); } - -// Used when parsing DWARF and EH frame information and any other object file -// sections that contain register numbers in them. -uint32_t RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - const uint32_t num_regs = GetRegisterCount(); - - assert(kind < kNumRegisterKinds); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); - - if (reg_info->kinds[kind] == num) - return reg_idx; - } - - return LLDB_INVALID_REGNUM; -} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h index 932f97bb567f..c4886ae618a2 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextPOSIX_x86_h_ -#define liblldb_RegisterContextPOSIX_x86_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_X86_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_X86_H #include "RegisterContext_x86.h" #include "RegisterInfoInterface.h" @@ -47,9 +47,6 @@ public: const char *GetRegisterName(unsigned reg); - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - // Note: prefer kernel definitions over user-land enum FPRType { eNotValid = 0, @@ -160,8 +157,6 @@ protected: bool IsAVX(unsigned reg); - lldb::ByteOrder GetByteOrder(); - bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order); bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order); bool IsFPR(unsigned reg, FPRType fpr_type); @@ -173,4 +168,4 @@ protected: virtual bool WriteFPR() = 0; }; -#endif // liblldb_RegisterContextPOSIX_x86_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_X86_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp index bcf60cc7a338..31e2944084ed 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextThreadMemory.cpp -------------------------*- C++ -*-===// +//===-- RegisterContextThreadMemory.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h index 09a679ab2c9f..40688a502a66 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_RegisterContextThreadMemory_h_ -#define lldb_RegisterContextThreadMemory_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTTHREADMEMORY_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTTHREADMEMORY_H #include <vector> @@ -92,9 +92,11 @@ protected: uint32_t m_stop_id; private: - DISALLOW_COPY_AND_ASSIGN(RegisterContextThreadMemory); + RegisterContextThreadMemory(const RegisterContextThreadMemory &) = delete; + const RegisterContextThreadMemory & + operator=(const RegisterContextThreadMemory &) = delete; }; } // namespace lldb_private -#endif // lldb_RegisterContextThreadMemory_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTTHREADMEMORY_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.cpp index 916d3233cde5..11556e802e33 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextWindows_i386.cpp -------------------------*- C++ -*-===// +//===-- RegisterContextWindows_i386.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.h b/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.h index 7779cc357526..6a5d3524300d 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextWindows_i386_H_ -#define liblldb_RegisterContextWindows_i386_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTWINDOWS_I386_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTWINDOWS_I386_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.cpp index e90584de1a44..4ffc4d25781c 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextWindows_x86_64.cpp -----------------------*- C++ -*-===// +//===-- RegisterContextWindows_x86_64.cpp ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.h index 18198b5b25b3..c29acf284841 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextWindows_x86_64_H_ -#define liblldb_RegisterContextWindows_x86_64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTWINDOWS_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTWINDOWS_X86_64_H #include "RegisterInfoInterface.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h b/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h index 7780be51baad..15081f974c66 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContext_mips64_H_ -#define liblldb_RegisterContext_mips64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_MIPS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_MIPS_H #include <cstddef> #include <cstdint> @@ -371,4 +371,4 @@ struct UserArea { MSA_linux_mips msa; // MSA registers. }; -#endif // liblldb_RegisterContext_mips64_H_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_MIPS_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h b/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h index 1ffcbeb5ec48..7407e2f402e0 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContext_powerpc_H_ -#define liblldb_RegisterContext_powerpc_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_POWERPC_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_POWERPC_H // eh_frame and DWARF Register numbers (eRegisterKindEHFrame & // eRegisterKindDWARF) @@ -120,4 +120,4 @@ enum { dwarf_v31_powerpc, }; -#endif // liblldb_RegisterContext_powerpc_H_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_POWERPC_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_s390x.h b/lldb/source/Plugins/Process/Utility/RegisterContext_s390x.h index 2cf39e9eb8e2..248b3bd0beac 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContext_s390x.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContext_s390x.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContext_s390x_h_ -#define liblldb_RegisterContext_s390x_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_S390X_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_S390X_H // SystemZ ehframe, dwarf regnums diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h b/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h index 2b79f778aa56..27a1bad4d53f 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContext_x86_H_ -#define liblldb_RegisterContext_x86_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_X86_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_X86_H #include <cstddef> #include <cstdint> diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoAndSetInterface.h b/lldb/source/Plugins/Process/Utility/RegisterInfoAndSetInterface.h new file mode 100644 index 000000000000..7e569dc9ba78 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoAndSetInterface.h @@ -0,0 +1,36 @@ +//===-- RegisterInfoAndSetInterface.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_REGISTERINFOANDSETINTERFACE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOANDSETINTERFACE_H + +#include "RegisterInfoInterface.h" + +#include "lldb/Utility/ArchSpec.h" +#include "lldb/lldb-private-types.h" +#include <vector> + +namespace lldb_private { + +class RegisterInfoAndSetInterface : public RegisterInfoInterface { +public: + RegisterInfoAndSetInterface(const lldb_private::ArchSpec &target_arch) + : RegisterInfoInterface(target_arch) {} + + virtual size_t GetFPRSize() const = 0; + + virtual const lldb_private::RegisterSet * + GetRegisterSet(size_t reg_set) const = 0; + + virtual size_t GetRegisterSetCount() const = 0; + + virtual size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const = 0; +}; +} // namespace lldb_private + +#endif diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h b/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h index 4b58e749adce..88c2ae7c5010 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_RegisterInfoInterface_h -#define lldb_RegisterInfoInterface_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOINTERFACE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOINTERFACE_H #include "lldb/Utility/ArchSpec.h" #include "lldb/lldb-private-types.h" @@ -61,7 +61,6 @@ public: return nullptr; } -public: // FIXME make private. lldb_private::ArchSpec m_target_arch; }; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp index d392d3be1c41..8fc4d5282b06 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp @@ -1,4 +1,4 @@ -//===-- RegisterInfoPOSIX_arm.cpp ------------------------------*- C++ -*-===// +//===-- RegisterInfoPOSIX_arm.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h index 39c2047600aa..1cf896e3decf 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterInfoPOSIX_arm_h_ -#define liblldb_RegisterInfoPOSIX_arm_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H #include "RegisterInfoInterface.h" #include "lldb/Target/RegisterContext.h" @@ -58,4 +58,4 @@ private: uint32_t m_register_info_count; }; -#endif // liblldb_RegisterInfoPOSIX_arm_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp index 8b367bdc6448..4537cee42ad9 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterInfoPOSIX_arm64.cpp ----------------------------*- C++ -*-===// +//===-- RegisterInfoPOSIX_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. @@ -65,6 +65,82 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { } } +// Number of register sets provided by this context. +enum { + k_num_gpr_registers = gpr_w28 - gpr_x0 + 1, + k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1, + k_num_register_sets = 2 +}; + +// ARM64 general purpose registers. +static const uint32_t g_gpr_regnums_arm64[] = { + gpr_x0, gpr_x1, gpr_x2, gpr_x3, + gpr_x4, gpr_x5, gpr_x6, gpr_x7, + gpr_x8, gpr_x9, gpr_x10, gpr_x11, + gpr_x12, gpr_x13, gpr_x14, gpr_x15, + gpr_x16, gpr_x17, gpr_x18, gpr_x19, + gpr_x20, gpr_x21, gpr_x22, gpr_x23, + gpr_x24, gpr_x25, gpr_x26, gpr_x27, + gpr_x28, gpr_fp, gpr_lr, gpr_sp, + gpr_pc, gpr_cpsr, gpr_w0, gpr_w1, + gpr_w2, gpr_w3, gpr_w4, gpr_w5, + gpr_w6, gpr_w7, gpr_w8, gpr_w9, + gpr_w10, gpr_w11, gpr_w12, gpr_w13, + gpr_w14, gpr_w15, gpr_w16, gpr_w17, + gpr_w18, gpr_w19, gpr_w20, gpr_w21, + gpr_w22, gpr_w23, gpr_w24, gpr_w25, + gpr_w26, gpr_w27, gpr_w28, LLDB_INVALID_REGNUM}; + +static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - + 1) == k_num_gpr_registers, + "g_gpr_regnums_arm64 has wrong number of register infos"); + +// ARM64 floating point registers. +static const uint32_t g_fpu_regnums_arm64[] = { + fpu_v0, fpu_v1, fpu_v2, + fpu_v3, fpu_v4, fpu_v5, + fpu_v6, fpu_v7, fpu_v8, + fpu_v9, fpu_v10, fpu_v11, + fpu_v12, fpu_v13, fpu_v14, + fpu_v15, fpu_v16, fpu_v17, + fpu_v18, fpu_v19, fpu_v20, + fpu_v21, fpu_v22, fpu_v23, + fpu_v24, fpu_v25, fpu_v26, + fpu_v27, fpu_v28, fpu_v29, + fpu_v30, fpu_v31, fpu_s0, + fpu_s1, fpu_s2, fpu_s3, + fpu_s4, fpu_s5, fpu_s6, + fpu_s7, fpu_s8, fpu_s9, + fpu_s10, fpu_s11, fpu_s12, + fpu_s13, fpu_s14, fpu_s15, + fpu_s16, fpu_s17, fpu_s18, + fpu_s19, fpu_s20, fpu_s21, + fpu_s22, fpu_s23, fpu_s24, + fpu_s25, fpu_s26, fpu_s27, + fpu_s28, fpu_s29, fpu_s30, + fpu_s31, fpu_d0, fpu_d1, + fpu_d2, fpu_d3, fpu_d4, + fpu_d5, fpu_d6, fpu_d7, + fpu_d8, fpu_d9, fpu_d10, + fpu_d11, fpu_d12, fpu_d13, + fpu_d14, fpu_d15, fpu_d16, + fpu_d17, fpu_d18, fpu_d19, + fpu_d20, fpu_d21, fpu_d22, + fpu_d23, fpu_d24, fpu_d25, + fpu_d26, fpu_d27, fpu_d28, + fpu_d29, fpu_d30, fpu_d31, + fpu_fpsr, fpu_fpcr, LLDB_INVALID_REGNUM}; +static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - + 1) == k_num_fpr_registers, + "g_fpu_regnums_arm64 has wrong number of register infos"); +// clang-format on +// Register sets for ARM64. +static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers, + g_gpr_regnums_arm64}, + {"Floating Point Registers", "fpu", k_num_fpr_registers, + g_fpu_regnums_arm64}}; + static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { @@ -80,19 +156,60 @@ GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( const lldb_private::ArchSpec &target_arch) - : lldb_private::RegisterInfoInterface(target_arch), + : lldb_private::RegisterInfoAndSetInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), - m_register_info_count(GetRegisterInfoCount(target_arch)) {} + m_register_info_count(GetRegisterInfoCount(target_arch)) { + + switch (target_arch.GetMachine()) { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + num_registers = k_num_gpr_registers + k_num_fpr_registers; + num_gpr_registers = k_num_gpr_registers; + num_fpr_registers = k_num_fpr_registers; + last_gpr = gpr_w28; + first_fpr = fpu_v0; + last_fpr = fpu_fpcr; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } +} + +uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const { + return num_gpr_registers + num_fpr_registers; +} size_t RegisterInfoPOSIX_arm64::GetGPRSize() const { return sizeof(struct RegisterInfoPOSIX_arm64::GPR); } +size_t RegisterInfoPOSIX_arm64::GetFPRSize() const { + return sizeof(struct RegisterInfoPOSIX_arm64::FPU); +} + const lldb_private::RegisterInfo * RegisterInfoPOSIX_arm64::GetRegisterInfo() const { return m_register_info_p; } -uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const { - return m_register_info_count; +size_t RegisterInfoPOSIX_arm64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +size_t RegisterInfoPOSIX_arm64::GetRegisterSetFromRegisterIndex( + uint32_t reg_index) const { + if (reg_index <= last_gpr) + return GPRegSet; + else if (reg_index <= last_fpr) + return FPRegSet; + return LLDB_INVALID_REGNUM; +} + +const lldb_private::RegisterSet * +RegisterInfoPOSIX_arm64::GetRegisterSet(size_t set_index) const { + if (set_index < k_num_register_sets) + return &g_reg_sets_arm64[set_index]; + + return nullptr; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h index ace179a81814..2da6a531a6b6 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h @@ -6,15 +6,18 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextLinux_arm64_H_ -#define liblldb_RegisterContextLinux_arm64_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM64_H -#include "RegisterInfoInterface.h" +#include "RegisterInfoAndSetInterface.h" #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" -class RegisterInfoPOSIX_arm64 : public lldb_private::RegisterInfoInterface { +class RegisterInfoPOSIX_arm64 + : public lldb_private::RegisterInfoAndSetInterface { public: + enum { GPRegSet = 0, FPRegSet }; + // based on RegisterContextDarwin_arm64.h struct GPR { uint64_t x[29]; // x0-x28 @@ -57,11 +60,28 @@ public: size_t GetGPRSize() const override; + size_t GetFPRSize() const override; + const lldb_private::RegisterInfo *GetRegisterInfo() const override; uint32_t GetRegisterCount() const override; + const lldb_private::RegisterSet * + GetRegisterSet(size_t reg_set) const override; + + size_t GetRegisterSetCount() const override; + + size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override; + private: + uint32_t num_registers; + uint32_t num_gpr_registers; + uint32_t num_fpr_registers; + + uint32_t last_gpr; + uint32_t first_fpr; + uint32_t last_fpr; + const lldb_private::RegisterInfo *m_register_info_p; uint32_t m_register_info_count; }; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp index 35051a3ce095..3461d38a3901 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp @@ -1,4 +1,4 @@ -//===-- RegisterInfoPOSIX_ppc64le.cpp --------------------------*- C++ -*-===// +//===-- RegisterInfoPOSIX_ppc64le.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h index c4d4d3b546e2..98549ac0dda4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextLinux_ppc64le_H_ -#define liblldb_RegisterContextLinux_ppc64le_H_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_PPC64LE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_PPC64LE_H #include "RegisterInfoInterface.h" #include "lldb/Target/RegisterContext.h" diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h index 68c12aa6e529..4aee55e7afba 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -456,37 +456,26 @@ static uint32_t g_d29_invalidates[] = {fpu_v29, fpu_s29, LLDB_INVALID_REGNUM}; static uint32_t g_d30_invalidates[] = {fpu_v30, fpu_s30, LLDB_INVALID_REGNUM}; static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; -// Generates register kinds array for 64-bit general purpose registers -#define GPR64_KIND(reg, generic_kind) \ +// Generates register kinds array with DWARF, EH frame and generic kind +#define MISC_KIND(reg, type, generic_kind) \ { \ arm64_ehframe::reg, arm64_dwarf::reg, generic_kind, LLDB_INVALID_REGNUM, \ - gpr_##reg \ + type##_##reg \ } -// Generates register kinds array for registers with lldb kind -#define MISC_KIND(lldb_kind) \ +// Generates register kinds array for registers with only lldb kind +#define LLDB_KIND(lldb_kind) \ { \ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ LLDB_INVALID_REGNUM, lldb_kind \ } // Generates register kinds array for vector registers -#define VREG_KIND(reg) \ - { \ - LLDB_INVALID_REGNUM, arm64_dwarf::reg, LLDB_INVALID_REGNUM, \ - LLDB_INVALID_REGNUM, fpu_##reg \ - } - -// Generates register kinds array for cpsr -#define CPSR_KIND(lldb_kind) \ - { \ - arm64_ehframe::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, \ - LLDB_INVALID_REGNUM, lldb_kind \ - } - -#define MISC_GPR_KIND(lldb_kind) CPSR_KIND(lldb_kind) -#define MISC_FPU_KIND(lldb_kind) MISC_KIND(lldb_kind) -#define MISC_EXC_KIND(lldb_kind) MISC_KIND(lldb_kind) +#define GPR64_KIND(reg, generic_kind) MISC_KIND(reg, gpr, generic_kind) +#define VREG_KIND(reg) MISC_KIND(reg, fpu, LLDB_INVALID_REGNUM) +#define MISC_GPR_KIND(lldb_kind) MISC_KIND(cpsr, gpr, LLDB_REGNUM_GENERIC_FLAGS) +#define MISC_FPU_KIND(lldb_kind) LLDB_KIND(lldb_kind) +#define MISC_EXC_KIND(lldb_kind) LLDB_KIND(lldb_kind) // Defines a 64-bit general purpose register #define DEFINE_GPR64(reg, generic_kind) \ @@ -509,7 +498,7 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; { \ #wreg, nullptr, 4, \ GPR_OFFSET(gpr_##xreg) + GPR_W_PSEUDO_REG_ENDIAN_OFFSET, \ - lldb::eEncodingUint, lldb::eFormatHex, MISC_KIND(gpr_##wreg), \ + lldb::eEncodingUint, lldb::eFormatHex, LLDB_KIND(gpr_##wreg), \ g_contained_##xreg, g_##wreg##_invalidates, nullptr, 0 \ } @@ -521,11 +510,11 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; 0 \ } -// Defines S and D pseudo registers mapping over correspondig vector register +// Defines S and D pseudo registers mapping over corresponding vector register #define DEFINE_FPU_PSEUDO(reg, size, offset, vreg) \ { \ #reg, nullptr, size, FPU_OFFSET(fpu_##vreg - fpu_v0) + offset, \ - lldb::eEncodingIEEE754, lldb::eFormatFloat, MISC_KIND(fpu_##reg), \ + lldb::eEncodingIEEE754, lldb::eFormatFloat, LLDB_KIND(fpu_##reg), \ g_contained_##vreg, g_##reg##_invalidates, nullptr, 0 \ } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h index 72ff904520ad..343579cd2657 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h @@ -145,7 +145,7 @@ DR_OFFSET(i), eEncodingUint, eFormatHex, \ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ - LLDB_INVALID_REGNUM }, \ + lldb_##reg##i##_i386 }, \ nullptr, nullptr, nullptr, 0 \ } diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index 6d03bd534f37..2d8e8ef21612 100644 --- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -1,4 +1,4 @@ -//===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===// +//===-- StopInfoMachException.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,6 +8,7 @@ #include "StopInfoMachException.h" +#include "lldb/lldb-forward.h" #if defined(__APPLE__) // Needed for the EXC_RESOURCE interpretation macros @@ -289,10 +290,48 @@ const char *StopInfoMachException::GetDescription() { if (m_exc_data_count > 0) strm.PutChar(')'); - m_description = strm.GetString(); + m_description = std::string(strm.GetString()); return m_description.c_str(); } +static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target, + uint32_t exc_data_count, + uint64_t exc_sub_code, + uint64_t exc_sub_sub_code) { + // Try hardware watchpoint. + if (target) { + // 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()); + } + } + + // Try hardware breakpoint. + ProcessSP process_sp(thread.GetProcess()); + if (process_sp) { + // The exc_sub_code indicates the data break address. + lldb::BreakpointSiteSP bp_sp = + 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()); + } + } + + return nullptr; +} + StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( Thread &thread, uint32_t exc_type, uint32_t exc_data_count, uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, @@ -350,22 +389,10 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( is_actual_breakpoint = true; is_trace_if_actual_breakpoint_missing = true; } else { - - // It's a watchpoint, then. - // The exc_sub_code indicates the data break address. - lldb::WatchpointSP wp_sp; - if (target) - 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()); - } + if (StopInfoSP stop_info = + GetStopInfoForHardwareBP(thread, target, exc_data_count, + exc_sub_code, exc_sub_sub_code)) + return stop_info; } } else if (exc_code == 2 || // EXC_I386_BPT exc_code == 3) // EXC_I386_BPTFLT diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.h b/lldb/source/Plugins/Process/Utility/StopInfoMachException.h index 74c05812ab00..d9c1886d7096 100644 --- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.h +++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_StopInfoMachException_h_ -#define liblldb_StopInfoMachException_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_STOPINFOMACHEXCEPTION_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_STOPINFOMACHEXCEPTION_H #include <string> @@ -48,4 +48,4 @@ protected: } // namespace lldb_private -#endif // liblldb_StopInfoMachException_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_STOPINFOMACHEXCEPTION_H diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp index 80b04bb14f77..7469e7633e71 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -1,5 +1,4 @@ -//===-- ThreadMemory.cpp ----------------------------------------------*- C++ -//-*-===// +//===-- ThreadMemory.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -30,7 +29,8 @@ ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid, llvm::StringRef name, llvm::StringRef queue, lldb::addr_t register_data_addr) : Thread(process, tid), m_backing_thread_sp(), m_thread_info_valobj_sp(), - m_name(name), m_queue(queue), m_register_data_addr(register_data_addr) {} + m_name(std::string(name)), m_queue(std::string(queue)), + m_register_data_addr(register_data_addr) {} ThreadMemory::~ThreadMemory() { DestroyThread(); } @@ -54,20 +54,14 @@ RegisterContextSP ThreadMemory::GetRegisterContext() { RegisterContextSP ThreadMemory::CreateRegisterContextForFrame(StackFrame *frame) { - RegisterContextSP reg_ctx_sp; uint32_t concrete_frame_idx = 0; if (frame) concrete_frame_idx = frame->GetConcreteFrameIndex(); - if (concrete_frame_idx == 0) { - reg_ctx_sp = GetRegisterContext(); - } else { - Unwind *unwinder = GetUnwinder(); - if (unwinder != nullptr) - reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); - } - return reg_ctx_sp; + if (concrete_frame_idx == 0) + return GetRegisterContext(); + return GetUnwinder().CreateRegisterContextForFrame(frame); } bool ThreadMemory::CalculateStopInfo() { diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.h b/lldb/source/Plugins/Process/Utility/ThreadMemory.h index 85bc1451e4a0..d124f5780ea9 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.h +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ThreadMemory_h_ -#define liblldb_ThreadMemory_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_THREADMEMORY_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_THREADMEMORY_H #include <string> @@ -100,7 +100,8 @@ protected: lldb::addr_t m_register_data_addr; private: - DISALLOW_COPY_AND_ASSIGN(ThreadMemory); + ThreadMemory(const ThreadMemory &) = delete; + const ThreadMemory &operator=(const ThreadMemory &) = delete; }; -#endif // liblldb_ThreadMemory_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_THREADMEMORY_H diff --git a/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp deleted file mode 100644 index 74fc90e88547..000000000000 --- a/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ /dev/null @@ -1,519 +0,0 @@ -//===-- UnwindLLDB.cpp -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Core/Module.h" -#include "lldb/Symbol/FuncUnwinders.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/UnwindPlan.h" -#include "lldb/Target/ABI.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/Log.h" - -#include "RegisterContextLLDB.h" -#include "UnwindLLDB.h" - -using namespace lldb; -using namespace lldb_private; - -UnwindLLDB::UnwindLLDB(Thread &thread) - : Unwind(thread), m_frames(), m_unwind_complete(false), - m_user_supplied_trap_handler_functions() { - ProcessSP process_sp(thread.GetProcess()); - if (process_sp) { - Args args; - process_sp->GetTarget().GetUserSpecifiedTrapHandlerNames(args); - size_t count = args.GetArgumentCount(); - for (size_t i = 0; i < count; i++) { - const char *func_name = args.GetArgumentAtIndex(i); - m_user_supplied_trap_handler_functions.push_back(ConstString(func_name)); - } - } -} - -uint32_t UnwindLLDB::DoGetFrameCount() { - if (!m_unwind_complete) { -//#define DEBUG_FRAME_SPEED 1 -#if DEBUG_FRAME_SPEED -#define FRAME_COUNT 10000 - using namespace std::chrono; - auto time_value = steady_clock::now(); -#endif - if (!AddFirstFrame()) - return 0; - - ProcessSP process_sp(m_thread.GetProcess()); - ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - - while (AddOneMoreFrame(abi)) { -#if DEBUG_FRAME_SPEED - if ((m_frames.size() % FRAME_COUNT) == 0) { - const auto now = steady_clock::now(); - const auto delta_t = now - time_value; - printf("%u frames in %.9f ms (%g frames/sec)\n", FRAME_COUNT, - duration<double, std::milli>(delta_t).count(), - (float)FRAME_COUNT / duration<double>(delta_t).count()); - time_value = now; - } -#endif - } - } - return m_frames.size(); -} - -bool UnwindLLDB::AddFirstFrame() { - if (m_frames.size() > 0) - return true; - - ProcessSP process_sp(m_thread.GetProcess()); - ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - - // First, set up the 0th (initial) frame - CursorSP first_cursor_sp(new Cursor()); - RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB( - m_thread, RegisterContextLLDBSP(), first_cursor_sp->sctx, 0, *this)); - if (reg_ctx_sp.get() == nullptr) - goto unwind_done; - - if (!reg_ctx_sp->IsValid()) - goto unwind_done; - - if (!reg_ctx_sp->GetCFA(first_cursor_sp->cfa)) - goto unwind_done; - - if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) - goto unwind_done; - - // Everything checks out, so release the auto pointer value and let the - // cursor own it in its shared pointer - first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; - m_frames.push_back(first_cursor_sp); - - // Update the Full Unwind Plan for this frame if not valid - UpdateUnwindPlanForFirstFrameIfInvalid(abi); - - return true; - -unwind_done: - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (log) { - LLDB_LOGF(log, "th%d Unwind of this thread is complete.", - m_thread.GetIndexID()); - } - m_unwind_complete = true; - return false; -} - -UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { - assert(m_frames.size() != 0 && - "Get one more frame called with empty frame list"); - - // If we've already gotten to the end of the stack, don't bother to try - // again... - if (m_unwind_complete) - return nullptr; - - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - - CursorSP prev_frame = m_frames.back(); - uint32_t cur_idx = m_frames.size(); - - CursorSP cursor_sp(new Cursor()); - RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB( - m_thread, prev_frame->reg_ctx_lldb_sp, cursor_sp->sctx, cur_idx, *this)); - - uint64_t max_stack_depth = m_thread.GetMaxBacktraceDepth(); - - // We want to detect an unwind that cycles erroneously and stop backtracing. - // Don't want this maximum unwind limit to be too low -- if you have a - // backtrace with an "infinitely recursing" bug, it will crash when the stack - // blows out and the first 35,000 frames are uninteresting - it's the top - // most 5 frames that you actually care about. So you can't just cap the - // unwind at 10,000 or something. Realistically anything over around 200,000 - // is going to blow out the stack space. If we're still unwinding at that - // point, we're probably never going to finish. - if (cur_idx >= max_stack_depth) { - LLDB_LOGF(log, - "%*sFrame %d unwound too many frames, assuming unwind has " - "gone astray, stopping.", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); - return nullptr; - } - - if (reg_ctx_sp.get() == nullptr) { - // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to - // that and return true. Subsequent calls to TryFallbackUnwindPlan() will - // return false. - if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { - // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame - // still needs to be updated. Hence updating it. - if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) - return nullptr; - - return GetOneMoreFrame(abi); - } - - LLDB_LOGF(log, "%*sFrame %d did not get a RegisterContext, stopping.", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); - return nullptr; - } - - if (!reg_ctx_sp->IsValid()) { - // We failed to get a valid RegisterContext. See if the regctx below this - // on the stack has a fallback unwind plan it can use. Subsequent calls to - // TryFallbackUnwindPlan() will return false. - if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { - // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame - // still needs to be updated. Hence updating it. - if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) - return nullptr; - - return GetOneMoreFrame(abi); - } - - LLDB_LOGF(log, - "%*sFrame %d invalid RegisterContext for this frame, " - "stopping stack walk", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); - return nullptr; - } - if (!reg_ctx_sp->GetCFA(cursor_sp->cfa)) { - // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to - // that and return true. Subsequent calls to TryFallbackUnwindPlan() will - // return false. - if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { - // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame - // still needs to be updated. Hence updating it. - if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) - return nullptr; - - return GetOneMoreFrame(abi); - } - - LLDB_LOGF(log, - "%*sFrame %d did not get CFA for this frame, stopping stack walk", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); - return nullptr; - } - if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa)) { - // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not - // have its (constructed) CFA aligned correctly -- don't do the abi - // alignment check for these. - if (!reg_ctx_sp->IsTrapHandlerFrame()) { - // See if we can find a fallback unwind plan for THIS frame. It may be - // that the UnwindPlan we're using for THIS frame was bad and gave us a - // bad CFA. If that's not it, then see if we can change the UnwindPlan - // for the frame below us ("NEXT") -- see if using that other UnwindPlan - // gets us a better unwind state. - if (!reg_ctx_sp->TryFallbackUnwindPlan() || - !reg_ctx_sp->GetCFA(cursor_sp->cfa) || - !abi->CallFrameAddressIsValid(cursor_sp->cfa)) { - if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { - // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of prev_frame. However, cfa field of - // prev_frame still needs to be updated. Hence updating it. - if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) - return nullptr; - - return GetOneMoreFrame(abi); - } - - LLDB_LOGF(log, - "%*sFrame %d did not get a valid CFA for this frame, " - "stopping stack walk", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); - return nullptr; - } else { - LLDB_LOGF(log, - "%*sFrame %d had a bad CFA value but we switched the " - "UnwindPlan being used and got one that looks more " - "realistic.", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); - } - } - } - if (!reg_ctx_sp->ReadPC(cursor_sp->start_pc)) { - // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to - // that and return true. Subsequent calls to TryFallbackUnwindPlan() will - // return false. - if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { - // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame - // still needs to be updated. Hence updating it. - if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) - return nullptr; - - return GetOneMoreFrame(abi); - } - - LLDB_LOGF(log, - "%*sFrame %d did not get PC for this frame, stopping stack walk", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); - return nullptr; - } - if (abi && !abi->CodeAddressIsValid(cursor_sp->start_pc)) { - // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to - // that and return true. Subsequent calls to TryFallbackUnwindPlan() will - // return false. - if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { - // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame - // still needs to be updated. Hence updating it. - if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) - return nullptr; - - return GetOneMoreFrame(abi); - } - - LLDB_LOGF(log, "%*sFrame %d did not get a valid PC, stopping stack walk", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); - return nullptr; - } - // Infinite loop where the current cursor is the same as the previous one... - if (prev_frame->start_pc == cursor_sp->start_pc && - prev_frame->cfa == cursor_sp->cfa) { - LLDB_LOGF(log, - "th%d pc of this frame is the same as the previous frame and " - "CFAs for both frames are identical -- stopping unwind", - m_thread.GetIndexID()); - return nullptr; - } - - cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; - return cursor_sp; -} - -void UnwindLLDB::UpdateUnwindPlanForFirstFrameIfInvalid(ABI *abi) { - // This function is called for First Frame only. - assert(m_frames.size() == 1 && "No. of cursor frames are not 1"); - - bool old_m_unwind_complete = m_unwind_complete; - CursorSP old_m_candidate_frame = m_candidate_frame; - - // Try to unwind 2 more frames using the Unwinder. It uses Full UnwindPlan - // and if Full UnwindPlan fails, then uses FallBack UnwindPlan. Also update - // the cfa of Frame 0 (if required). - AddOneMoreFrame(abi); - - // Remove all the frames added by above function as the purpose of using - // above function was just to check whether Unwinder of Frame 0 works or not. - for (uint32_t i = 1; i < m_frames.size(); i++) - m_frames.pop_back(); - - // Restore status after calling AddOneMoreFrame - m_unwind_complete = old_m_unwind_complete; - m_candidate_frame = old_m_candidate_frame; - return; -} - -bool UnwindLLDB::AddOneMoreFrame(ABI *abi) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - - // Frame zero is a little different - if (m_frames.empty()) - return false; - - // If we've already gotten to the end of the stack, don't bother to try - // again... - if (m_unwind_complete) - return false; - - CursorSP new_frame = m_candidate_frame; - if (new_frame == nullptr) - new_frame = GetOneMoreFrame(abi); - - if (new_frame == nullptr) { - LLDB_LOGF(log, "th%d Unwind of this thread is complete.", - m_thread.GetIndexID()); - m_unwind_complete = true; - return false; - } - - m_frames.push_back(new_frame); - - // If we can get one more frame further then accept that we get back a - // correct frame. - m_candidate_frame = GetOneMoreFrame(abi); - if (m_candidate_frame) - return true; - - // We can't go further from the frame returned by GetOneMore frame. Lets try - // to get a different frame with using the fallback unwind plan. - if (!m_frames[m_frames.size() - 2] - ->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { - // We don't have a valid fallback unwind plan. Accept the frame as it is. - // This is a valid situation when we are at the bottom of the stack. - return true; - } - - // Remove the possibly incorrect frame from the frame list and try to add a - // different one with the newly selected fallback unwind plan. - m_frames.pop_back(); - CursorSP new_frame_v2 = GetOneMoreFrame(abi); - if (new_frame_v2 == nullptr) { - // We haven't got a new frame from the fallback unwind plan. Accept the - // frame from the original unwind plan. This is a valid situation when we - // are at the bottom of the stack. - m_frames.push_back(new_frame); - return true; - } - - // Push the new frame to the list and try to continue from this frame. If we - // can get a new frame then accept it as the correct one. - m_frames.push_back(new_frame_v2); - m_candidate_frame = GetOneMoreFrame(abi); - if (m_candidate_frame) { - // If control reached here then TryFallbackUnwindPlan had succeeded for - // Cursor::m_frames[m_frames.size() - 2]. It also succeeded to Unwind next - // 2 frames i.e. m_frames[m_frames.size() - 1] and a frame after that. For - // Cursor::m_frames[m_frames.size() - 2], reg_ctx_lldb_sp field was already - // updated during TryFallbackUnwindPlan call above. However, cfa field - // still needs to be updated. Hence updating it here and then returning. - return m_frames[m_frames.size() - 2]->reg_ctx_lldb_sp->GetCFA( - m_frames[m_frames.size() - 2]->cfa); - } - - // The new frame hasn't helped in unwinding. Fall back to the original one as - // the default unwind plan is usually more reliable then the fallback one. - m_frames.pop_back(); - m_frames.push_back(new_frame); - return true; -} - -bool UnwindLLDB::DoGetFrameInfoAtIndex(uint32_t idx, addr_t &cfa, addr_t &pc, - bool &behaves_like_zeroth_frame) { - if (m_frames.size() == 0) { - if (!AddFirstFrame()) - return false; - } - - ProcessSP process_sp(m_thread.GetProcess()); - ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - - while (idx >= m_frames.size() && AddOneMoreFrame(abi)) - ; - - if (idx < m_frames.size()) { - cfa = m_frames[idx]->cfa; - pc = m_frames[idx]->start_pc; - if (idx == 0) { - // Frame zero always behaves like it. - behaves_like_zeroth_frame = true; - } else if (m_frames[idx - 1]->reg_ctx_lldb_sp->IsTrapHandlerFrame()) { - // This could be an asynchronous signal, thus the - // pc might point to the interrupted instruction rather - // than a post-call instruction - behaves_like_zeroth_frame = true; - } else if (m_frames[idx]->reg_ctx_lldb_sp->IsTrapHandlerFrame()) { - // This frame may result from signal processing installing - // a pointer to the first byte of a signal-return trampoline - // in the return address slot of the frame below, so this - // too behaves like the zeroth frame (i.e. the pc might not - // be pointing just past a call in it) - behaves_like_zeroth_frame = true; - } else { - behaves_like_zeroth_frame = false; - } - return true; - } - return false; -} - -lldb::RegisterContextSP -UnwindLLDB::DoCreateRegisterContextForFrame(StackFrame *frame) { - lldb::RegisterContextSP reg_ctx_sp; - uint32_t idx = frame->GetConcreteFrameIndex(); - - if (idx == 0) { - return m_thread.GetRegisterContext(); - } - - if (m_frames.size() == 0) { - if (!AddFirstFrame()) - return reg_ctx_sp; - } - - ProcessSP process_sp(m_thread.GetProcess()); - ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - - while (idx >= m_frames.size()) { - if (!AddOneMoreFrame(abi)) - break; - } - - const uint32_t num_frames = m_frames.size(); - if (idx < num_frames) { - Cursor *frame_cursor = m_frames[idx].get(); - reg_ctx_sp = frame_cursor->reg_ctx_lldb_sp; - } - return reg_ctx_sp; -} - -UnwindLLDB::RegisterContextLLDBSP -UnwindLLDB::GetRegisterContextForFrameNum(uint32_t frame_num) { - RegisterContextLLDBSP reg_ctx_sp; - if (frame_num < m_frames.size()) - reg_ctx_sp = m_frames[frame_num]->reg_ctx_lldb_sp; - return reg_ctx_sp; -} - -bool UnwindLLDB::SearchForSavedLocationForRegister( - uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, - uint32_t starting_frame_num, bool pc_reg) { - int64_t frame_num = starting_frame_num; - if (static_cast<size_t>(frame_num) >= m_frames.size()) - return false; - - // Never interrogate more than one level while looking for the saved pc - // value. If the value isn't saved by frame_num, none of the frames lower on - // the stack will have a useful value. - if (pc_reg) { - UnwindLLDB::RegisterSearchResult result; - result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister( - lldb_regnum, regloc); - return result == UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - while (frame_num >= 0) { - UnwindLLDB::RegisterSearchResult result; - result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister( - lldb_regnum, regloc); - - // We descended down to the live register context aka stack frame 0 and are - // reading the value out of a live register. - if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound && - regloc.type == - UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext) { - return true; - } - - // If we have unwind instructions saying that register N is saved in - // register M in the middle of the stack (and N can equal M here, meaning - // the register was not used in this function), then change the register - // number we're looking for to M and keep looking for a concrete location - // down the stack, or an actual value from a live RegisterContext at frame - // 0. - if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound && - regloc.type == UnwindLLDB::RegisterLocation::eRegisterInRegister && - frame_num > 0) { - result = UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - lldb_regnum = regloc.location.register_number; - } - - if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound) - return true; - if (result == UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile) - return false; - frame_num--; - } - return false; -} diff --git a/lldb/source/Plugins/Process/Utility/UnwindLLDB.h b/lldb/source/Plugins/Process/Utility/UnwindLLDB.h deleted file mode 100644 index ff5db39730b5..000000000000 --- a/lldb/source/Plugins/Process/Utility/UnwindLLDB.h +++ /dev/null @@ -1,158 +0,0 @@ -//===-- UnwindLLDB.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_UnwindLLDB_h_ -#define lldb_UnwindLLDB_h_ - -#include <vector> - -#include "lldb/Symbol/FuncUnwinders.h" -#include "lldb/Symbol/SymbolContext.h" -#include "lldb/Symbol/UnwindPlan.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Unwind.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/lldb-public.h" - -namespace lldb_private { - -class RegisterContextLLDB; - -class UnwindLLDB : public lldb_private::Unwind { -public: - UnwindLLDB(lldb_private::Thread &thread); - - ~UnwindLLDB() override = default; - - enum RegisterSearchResult { - eRegisterFound = 0, - eRegisterNotFound, - eRegisterIsVolatile - }; - -protected: - friend class lldb_private::RegisterContextLLDB; - - struct RegisterLocation { - enum RegisterLocationTypes { - eRegisterNotSaved = 0, // register was not preserved by callee. If - // volatile reg, is unavailable - eRegisterSavedAtMemoryLocation, // register is saved at a specific word of - // target mem (target_memory_location) - eRegisterInRegister, // register is available in a (possible other) - // register (register_number) - eRegisterSavedAtHostMemoryLocation, // register is saved at a word in - // lldb's address space - eRegisterValueInferred, // register val was computed (and is in - // inferred_value) - eRegisterInLiveRegisterContext // register value is in a live (stack frame - // #0) register - }; - int type; - union { - lldb::addr_t target_memory_location; - uint32_t - register_number; // in eRegisterKindLLDB register numbering system - void *host_memory_location; - uint64_t inferred_value; // eRegisterValueInferred - e.g. stack pointer == - // cfa + offset - } location; - }; - - void DoClear() override { - m_frames.clear(); - m_candidate_frame.reset(); - m_unwind_complete = false; - } - - uint32_t DoGetFrameCount() override; - - bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, - lldb::addr_t &start_pc, - bool &behaves_like_zeroth_frame) override; - - lldb::RegisterContextSP - DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; - - typedef std::shared_ptr<RegisterContextLLDB> RegisterContextLLDBSP; - - // Needed to retrieve the "next" frame (e.g. frame 2 needs to retrieve frame - // 1's RegisterContextLLDB) - // The RegisterContext for frame_num must already exist or this returns an - // empty shared pointer. - RegisterContextLLDBSP GetRegisterContextForFrameNum(uint32_t frame_num); - - // Iterate over the RegisterContextLLDB's in our m_frames vector, look for the - // first one that - // has a saved location for this reg. - bool SearchForSavedLocationForRegister( - uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, - uint32_t starting_frame_num, bool pc_register); - - /// Provide the list of user-specified trap handler functions - /// - /// The Platform is one source of trap handler function names; that - /// may be augmented via a setting. The setting needs to be converted - /// into an array of ConstStrings before it can be used - we only want - /// to do that once per thread so it's here in the UnwindLLDB object. - /// - /// \return - /// Vector of ConstStrings of trap handler function names. May be - /// empty. - const std::vector<ConstString> &GetUserSpecifiedTrapHandlerFunctionNames() { - return m_user_supplied_trap_handler_functions; - } - -private: - struct Cursor { - lldb::addr_t start_pc; // The start address of the function/symbol for this - // frame - current pc if unknown - lldb::addr_t cfa; // The canonical frame address for this stack frame - lldb_private::SymbolContext sctx; // A symbol context we'll contribute to & - // provide to the StackFrame creation - RegisterContextLLDBSP - reg_ctx_lldb_sp; // These are all RegisterContextLLDB's - - Cursor() - : start_pc(LLDB_INVALID_ADDRESS), cfa(LLDB_INVALID_ADDRESS), sctx(), - reg_ctx_lldb_sp() {} - - private: - DISALLOW_COPY_AND_ASSIGN(Cursor); - }; - - typedef std::shared_ptr<Cursor> CursorSP; - std::vector<CursorSP> m_frames; - CursorSP m_candidate_frame; - bool m_unwind_complete; // If this is true, we've enumerated all the frames in - // the stack, and m_frames.size() is the - // number of frames, etc. Otherwise we've only gone as far as directly asked, - // and m_frames.size() - // is how far we've currently gone. - - std::vector<ConstString> m_user_supplied_trap_handler_functions; - - // Check if Full UnwindPlan of First frame is valid or not. - // If not then try Fallback UnwindPlan of the frame. If Fallback - // UnwindPlan succeeds then update the Full UnwindPlan with the - // Fallback UnwindPlan. - void UpdateUnwindPlanForFirstFrameIfInvalid(ABI *abi); - - CursorSP GetOneMoreFrame(ABI *abi); - - bool AddOneMoreFrame(ABI *abi); - - bool AddFirstFrame(); - - // For UnwindLLDB only - DISALLOW_COPY_AND_ASSIGN(UnwindLLDB); -}; - -} // namespace lldb_private - -#endif // lldb_UnwindLLDB_h_ diff --git a/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp deleted file mode 100644 index 558edeec1a37..000000000000 --- a/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp +++ /dev/null @@ -1,247 +0,0 @@ -//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/Symbol.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/ArchSpec.h" - -#include "RegisterContextMacOSXFrameBackchain.h" - -#include <memory> - -using namespace lldb; -using namespace lldb_private; - -UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain(Thread &thread) - : Unwind(thread), m_cursors() {} - -uint32_t UnwindMacOSXFrameBackchain::DoGetFrameCount() { - if (m_cursors.empty()) { - ExecutionContext exe_ctx(m_thread.shared_from_this()); - Target *target = exe_ctx.GetTargetPtr(); - if (target) { - const ArchSpec &target_arch = target->GetArchitecture(); - // Frame zero should always be supplied by the thread... - exe_ctx.SetFrameSP(m_thread.GetStackFrameAtIndex(0)); - - if (target_arch.GetAddressByteSize() == 8) - GetStackFrameData_x86_64(exe_ctx); - else - GetStackFrameData_i386(exe_ctx); - } - } - return m_cursors.size(); -} - -bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex( - uint32_t idx, addr_t &cfa, addr_t &pc, bool &behaves_like_zeroth_frame) { - const uint32_t frame_count = GetFrameCount(); - if (idx < frame_count) { - if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS) - return false; - if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS) - return false; - - pc = m_cursors[idx].pc; - cfa = m_cursors[idx].fp; - behaves_like_zeroth_frame = (idx == 0); - - return true; - } - return false; -} - -lldb::RegisterContextSP -UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame(StackFrame *frame) { - lldb::RegisterContextSP reg_ctx_sp; - uint32_t concrete_idx = frame->GetConcreteFrameIndex(); - const uint32_t frame_count = GetFrameCount(); - if (concrete_idx < frame_count) - reg_ctx_sp = std::make_shared<RegisterContextMacOSXFrameBackchain>( - m_thread, concrete_idx, m_cursors[concrete_idx]); - return reg_ctx_sp; -} - -size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386( - const ExecutionContext &exe_ctx) { - m_cursors.clear(); - - StackFrame *first_frame = exe_ctx.GetFramePtr(); - - Process *process = exe_ctx.GetProcessPtr(); - if (process == nullptr) - return 0; - - struct Frame_i386 { - uint32_t fp; - uint32_t pc; - }; - - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); - assert(reg_ctx); - - Cursor cursor; - cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS); - cursor.fp = reg_ctx->GetFP(0); - - Frame_i386 frame = {static_cast<uint32_t>(cursor.fp), - static_cast<uint32_t>(cursor.pc)}; - - m_cursors.push_back(cursor); - - const size_t k_frame_size = sizeof(frame); - Status error; - while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) { - // Read both the FP and PC (8 bytes) - if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) != - k_frame_size) - break; - if (frame.pc >= 0x1000) { - cursor.pc = frame.pc; - cursor.fp = frame.fp; - m_cursors.push_back(cursor); - } - } - if (!m_cursors.empty()) { - lldb::addr_t first_frame_pc = m_cursors.front().pc; - if (first_frame_pc != LLDB_INVALID_ADDRESS) { - const SymbolContextItem resolve_scope = - eSymbolContextModule | eSymbolContextCompUnit | - eSymbolContextFunction | eSymbolContextSymbol; - - SymbolContext first_frame_sc( - first_frame->GetSymbolContext(resolve_scope)); - const AddressRange *addr_range_ptr = nullptr; - AddressRange range; - if (first_frame_sc.function) - addr_range_ptr = &first_frame_sc.function->GetAddressRange(); - else if (first_frame_sc.symbol) { - range.GetBaseAddress() = first_frame_sc.symbol->GetAddress(); - range.SetByteSize(first_frame_sc.symbol->GetByteSize()); - addr_range_ptr = ⦥ - } - - if (addr_range_ptr) { - if (first_frame->GetFrameCodeAddress() == - addr_range_ptr->GetBaseAddress()) { - // We are at the first instruction, so we can recover the previous PC - // by dereferencing the SP - lldb::addr_t first_frame_sp = reg_ctx->GetSP(0); - // Read the real second frame return address into frame.pc - if (first_frame_sp && - process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc), - error) == sizeof(frame.pc)) { - cursor.fp = m_cursors.front().fp; - cursor.pc = frame.pc; // Set the new second frame PC - - // Insert the second frame - m_cursors.insert(m_cursors.begin() + 1, cursor); - - m_cursors.front().fp = first_frame_sp; - } - } - } - } - } - // uint32_t i=0; - // printf(" PC FP\n"); - // printf(" ------------------ ------------------ \n"); - // for (i=0; i<m_cursors.size(); ++i) - // { - // printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, - // m_cursors[i].pc, m_cursors[i].fp); - // } - return m_cursors.size(); -} - -size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64( - const ExecutionContext &exe_ctx) { - m_cursors.clear(); - - Process *process = exe_ctx.GetProcessPtr(); - if (process == nullptr) - return 0; - - StackFrame *first_frame = exe_ctx.GetFramePtr(); - - struct Frame_x86_64 { - uint64_t fp; - uint64_t pc; - }; - - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); - assert(reg_ctx); - - Cursor cursor; - cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS); - cursor.fp = reg_ctx->GetFP(0); - - Frame_x86_64 frame = {cursor.fp, cursor.pc}; - - m_cursors.push_back(cursor); - Status error; - const size_t k_frame_size = sizeof(frame); - while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) { - // Read both the FP and PC (16 bytes) - if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) != - k_frame_size) - break; - - if (frame.pc >= 0x1000) { - cursor.pc = frame.pc; - cursor.fp = frame.fp; - m_cursors.push_back(cursor); - } - } - if (!m_cursors.empty()) { - lldb::addr_t first_frame_pc = m_cursors.front().pc; - if (first_frame_pc != LLDB_INVALID_ADDRESS) { - const SymbolContextItem resolve_scope = - eSymbolContextModule | eSymbolContextCompUnit | - eSymbolContextFunction | eSymbolContextSymbol; - - SymbolContext first_frame_sc( - first_frame->GetSymbolContext(resolve_scope)); - const AddressRange *addr_range_ptr = nullptr; - AddressRange range; - if (first_frame_sc.function) - addr_range_ptr = &first_frame_sc.function->GetAddressRange(); - else if (first_frame_sc.symbol) { - range.GetBaseAddress() = first_frame_sc.symbol->GetAddress(); - range.SetByteSize(first_frame_sc.symbol->GetByteSize()); - addr_range_ptr = ⦥ - } - - if (addr_range_ptr) { - if (first_frame->GetFrameCodeAddress() == - addr_range_ptr->GetBaseAddress()) { - // We are at the first instruction, so we can recover the previous PC - // by dereferencing the SP - lldb::addr_t first_frame_sp = reg_ctx->GetSP(0); - // Read the real second frame return address into frame.pc - if (process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc), - error) == sizeof(frame.pc)) { - cursor.fp = m_cursors.front().fp; - cursor.pc = frame.pc; // Set the new second frame PC - - // Insert the second frame - m_cursors.insert(m_cursors.begin() + 1, cursor); - - m_cursors.front().fp = first_frame_sp; - } - } - } - } - } - return m_cursors.size(); -} diff --git a/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h deleted file mode 100644 index f0bde90a53be..000000000000 --- a/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h +++ /dev/null @@ -1,54 +0,0 @@ -//===-- UnwindMacOSXFrameBackchain.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_UnwindMacOSXFrameBackchain_h_ -#define lldb_UnwindMacOSXFrameBackchain_h_ - -#include <vector> - -#include "lldb/Target/Unwind.h" -#include "lldb/lldb-private.h" - -class UnwindMacOSXFrameBackchain : public lldb_private::Unwind { -public: - UnwindMacOSXFrameBackchain(lldb_private::Thread &thread); - - ~UnwindMacOSXFrameBackchain() override = default; - -protected: - void DoClear() override { m_cursors.clear(); } - - uint32_t DoGetFrameCount() override; - - bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, - lldb::addr_t &pc, - bool &behaves_like_zeroth_frame) override; - - lldb::RegisterContextSP - DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; - - friend class RegisterContextMacOSXFrameBackchain; - - struct Cursor { - lldb::addr_t pc; // Program counter - lldb::addr_t fp; // Frame pointer for us with backchain - }; - -private: - std::vector<Cursor> m_cursors; - - size_t GetStackFrameData_i386(const lldb_private::ExecutionContext &exe_ctx); - - size_t - GetStackFrameData_x86_64(const lldb_private::ExecutionContext &exe_ctx); - - // For UnwindMacOSXFrameBackchain only - DISALLOW_COPY_AND_ASSIGN(UnwindMacOSXFrameBackchain); -}; - -#endif // lldb_UnwindMacOSXFrameBackchain_h_ diff --git a/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h index 39cbf01ea9d2..8f0eed4f02c9 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_arm_register_enums_h -#define lldb_arm_register_enums_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM_REGISTER_ENUMS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM_REGISTER_ENUMS_H namespace lldb_private { // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) @@ -196,4 +196,4 @@ enum { }; } -#endif // #ifndef lldb_arm64_register_enums_h +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM_REGISTER_ENUMS_H diff --git a/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h index cc414dcde3cf..39d47b8801cc 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_arm64_register_enums_h -#define lldb_arm64_register_enums_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM64_REGISTER_ENUMS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM64_REGISTER_ENUMS_H namespace lldb_private { // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) @@ -261,4 +261,4 @@ enum { }; } -#endif // #ifndef lldb_arm64_register_enums_h +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM64_REGISTER_ENUMS_H diff --git a/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h index d97f77122426..e6a7efd00f67 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_mips_freebsd_register_enums_h -#define lldb_mips_freebsd_register_enums_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_FREEBSD_REGISTER_ENUMS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_FREEBSD_REGISTER_ENUMS_H namespace lldb_private { // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) @@ -62,4 +62,4 @@ enum { k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1 }; } -#endif // #ifndef lldb_mips_freebsd_register_enums_h +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_FREEBSD_REGISTER_ENUMS_H diff --git a/lldb/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h index 2f68b8022c9a..348af27d2809 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_mips_linux_register_enums_h -#define lldb_mips_linux_register_enums_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_LINUX_REGISTER_ENUMS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_LINUX_REGISTER_ENUMS_H namespace lldb_private { // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) @@ -357,4 +357,4 @@ enum { }; } -#endif // #ifndef lldb_mips_linux_register_enums_h +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_LINUX_REGISTER_ENUMS_H diff --git a/lldb/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h index 6edf7ee3864d..40a75c006d84 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_ppc64_register_enums_h -#define lldb_ppc64_register_enums_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64_REGISTER_ENUMS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64_REGISTER_ENUMS_H // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) @@ -133,4 +133,4 @@ enum { k_num_vmx_registers_ppc64 = k_last_vmx_ppc64 - k_first_vmx_ppc64 + 1, }; -#endif // #ifndef lldb_ppc64_register_enums_h +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64_REGISTER_ENUMS_H diff --git a/lldb/source/Plugins/Process/Utility/lldb-ppc64le-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-ppc64le-register-enums.h index 0c381a5f3918..a7b5bc5ad9e3 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-ppc64le-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-ppc64le-register-enums.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_ppc64le_register_enums_h -#define lldb_ppc64le_register_enums_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64LE_REGISTER_ENUMS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64LE_REGISTER_ENUMS_H // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) @@ -204,4 +204,4 @@ enum { k_num_vsx_registers_ppc64le = k_last_vsx_ppc64le - k_first_vsx_ppc64le + 1, }; -#endif // #ifndef lldb_ppc64le_register_enums_h +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64LE_REGISTER_ENUMS_H diff --git a/lldb/source/Plugins/Process/Utility/lldb-s390x-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-s390x-register-enums.h index bd6626108290..23c441e1c803 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-s390x-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-s390x-register-enums.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_s390x_register_enums_h -#define lldb_s390x_register_enums_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_S390X_REGISTER_ENUMS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_S390X_REGISTER_ENUMS_H namespace lldb_private { // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) @@ -87,4 +87,4 @@ enum { }; } -#endif // #ifndef lldb_s390x_register_enums_h +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_S390X_REGISTER_ENUMS_H diff --git a/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h index bfdd586d9ded..35f1a4075d09 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_x86_register_enums_h -#define lldb_x86_register_enums_h +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_X86_REGISTER_ENUMS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_X86_REGISTER_ENUMS_H namespace lldb_private { // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) @@ -113,7 +113,8 @@ enum { lldb_bndstatus_i386, k_last_mpxc_i386 = lldb_bndstatus_i386, - lldb_dr0_i386, + k_first_dbr_i386, + lldb_dr0_i386 = k_first_dbr_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386, @@ -121,6 +122,7 @@ enum { lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386, + k_last_dbr_i386 = lldb_dr7_i386, k_num_registers_i386, k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1, @@ -131,6 +133,7 @@ enum { k_num_fpr_registers_i386 + k_num_avx_registers_i386 + k_num_mpx_registers_i386, + k_num_dbr_registers_i386 = k_last_dbr_i386 - k_first_dbr_i386 + 1, }; // Internal codes for all x86_64 registers. @@ -318,4 +321,4 @@ enum { }; } -#endif // #ifndef lldb_x86_register_enums_h +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_X86_REGISTER_ENUMS_H diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index ab23589ae9a9..aa95e92607ad 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -1,4 +1,4 @@ -//===-- ProcessElfCore.cpp --------------------------------------*- C++ -*-===// +//===-- ProcessElfCore.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -35,6 +35,8 @@ using namespace lldb_private; namespace ELF = llvm::ELF; +LLDB_PLUGIN_DEFINE(ProcessElfCore) + ConstString ProcessElfCore::GetPluginNameStatic() { static ConstString g_name("elf-core"); return g_name; diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h index 829fe9ac7199..6f6309799f43 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -13,8 +13,8 @@ // space. //===----------------------------------------------------------------------===// -#ifndef liblldb_ProcessElfCore_h_ -#define liblldb_ProcessElfCore_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H #include <list> #include <vector> @@ -125,7 +125,8 @@ private: lldb::ModuleSP m_core_module_sp; lldb_private::FileSpec m_core_file; std::string m_dyld_plugin_name; - DISALLOW_COPY_AND_ASSIGN(ProcessElfCore); + ProcessElfCore(const ProcessElfCore &) = delete; + const ProcessElfCore &operator=(const ProcessElfCore &) = delete; // True if m_thread_contexts contains valid entries bool m_thread_data_valid = false; @@ -165,4 +166,4 @@ private: llvm::Error parseLinuxNotes(llvm::ArrayRef<lldb_private::CoreNote> notes); }; -#endif // liblldb_ProcessElfCore_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp index fa05c457fc61..b76f26a584c0 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXCore_arm.cpp ------------------------*- C++ -*-===// +//===-- RegisterContextPOSIXCore_arm.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -44,10 +44,12 @@ bool RegisterContextCorePOSIX_arm::WriteFPR() { bool RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { lldb::offset_t offset = reg_info->byte_offset; - uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); - if (offset == reg_info->byte_offset + reg_info->byte_size) { - value = v; - return true; + if (offset + reg_info->byte_size <= GetGPRSize()) { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) { + value = v; + return true; + } } return false; } diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h index adda43ebccbc..f9ec08ed35fc 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextCorePOSIX_arm_h_ -#define liblldb_RegisterContextCorePOSIX_arm_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H #include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" @@ -50,4 +50,4 @@ private: lldb_private::DataExtractor m_gpr; }; -#endif // liblldb_RegisterContextCorePOSIX_arm_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp index e477c438ba12..685567416983 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXCore_arm64.cpp ----------------------*- C++ -*-===// +//===-- RegisterContextPOSIXCore_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. @@ -17,13 +17,16 @@ using namespace lldb_private; RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( - Thread &thread, RegisterInfoInterface *register_info, + Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info, const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes) - : RegisterContextPOSIX_arm64(thread, 0, register_info) { + : RegisterContextPOSIX_arm64(thread, std::move(register_info)) { m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(), gpregset.GetByteSize()); m_gpr.SetData(m_gpr_buffer); m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + m_fpregset = getRegset( + notes, m_register_info_up->GetTargetArchitecture().GetTriple(), FPR_Desc); } RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() {} @@ -45,11 +48,26 @@ bool RegisterContextCorePOSIX_arm64::WriteFPR() { bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { lldb::offset_t offset = reg_info->byte_offset; - uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); - if (offset == reg_info->byte_offset + reg_info->byte_size) { - value = v; - return true; + if (offset + reg_info->byte_size <= GetGPRSize()) { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) { + value = v; + return true; + } } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg == LLDB_INVALID_REGNUM) + return false; + + offset -= GetGPRSize(); + if (IsFPR(reg) && offset + reg_info->byte_size <= GetFPUSize()) { + Status error; + value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset, + reg_info->byte_size, lldb::eByteOrderLittle, error); + return error.Success(); + } + return false; } diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h index de6d819c29ce..830e0ff91e4c 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextCorePOSIX_arm64_h_ -#define liblldb_RegisterContextCorePOSIX_arm64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" @@ -18,7 +18,7 @@ class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 { public: RegisterContextCorePOSIX_arm64( lldb_private::Thread &thread, - lldb_private::RegisterInfoInterface *register_info, + std::unique_ptr<RegisterInfoPOSIX_arm64> register_info, const lldb_private::DataExtractor &gpregset, llvm::ArrayRef<lldb_private::CoreNote> notes); @@ -48,6 +48,7 @@ protected: private: lldb::DataBufferSP m_gpr_buffer; lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpregset; }; -#endif // liblldb_RegisterContextCorePOSIX_arm64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp index 3601f3b3b216..b5b83d899a44 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXCore_mips64.cpp ---------------------*- C++ -*-===// +//===-- RegisterContextPOSIXCore_mips64.cpp -------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h index 999c9451573b..b42a76c082f0 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextCorePOSIX_mips64_h_ -#define liblldb_RegisterContextCorePOSIX_mips64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_MIPS64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_MIPS64_H #include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" @@ -52,4 +52,4 @@ private: lldb_private::DataExtractor m_fpr; }; -#endif // liblldb_RegisterContextCorePOSIX_mips64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_MIPS64_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp index 6984bf4ee9b8..e15cd47cd7da 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXCore_powerpc.cpp --------------------*- C++ -*-===// +//===-- RegisterContextPOSIXCore_powerpc.cpp ------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h index 7684c0b31837..cf50b6e0bf70 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextCorePOSIX_powerpc_h_ -#define liblldb_RegisterContextCorePOSIX_powerpc_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_POWERPC_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_POWERPC_H #include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" @@ -57,4 +57,4 @@ private: lldb_private::DataExtractor m_vec; }; -#endif // liblldb_RegisterContextCorePOSIX_powerpc_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_POWERPC_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp index 0eebf474f60e..d44fb399e18a 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXCore_ppc64le.cpp --------------------*- C++ -*-===// +//===-- RegisterContextPOSIXCore_ppc64le.cpp ------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h index 6e01d23dd656..8de77a7e25bf 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextCorePOSIX_ppc64le_h_ -#define liblldb_RegisterContextCorePOSIX_ppc64le_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_PPC64LE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_PPC64LE_H #include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" @@ -45,4 +45,4 @@ private: lldb_private::DataExtractor m_vsx; }; -#endif // liblldb_RegisterContextCorePOSIX_ppc64le_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_PPC64LE_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp index d84fc3e74395..c3aa92c9f86c 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXCore_s390x.cpp ----------------------*- C++ -*-===// +//===-- RegisterContextPOSIXCore_s390x.cpp --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h index 729617649c4f..4560f062e06f 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextCorePOSIX_s390x_h_ -#define liblldb_RegisterContextCorePOSIX_s390x_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_S390X_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_S390X_H #include "Plugins/Process/Utility/RegisterContextPOSIX_s390x.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" @@ -52,4 +52,4 @@ private: lldb_private::DataExtractor m_fpr; }; -#endif // liblldb_RegisterContextCorePOSIX_s390x_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_S390X_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp index 4454857e1799..6eaad9f381d6 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextPOSIXCore_x86_64.cpp ---------------------*- C++ -*-===// +//===-- RegisterContextPOSIXCore_x86_64.cpp -------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h index f41991c240d2..9adfbf7e6852 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextCorePOSIX_x86_64_h_ -#define liblldb_RegisterContextCorePOSIX_x86_64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_X86_64_H #include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" @@ -46,4 +46,4 @@ private: std::unique_ptr<uint8_t[]> m_fpregset; }; -#endif // liblldb_RegisterContextCorePOSIX_x86_64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_X86_64_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.cpp b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.cpp index c8829d612b31..0c21c0f50abb 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.cpp @@ -1,4 +1,4 @@ -//===-- RegisterUtilities.cpp -----------------------------------*- C++ -*-===// +//===-- RegisterUtilities.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h index 49ad425db445..4e08aa280817 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_REGISTERUTILITIES_H -#define LLDB_REGISTERUTILITIES_H +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERUTILITIES_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERUTILITIES_H #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "lldb/Utility/DataExtractor.h" @@ -118,4 +118,4 @@ constexpr RegsetDesc PPC_VSX_Desc[] = { } // namespace lldb_private -#endif // #ifndef LLDB_REGISTERUTILITIES_H +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERUTILITIES_H diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 508c8a3108a6..6b5acfa4bc1b 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -1,4 +1,4 @@ -//===-- ThreadElfCore.cpp --------------------------------------*- C++ -*-===// +//===-- ThreadElfCore.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -82,7 +82,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { case llvm::Triple::FreeBSD: { switch (arch.GetMachine()) { case llvm::Triple::aarch64: - reg_interface = new RegisterInfoPOSIX_arm64(arch); break; case llvm::Triple::arm: reg_interface = new RegisterInfoPOSIX_arm(arch); @@ -111,7 +110,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { case llvm::Triple::NetBSD: { switch (arch.GetMachine()) { case llvm::Triple::aarch64: - reg_interface = new RegisterInfoPOSIX_arm64(arch); break; case llvm::Triple::x86_64: reg_interface = new RegisterContextNetBSD_x86_64(arch); @@ -128,7 +126,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { reg_interface = new RegisterInfoPOSIX_arm(arch); break; case llvm::Triple::aarch64: - reg_interface = new RegisterInfoPOSIX_arm64(arch); break; case llvm::Triple::mipsel: case llvm::Triple::mips: @@ -159,7 +156,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { case llvm::Triple::OpenBSD: { switch (arch.GetMachine()) { case llvm::Triple::aarch64: - reg_interface = new RegisterInfoPOSIX_arm64(arch); break; case llvm::Triple::arm: reg_interface = new RegisterInfoPOSIX_arm(arch); @@ -180,7 +176,7 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { break; } - if (!reg_interface) { + if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64) { LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported", __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); assert(false && "Architecture or OS not supported"); @@ -189,7 +185,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { switch (arch.GetMachine()) { case llvm::Triple::aarch64: m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm64>( - *this, reg_interface, m_gpregset_data, m_notes); + *this, std::make_unique<RegisterInfoPOSIX_arm64>(arch), + m_gpregset_data, m_notes); break; case llvm::Triple::arm: m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>( @@ -229,9 +226,7 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { reg_ctx_sp = m_thread_reg_ctx_sp; } else { - Unwind *unwinder = GetUnwinder(); - if (unwinder != nullptr) - reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); + reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); } return reg_ctx_sp; } @@ -296,25 +291,25 @@ Status ELFLinuxPrStatus::Parse(const DataExtractor &data, pr_cursig = data.GetU16(&offset); offset += 2; // pad - pr_sigpend = data.GetPointer(&offset); - pr_sighold = data.GetPointer(&offset); + pr_sigpend = data.GetAddress(&offset); + pr_sighold = data.GetAddress(&offset); pr_pid = data.GetU32(&offset); pr_ppid = data.GetU32(&offset); pr_pgrp = data.GetU32(&offset); pr_sid = data.GetU32(&offset); - pr_utime.tv_sec = data.GetPointer(&offset); - pr_utime.tv_usec = data.GetPointer(&offset); + pr_utime.tv_sec = data.GetAddress(&offset); + pr_utime.tv_usec = data.GetAddress(&offset); - pr_stime.tv_sec = data.GetPointer(&offset); - pr_stime.tv_usec = data.GetPointer(&offset); + pr_stime.tv_sec = data.GetAddress(&offset); + pr_stime.tv_usec = data.GetAddress(&offset); - pr_cutime.tv_sec = data.GetPointer(&offset); - pr_cutime.tv_usec = data.GetPointer(&offset); + pr_cutime.tv_sec = data.GetAddress(&offset); + pr_cutime.tv_usec = data.GetAddress(&offset); - pr_cstime.tv_sec = data.GetPointer(&offset); - pr_cstime.tv_usec = data.GetPointer(&offset); + pr_cstime.tv_sec = data.GetAddress(&offset); + pr_cstime.tv_usec = data.GetAddress(&offset); return error; } @@ -367,7 +362,7 @@ Status ELFLinuxPrPsInfo::Parse(const DataExtractor &data, offset += 4; } - pr_flag = data.GetPointer(&offset); + pr_flag = data.GetAddress(&offset); if (arch.IsMIPS()) { // The pr_uid and pr_gid is always 32 bit irrespective of platforms diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index ddcf35013b34..8d973bb840d2 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ThreadElfCore_h_ -#define liblldb_ThreadElfCore_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_THREADELFCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_THREADELFCORE_H #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Target/Thread.h" @@ -173,4 +173,4 @@ protected: bool CalculateStopInfo() override; }; -#endif // liblldb_ThreadElfCore_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_THREADELFCORE_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp index 064bbde8442e..fdaa60e2df41 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteClientBase.cpp ---------------------------------*- C++ -*-===// +//===-- GDBRemoteClientBase.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -41,7 +41,7 @@ StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( { std::lock_guard<std::mutex> lock(m_mutex); - m_continue_packet = payload; + m_continue_packet = std::string(payload); m_should_stop = false; } ContinueLock cont_lock(*this); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h index ea294ffcef26..cd9f6ebd7642 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteClientBase_h_ -#define liblldb_GDBRemoteClientBase_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H #include "GDBRemoteCommunication.h" @@ -149,4 +149,4 @@ private: } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationClient_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 7cea013eea7f..bfacd41dc1a3 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteCommunication.cpp ------------------------------*- C++ -*-===// +//===-- GDBRemoteCommunication.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -50,7 +50,7 @@ #include <compression.h> #endif -#if LLVM_ENABLE_ZLIB +#if defined(HAVE_LIBZ) #include <zlib.h> #endif @@ -125,7 +125,7 @@ GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { packet.Write(payload.data(), payload.size()); packet.PutChar('#'); packet.PutHex8(CalculcateChecksum(payload)); - std::string packet_str = packet.GetString(); + std::string packet_str = std::string(packet.GetString()); return SendRawPacketNoLock(packet_str); } @@ -582,7 +582,7 @@ bool GDBRemoteCommunication::DecompressPacket() { } #endif -#if LLVM_ENABLE_ZLIB +#if defined(HAVE_LIBZ) if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr && m_compression_type == CompressionType::ZlibDeflate) { @@ -763,7 +763,7 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, if (m_bytes[0] == '$' && total_length > 4) { for (size_t i = 0; !binary && i < total_length; ++i) { unsigned char c = m_bytes[i]; - if (isprint(c) == 0 && isspace(c) == 0) { + if (!llvm::isPrint(c) && !llvm::isSpace(c)) { binary = true; } } @@ -810,31 +810,9 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, GDBRemotePacket::ePacketTypeRecv, total_length); // Copy the packet from m_bytes to packet_str expanding the run-length - // encoding in the process. Reserve enough byte for the most common case - // (no RLE used) - std ::string packet_str; - packet_str.reserve(m_bytes.length()); - for (std::string::const_iterator c = m_bytes.begin() + content_start; - c != m_bytes.begin() + content_end; ++c) { - if (*c == '*') { - // '*' indicates RLE. Next character will give us the repeat count - // and previous character is what is to be repeated. - char char_to_repeat = packet_str.back(); - // Number of time the previous character is repeated - int repeat_count = *++c + 3 - ' '; - // We have the char_to_repeat and repeat_count. Now push it in the - // packet. - for (int i = 0; i < repeat_count; ++i) - packet_str.push_back(char_to_repeat); - } else if (*c == 0x7d) { - // 0x7d is the escape character. The next character is to be XOR'd - // with 0x20. - char escapee = *++c ^ 0x20; - packet_str.push_back(escapee); - } else { - packet_str.push_back(*c); - } - } + // encoding in the process. + std ::string packet_str = + ExpandRLE(m_bytes.substr(content_start, content_end - content_start)); packet = StringExtractorGDBRemote(packet_str); if (m_bytes[0] == '$' || m_bytes[0] == '%') { @@ -891,7 +869,7 @@ Status GDBRemoteCommunication::StartListenThread(const char *hostname, else snprintf(listen_url, sizeof(listen_url), "listen://%i", port); m_listen_url = listen_url; - SetConnection(new ConnectionFileDescriptor()); + SetConnection(std::make_unique<ConnectionFileDescriptor>()); llvm::Expected<HostThread> listen_thread = ThreadLauncher::LaunchThread( listen_url, GDBRemoteCommunication::ListenThread, this); if (!listen_thread) @@ -1274,11 +1252,12 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client, return llvm::createStringError(llvm::inconvertibleErrorCode(), "Unable to connect: %s", status.AsCString()); - client.SetConnection(conn_up.release()); + client.SetConnection(std::move(conn_up)); if (llvm::Error error = accept_status.get().ToError()) return error; - server.SetConnection(new ConnectionFileDescriptor(accept_socket)); + server.SetConnection( + std::make_unique<ConnectionFileDescriptor>(accept_socket)); return llvm::Error::success(); } @@ -1382,3 +1361,30 @@ void llvm::format_provider<GDBRemoteCommunication::PacketResult>::format( break; } } + +std::string GDBRemoteCommunication::ExpandRLE(std::string packet) { + // Reserve enough byte for the most common case (no RLE used). + std::string decoded; + decoded.reserve(packet.size()); + for (std::string::const_iterator c = packet.begin(); c != packet.end(); ++c) { + if (*c == '*') { + // '*' indicates RLE. Next character will give us the repeat count and + // previous character is what is to be repeated. + char char_to_repeat = decoded.back(); + // Number of time the previous character is repeated. + int repeat_count = *++c + 3 - ' '; + // We have the char_to_repeat and repeat_count. Now push it in the + // packet. + for (int i = 0; i < repeat_count; ++i) + decoded.push_back(char_to_repeat); + } else if (*c == 0x7d) { + // 0x7d is the escape character. The next character is to be XOR'd with + // 0x20. + char escapee = *++c ^ 0x20; + decoded.push_back(escapee); + } else { + decoded.push_back(*c); + } + } + return decoded; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 0b670018bd69..b1e2075a64fe 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteCommunication_h_ -#define liblldb_GDBRemoteCommunication_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H #include "GDBRemoteCommunicationHistory.h" @@ -142,6 +142,9 @@ public: static llvm::Error ConnectLocally(GDBRemoteCommunication &client, GDBRemoteCommunication &server); + /// Expand GDB run-length encoding. + static std::string ExpandRLE(std::string); + protected: std::chrono::seconds m_packet_timeout; uint32_t m_echo_number; @@ -223,7 +226,9 @@ private: void *m_decompression_scratch = nullptr; #endif - DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunication); + GDBRemoteCommunication(const GDBRemoteCommunication &) = delete; + const GDBRemoteCommunication & + operator=(const GDBRemoteCommunication &) = delete; }; } // namespace process_gdb_remote @@ -239,4 +244,4 @@ struct format_provider< }; } // namespace llvm -#endif // liblldb_GDBRemoteCommunication_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index b2f1ee527e8b..c75d5e106cd0 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteCommunicationClient.cpp ------------------------*- C++ -*-===// +//===-- GDBRemoteCommunicationClient.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -45,6 +45,13 @@ using namespace lldb_private::process_gdb_remote; using namespace lldb_private; using namespace std::chrono; +llvm::raw_ostream &process_gdb_remote::operator<<(llvm::raw_ostream &os, + const QOffsets &offsets) { + return os << llvm::formatv( + "QOffsets({0}, [{1:@[x]}])", offsets.segments, + llvm::make_range(offsets.offsets.begin(), offsets.offsets.end())); +} + // GDBRemoteCommunicationClient constructor GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : GDBRemoteClientBase("gdb-remote.client", "gdb-remote.client.rx_packet"), @@ -573,7 +580,8 @@ StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { if (response.IsUnsupportedResponse()) { m_supports_jThreadsInfo = false; } else if (!response.Empty()) { - object_sp = StructuredData::ParseJSON(response.GetStringRef()); + object_sp = + StructuredData::ParseJSON(std::string(response.GetStringRef())); } } } @@ -685,7 +693,7 @@ GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses( if (result != PacketResult::Success) return result; - const std::string &this_string = this_response.GetStringRef(); + const std::string &this_string = std::string(this_response.GetStringRef()); // Check for m or l as first character; l seems to mean this is the last // chunk @@ -757,7 +765,7 @@ bool GDBRemoteCommunicationClient::GetLaunchSuccess(std::string &error_str) { return true; if (response.GetChar() == 'E') { // A string the describes what failed when launching... - error_str = response.GetStringRef().substr(1); + error_str = std::string(response.GetStringRef().substr(1)); } else { error_str.assign("unknown error occurred launching process"); } @@ -833,7 +841,7 @@ int GDBRemoteCommunicationClient::SendEnvironmentPacket( bool send_hex_encoding = false; for (const char *p = name_equal_value; *p != '\0' && !send_hex_encoding; ++p) { - if (isprint(*p)) { + if (llvm::isPrint(*p)) { switch (*p) { case '$': case '#': @@ -1000,7 +1008,7 @@ bool GDBRemoteCommunicationClient::GetGDBServerVersion() { while (response.GetNameColonValue(name, value)) { if (name.equals("name")) { success = true; - m_gdb_server_name = value; + m_gdb_server_name = std::string(value); } else if (name.equals("version")) { llvm::StringRef major, minor; std::tie(major, minor) = value.split('.'); @@ -1045,7 +1053,7 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression( } #endif -#if LLVM_ENABLE_ZLIB +#if defined(HAVE_LIBZ) if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { @@ -1123,6 +1131,20 @@ bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) { return true; } +static void ParseOSType(llvm::StringRef value, std::string &os_name, + std::string &environment) { + if (value.equals("iossimulator") || value.equals("tvossimulator") || + value.equals("watchossimulator")) { + environment = "simulator"; + os_name = value.drop_back(environment.size()).str(); + } else if (value.equals("maccatalyst")) { + os_name = "ios"; + environment = "macabi"; + } else { + os_name = value.str(); + } +} + bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS)); @@ -1158,7 +1180,7 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { if (!value.getAsInteger(0, sub)) ++num_keys_decoded; } else if (name.equals("arch")) { - arch_name = value; + arch_name = std::string(value); ++num_keys_decoded; } else if (name.equals("triple")) { StringExtractor extractor(value); @@ -1181,14 +1203,10 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { extractor.GetHexByteString(m_os_kernel); ++num_keys_decoded; } else if (name.equals("ostype")) { - if (value.equals("maccatalyst")) { - os_name = "ios"; - environment = "macabi"; - } else - os_name = value; + ParseOSType(value, os_name, environment); ++num_keys_decoded; } else if (name.equals("vendor")) { - vendor_name = value; + vendor_name = std::string(value); ++num_keys_decoded; } else if (name.equals("endian")) { byte_order = llvm::StringSwitch<lldb::ByteOrder>(value) @@ -1956,9 +1974,9 @@ bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( } else if (name.equals("cpusubtype")) { value.getAsInteger(0, sub); } else if (name.equals("vendor")) { - vendor = value; + vendor = std::string(value); } else if (name.equals("ostype")) { - os_type = value; + os_type = std::string(value); } } @@ -2045,14 +2063,10 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { extractor.GetHexByteString(triple); ++num_keys_decoded; } else if (name.equals("ostype")) { - if (value.equals("maccatalyst")) { - os_name = "ios"; - environment = "macabi"; - } else - os_name = value; + ParseOSType(value, os_name, environment); ++num_keys_decoded; } else if (name.equals("vendor")) { - vendor_name = value; + vendor_name = std::string(value); ++num_keys_decoded; } else if (name.equals("endian")) { byte_order = llvm::StringSwitch<lldb::ByteOrder>(value) @@ -2069,7 +2083,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { if (!value.getAsInteger(16, pid)) ++num_keys_decoded; } else if (name.equals("elf_abi")) { - elf_abi = value; + elf_abi = std::string(value); ++num_keys_decoded; } } @@ -2140,7 +2154,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { uint32_t GDBRemoteCommunicationClient::FindProcesses( const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { - process_infos.Clear(); + process_infos.clear(); if (m_supports_qfProcessInfo) { StreamString packet; @@ -2220,7 +2234,7 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( ProcessInstanceInfo process_info; if (!DecodeProcessInfoResponse(response, process_info)) break; - process_infos.Append(process_info); + process_infos.push_back(process_info); response = StringExtractorGDBRemote(); } while (SendPacketAndWaitForResponse("qsProcessInfo", response, false) == PacketResult::Success); @@ -2229,7 +2243,7 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( return 0; } } - return process_infos.GetSize(); + return process_infos.size(); } bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid, @@ -2536,7 +2550,7 @@ size_t GDBRemoteCommunicationClient::QueryGDBServer( return 0; StructuredData::ObjectSP data = - StructuredData::ParseJSON(response.GetStringRef()); + StructuredData::ParseJSON(std::string(response.GetStringRef())); if (!data) return 0; @@ -2557,7 +2571,7 @@ size_t GDBRemoteCommunicationClient::QueryGDBServer( std::string socket_name; if (StructuredData::ObjectSP socket_name_osp = element->GetValueForKey(llvm::StringRef("socket_name"))) - socket_name = socket_name_osp->GetStringValue(); + socket_name = std::string(socket_name_osp->GetStringValue()); if (port != 0 || !socket_name.empty()) connection_urls.emplace_back(port, socket_name); @@ -2783,12 +2797,10 @@ size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( thread_ids.push_back(1); } } else { -#if !defined(LLDB_CONFIGURATION_DEBUG) Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - LLDB_LOGF(log, "error: failed to get packet sequence mutex, not sending " - "packet 'qfThreadInfo'"); -#endif + LLDB_LOG(log, "error: failed to get packet sequence mutex, not sending " + "packet 'qfThreadInfo'"); sequence_mutex_unavailable = true; } return thread_ids.size(); @@ -3478,7 +3490,7 @@ GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid, return error; } else options.setTraceParams( - static_pointer_cast<StructuredData::Dictionary>( + std::static_pointer_cast<StructuredData::Dictionary>( custom_params_sp)); } } else { @@ -3530,6 +3542,46 @@ Status GDBRemoteCommunicationClient::SendGetTraceDataPacket( return error; } +llvm::Optional<QOffsets> GDBRemoteCommunicationClient::GetQOffsets() { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse( + "qOffsets", response, /*send_async=*/false) != PacketResult::Success) + return llvm::None; + if (!response.IsNormalResponse()) + return llvm::None; + + QOffsets result; + llvm::StringRef ref = response.GetStringRef(); + const auto &GetOffset = [&] { + addr_t offset; + if (ref.consumeInteger(16, offset)) + return false; + result.offsets.push_back(offset); + return true; + }; + + if (ref.consume_front("Text=")) { + result.segments = false; + if (!GetOffset()) + return llvm::None; + if (!ref.consume_front(";Data=") || !GetOffset()) + return llvm::None; + if (ref.empty()) + return result; + if (ref.consume_front(";Bss=") && GetOffset() && ref.empty()) + return result; + } else if (ref.consume_front("TextSeg=")) { + result.segments = true; + if (!GetOffset()) + return llvm::None; + if (ref.empty()) + return result; + if (ref.consume_front(";DataSeg=") && GetOffset() && ref.empty()) + return result; + } + return llvm::None; +} + bool GDBRemoteCommunicationClient::GetModuleInfo( const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec, ModuleSpec &module_spec) { @@ -3571,7 +3623,7 @@ bool GDBRemoteCommunicationClient::GetModuleInfo( StringExtractor extractor(value); std::string uuid; extractor.GetHexByteString(uuid); - module_spec.GetUUID().SetFromStringRef(uuid, uuid.size() / 2); + module_spec.GetUUID().SetFromStringRef(uuid); } else if (name == "triple") { StringExtractor extractor(value); std::string triple; @@ -3607,8 +3659,7 @@ ParseModuleSpec(StructuredData::Dictionary *dict) { if (!dict->GetValueForKeyAsString("uuid", string)) return llvm::None; - if (result.GetUUID().SetFromStringRef(string, string.size() / 2) != - string.size()) + if (!result.GetUUID().SetFromStringRef(string)) return llvm::None; if (!dict->GetValueForKeyAsInteger("file_offset", integer)) @@ -3667,7 +3718,7 @@ GDBRemoteCommunicationClient::GetModulesInfo( } StructuredData::ObjectSP response_object_sp = - StructuredData::ParseJSON(response.GetStringRef()); + StructuredData::ParseJSON(std::string(response.GetStringRef())); if (!response_object_sp) return llvm::None; @@ -3722,7 +3773,7 @@ bool GDBRemoteCommunicationClient::ReadExtFeature( return false; } - const std::string &str = chunk.GetStringRef(); + const std::string &str = std::string(chunk.GetStringRef()); if (str.length() == 0) { // should have some data in chunk err.SetErrorString("Empty response from $qXfer packet"); @@ -3936,7 +3987,7 @@ GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() { if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response, send_async) == PacketResult::Success) { m_supported_async_json_packets_sp = - StructuredData::ParseJSON(response.GetStringRef()); + StructuredData::ParseJSON(std::string(response.GetStringRef())); if (m_supported_async_json_packets_sp && !m_supported_async_json_packets_sp->GetAsArray()) { // We were returned something other than a JSON array. This is @@ -4002,7 +4053,7 @@ Status GDBRemoteCommunicationClient::ConfigureRemoteStructuredData( // Build command: Configure{type_name}: serialized config data. StreamGDBRemote stream; stream.PutCString("QConfigure"); - stream.PutCString(type_name.AsCString()); + stream.PutCString(type_name.GetStringRef()); stream.PutChar(':'); if (config_sp) { // Gather the plain-text version of the configuration data. diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 11fd40bce44f..8df08cbde735 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteCommunicationClient_h_ -#define liblldb_GDBRemoteCommunicationClient_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONCLIENT_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONCLIENT_H #include "GDBRemoteClientBase.h" @@ -20,6 +20,7 @@ #include "lldb/Host/File.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/StructuredData.h" #if defined(_WIN32) #include "lldb/Host/windows/PosixApi.h" @@ -31,6 +32,22 @@ namespace lldb_private { namespace process_gdb_remote { +/// The offsets used by the target when relocating the executable. Decoded from +/// qOffsets packet response. +struct QOffsets { + /// If true, the offsets field describes segments. Otherwise, it describes + /// sections. + bool segments; + + /// The individual offsets. Section offsets have two or three members. + /// Segment offsets have either one of two. + std::vector<uint64_t> offsets; +}; +inline bool operator==(const QOffsets &a, const QOffsets &b) { + return a.segments == b.segments && a.offsets == b.offsets; +} +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const QOffsets &offsets); + class GDBRemoteCommunicationClient : public GDBRemoteClientBase { public: GDBRemoteCommunicationClient(); @@ -425,6 +442,11 @@ public: bool GetSharedCacheInfoSupported(); + /// Use qOffsets to query the offset used when relocating the target + /// executable. If successful, the returned structure will contain at least + /// one value in the offsets field. + llvm::Optional<QOffsets> GetQOffsets(); + bool GetModuleInfo(const FileSpec &module_file_spec, const ArchSpec &arch_spec, ModuleSpec &module_spec); @@ -599,10 +621,12 @@ protected: LazyBool GetThreadPacketSupported(lldb::tid_t tid, llvm::StringRef packetStr); private: - DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient); + GDBRemoteCommunicationClient(const GDBRemoteCommunicationClient &) = delete; + const GDBRemoteCommunicationClient & + operator=(const GDBRemoteCommunicationClient &) = delete; }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationClient_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONCLIENT_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp index 9e5646985f87..3984a45c3da1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteCommunicationHistory.cpp -----------------------*- C++ -*-===// +//===-- GDBRemoteCommunicationHistory.cpp ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h index ee265ef86dff..e783e59c3455 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteCommunicationHistory_h_ -#define liblldb_GDBRemoteCommunicationHistory_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONHISTORY_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONHISTORY_H #include <string> #include <vector> @@ -83,4 +83,4 @@ private: } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationHistory_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONHISTORY_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp index 15c73e78bd44..920327e7d0ab 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteCommunicationReplayServer.cpp ------------------*- C++ -*-===// +//===-- GDBRemoteCommunicationReplayServer.cpp ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -131,22 +131,26 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( GDBRemotePacket entry = m_packet_history.back(); m_packet_history.pop_back(); + // Decode run-length encoding. + const std::string expanded_data = + GDBRemoteCommunication::ExpandRLE(entry.packet.data); + // We've handled the handshake implicitly before. Skip the packet and move // on. if (entry.packet.data == "+") continue; if (entry.type == GDBRemotePacket::ePacketTypeSend) { - if (unexpected(entry.packet.data, packet.GetStringRef())) { + if (unexpected(expanded_data, packet.GetStringRef())) { LLDB_LOG(log, "GDBRemoteCommunicationReplayServer expected packet: '{0}'", - entry.packet.data); + expanded_data); LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'", packet.GetStringRef()); #ifndef NDEBUG // This behaves like a regular assert, but prints the expected and // received packet before aborting. - printf("Reproducer expected packet: '%s'\n", entry.packet.data.c_str()); + printf("Reproducer expected packet: '%s'\n", expanded_data.c_str()); printf("Reproducer received packet: '%s'\n", packet.GetStringRef().data()); llvm::report_fatal_error("Encountered unexpected packet during replay"); @@ -155,7 +159,7 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( } // Ignore QEnvironment packets as they're handled earlier. - if (entry.packet.data.find("QEnvironment") == 1) { + if (expanded_data.find("QEnvironment") == 1) { assert(m_packet_history.back().type == GDBRemotePacket::ePacketTypeRecv); m_packet_history.pop_back(); @@ -283,3 +287,28 @@ thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) { return {}; } + +Status GDBRemoteCommunicationReplayServer::Connect( + process_gdb_remote::GDBRemoteCommunicationClient &client) { + repro::Loader *loader = repro::Reproducer::Instance().GetLoader(); + if (!loader) + return Status("No loader provided."); + + static std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>> + multi_loader = repro::MultiLoader<repro::GDBRemoteProvider>::Create( + repro::Reproducer::Instance().GetLoader()); + if (!multi_loader) + return Status("No gdb remote provider found."); + + llvm::Optional<std::string> history_file = multi_loader->GetNextFile(); + if (!history_file) + return Status("No gdb remote packet log found."); + + if (auto error = LoadReplayHistory(FileSpec(*history_file))) + return Status("Unable to load replay history"); + + if (auto error = GDBRemoteCommunication::ConnectLocally(client, *this)) + return Status("Unable to connect to replay server"); + + return {}; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h index 0b5e910f7c6a..c13e5ee0bf92 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h @@ -6,11 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteCommunicationReplayServer_h_ -#define liblldb_GDBRemoteCommunicationReplayServer_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H // Other libraries and framework includes #include "GDBRemoteCommunication.h" +#include "GDBRemoteCommunicationClient.h" #include "GDBRemoteCommunicationHistory.h" // Project includes @@ -51,6 +52,8 @@ public: bool StartAsyncThread(); void StopAsyncThread(); + Status Connect(process_gdb_remote::GDBRemoteCommunicationClient &client); + protected: enum { eBroadcastBitAsyncContinue = (1 << 0), @@ -73,10 +76,13 @@ protected: bool m_skip_acks; private: - DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationReplayServer); + GDBRemoteCommunicationReplayServer( + const GDBRemoteCommunicationReplayServer &) = delete; + const GDBRemoteCommunicationReplayServer & + operator=(const GDBRemoteCommunicationReplayServer &) = delete; }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationReplayServer_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index ac6ecffcf854..b78f0916b9b9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteCommunicationServer.cpp ------------------------*- C++ -*-===// +//===-- GDBRemoteCommunicationServer.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 86f0abf45e06..a7c2ea47e3ba 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteCommunicationServer_h_ -#define liblldb_GDBRemoteCommunicationServer_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVER_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVER_H #include <functional> #include <map> @@ -74,7 +74,9 @@ protected: PacketResult SendOKResponse(); private: - DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServer); + GDBRemoteCommunicationServer(const GDBRemoteCommunicationServer &) = delete; + const GDBRemoteCommunicationServer & + operator=(const GDBRemoteCommunicationServer &) = delete; }; class PacketUnimplementedError @@ -92,4 +94,4 @@ public: } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServer_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVER_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 4b5fc0774a6d..08d489851799 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteCommunicationServerCommon.cpp ------------------*- C++ -*-===// +//===-- GDBRemoteCommunicationServerCommon.cpp ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -334,7 +334,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; - m_proc_infos.Clear(); + m_proc_infos.clear(); ProcessInstanceInfoMatch match_info; packet.SetFilePos(::strlen("qfProcessInfo")); @@ -416,10 +416,9 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo( StringExtractorGDBRemote &packet) { - if (m_proc_infos_index < m_proc_infos.GetSize()) { + if (m_proc_infos_index < m_proc_infos.size()) { StreamString response; - CreateProcessInfoResponse( - m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); + CreateProcessInfoResponse(m_proc_infos[m_proc_infos_index], response); ++m_proc_infos_index; return SendPacketNoLock(response.GetString()); } @@ -843,6 +842,7 @@ GDBRemoteCommunicationServerCommon::Handle_qSupported( response.PutCString(";QThreadSuffixSupported+"); response.PutCString(";QListThreadsInStopReply+"); response.PutCString(";qEcho+"); + response.PutCString(";qXfer:features:read+"); #if defined(__linux__) || defined(__NetBSD__) response.PutCString(";QPassSignals+"); response.PutCString(";qXfer:auxv:read+"); @@ -1228,7 +1228,7 @@ void GDBRemoteCommunicationServerCommon:: if (cpu_subtype != 0) response.Printf("cpusubtype:%" PRIx32 ";", cpu_subtype); - const std::string vendor = proc_triple.getVendorName(); + const std::string vendor = proc_triple.getVendorName().str(); if (!vendor.empty()) response.Printf("vendor:%s;", vendor.c_str()); #else @@ -1237,7 +1237,7 @@ void GDBRemoteCommunicationServerCommon:: response.PutStringAsRawHex8(proc_triple.getTriple()); response.PutChar(';'); #endif - std::string ostype = proc_triple.getOSName(); + std::string ostype = std::string(proc_triple.getOSName()); // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. if (proc_triple.getVendor() == llvm::Triple::Apple) { switch (proc_triple.getArch()) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h index 525546312470..0f933c09cbd4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteCommunicationServerCommon_h_ -#define liblldb_GDBRemoteCommunicationServerCommon_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERCOMMON_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERCOMMON_H #include <string> @@ -152,4 +152,4 @@ private: } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServerCommon_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERCOMMON_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index f33f0ee66304..ae2f4bd041c9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteCommunicationServerLLGS.cpp --------------------*- C++ -*-===// +//===-- GDBRemoteCommunicationServerLLGS.cpp ------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -377,6 +377,99 @@ static void AppendHexValue(StreamString &response, const uint8_t *buf, } } +static llvm::StringRef GetEncodingNameOrEmpty(const RegisterInfo ®_info) { + switch (reg_info.encoding) { + case eEncodingUint: + return "uint"; + case eEncodingSint: + return "sint"; + case eEncodingIEEE754: + return "ieee754"; + case eEncodingVector: + return "vector"; + default: + return ""; + } +} + +static llvm::StringRef GetFormatNameOrEmpty(const RegisterInfo ®_info) { + switch (reg_info.format) { + case eFormatBinary: + return "binary"; + case eFormatDecimal: + return "decimal"; + case eFormatHex: + return "hex"; + case eFormatFloat: + return "float"; + case eFormatVectorOfSInt8: + return "vector-sint8"; + case eFormatVectorOfUInt8: + return "vector-uint8"; + case eFormatVectorOfSInt16: + return "vector-sint16"; + case eFormatVectorOfUInt16: + return "vector-uint16"; + case eFormatVectorOfSInt32: + return "vector-sint32"; + case eFormatVectorOfUInt32: + return "vector-uint32"; + case eFormatVectorOfFloat32: + return "vector-float32"; + case eFormatVectorOfUInt64: + return "vector-uint64"; + case eFormatVectorOfUInt128: + return "vector-uint128"; + default: + return ""; + }; +} + +static llvm::StringRef GetKindGenericOrEmpty(const RegisterInfo ®_info) { + switch (reg_info.kinds[RegisterKind::eRegisterKindGeneric]) { + case LLDB_REGNUM_GENERIC_PC: + return "pc"; + case LLDB_REGNUM_GENERIC_SP: + return "sp"; + case LLDB_REGNUM_GENERIC_FP: + return "fp"; + case LLDB_REGNUM_GENERIC_RA: + return "ra"; + case LLDB_REGNUM_GENERIC_FLAGS: + return "flags"; + case LLDB_REGNUM_GENERIC_ARG1: + return "arg1"; + case LLDB_REGNUM_GENERIC_ARG2: + return "arg2"; + case LLDB_REGNUM_GENERIC_ARG3: + return "arg3"; + case LLDB_REGNUM_GENERIC_ARG4: + return "arg4"; + case LLDB_REGNUM_GENERIC_ARG5: + return "arg5"; + case LLDB_REGNUM_GENERIC_ARG6: + return "arg6"; + case LLDB_REGNUM_GENERIC_ARG7: + return "arg7"; + case LLDB_REGNUM_GENERIC_ARG8: + return "arg8"; + default: + return ""; + } +} + +static void CollectRegNums(const uint32_t *reg_num, StreamString &response, + bool usehex) { + for (int i = 0; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { + if (i > 0) + response.PutChar(','); + if (usehex) + response.Printf("%" PRIx32, *reg_num); + else + response.Printf("%" PRIu32, *reg_num); + } +} + static void WriteRegisterValueInHexFixedWidth( StreamString &response, NativeRegisterContext ®_ctx, const RegisterInfo ®_info, const RegisterValue *reg_value_p, @@ -922,9 +1015,9 @@ void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { } Status GDBRemoteCommunicationServerLLGS::InitializeConnection( - std::unique_ptr<Connection> &&connection) { + std::unique_ptr<Connection> connection) { IOObjectSP read_object_sp = connection->GetReadObject(); - GDBRemoteCommunicationServer::SetConnection(connection.release()); + GDBRemoteCommunicationServer::SetConnection(std::move(connection)); Status error; m_network_handle_up = m_mainloop.RegisterReadObject( @@ -960,7 +1053,7 @@ Status GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor(int fd) { } m_stdio_communication.SetCloseOnEOF(false); - m_stdio_communication.SetConnection(conn_up.release()); + m_stdio_communication.SetConnection(std::move(conn_up)); if (!m_stdio_communication.IsConnected()) { error.SetErrorString( "failed to set connection for inferior I/O communication"); @@ -1072,7 +1165,7 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStart( return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet "); options.setTraceParams( - static_pointer_cast<StructuredData::Dictionary>(custom_params_sp)); + std::static_pointer_cast<StructuredData::Dictionary>(custom_params_sp)); if (buffersize == std::numeric_limits<uint64_t>::max() || type != lldb::TraceType::eTraceTypeProcessorTrace) { @@ -1699,74 +1792,18 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset); - switch (reg_info->encoding) { - case eEncodingUint: - response.PutCString("encoding:uint;"); - break; - case eEncodingSint: - response.PutCString("encoding:sint;"); - break; - case eEncodingIEEE754: - response.PutCString("encoding:ieee754;"); - break; - case eEncodingVector: - response.PutCString("encoding:vector;"); - break; - default: - break; - } + llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info); + if (!encoding.empty()) + response << "encoding:" << encoding << ';'; - switch (reg_info->format) { - case eFormatBinary: - response.PutCString("format:binary;"); - break; - case eFormatDecimal: - response.PutCString("format:decimal;"); - break; - case eFormatHex: - response.PutCString("format:hex;"); - break; - case eFormatFloat: - response.PutCString("format:float;"); - break; - case eFormatVectorOfSInt8: - response.PutCString("format:vector-sint8;"); - break; - case eFormatVectorOfUInt8: - response.PutCString("format:vector-uint8;"); - break; - case eFormatVectorOfSInt16: - response.PutCString("format:vector-sint16;"); - break; - case eFormatVectorOfUInt16: - response.PutCString("format:vector-uint16;"); - break; - case eFormatVectorOfSInt32: - response.PutCString("format:vector-sint32;"); - break; - case eFormatVectorOfUInt32: - response.PutCString("format:vector-uint32;"); - break; - case eFormatVectorOfFloat32: - response.PutCString("format:vector-float32;"); - break; - case eFormatVectorOfUInt64: - response.PutCString("format:vector-uint64;"); - break; - case eFormatVectorOfUInt128: - response.PutCString("format:vector-uint128;"); - break; - default: - break; - }; + llvm::StringRef format = GetFormatNameOrEmpty(*reg_info); + if (!format.empty()) + response << "format:" << format << ';'; const char *const register_set_name = reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index); - if (register_set_name) { - response.PutCString("set:"); - response.PutCString(register_set_name); - response.PutChar(';'); - } + if (register_set_name) + response << "set:" << register_set_name << ';'; if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) @@ -1777,71 +1814,19 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( response.Printf("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]); - switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) { - case LLDB_REGNUM_GENERIC_PC: - response.PutCString("generic:pc;"); - break; - case LLDB_REGNUM_GENERIC_SP: - response.PutCString("generic:sp;"); - break; - case LLDB_REGNUM_GENERIC_FP: - response.PutCString("generic:fp;"); - break; - case LLDB_REGNUM_GENERIC_RA: - response.PutCString("generic:ra;"); - break; - case LLDB_REGNUM_GENERIC_FLAGS: - response.PutCString("generic:flags;"); - break; - case LLDB_REGNUM_GENERIC_ARG1: - response.PutCString("generic:arg1;"); - break; - case LLDB_REGNUM_GENERIC_ARG2: - response.PutCString("generic:arg2;"); - break; - case LLDB_REGNUM_GENERIC_ARG3: - response.PutCString("generic:arg3;"); - break; - case LLDB_REGNUM_GENERIC_ARG4: - response.PutCString("generic:arg4;"); - break; - case LLDB_REGNUM_GENERIC_ARG5: - response.PutCString("generic:arg5;"); - break; - case LLDB_REGNUM_GENERIC_ARG6: - response.PutCString("generic:arg6;"); - break; - case LLDB_REGNUM_GENERIC_ARG7: - response.PutCString("generic:arg7;"); - break; - case LLDB_REGNUM_GENERIC_ARG8: - response.PutCString("generic:arg8;"); - break; - default: - break; - } + llvm::StringRef kind_generic = GetKindGenericOrEmpty(*reg_info); + if (!kind_generic.empty()) + response << "generic:" << kind_generic << ';'; if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { response.PutCString("container-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->value_regs; - *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { - if (i > 0) - response.PutChar(','); - response.Printf("%" PRIx32, *reg_num); - } + CollectRegNums(reg_info->value_regs, response, true); response.PutChar(';'); } if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) { response.PutCString("invalidate-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->invalidate_regs; - *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { - if (i > 0) - response.PutChar(','); - response.Printf("%" PRIx32, *reg_num); - } + CollectRegNums(reg_info->invalidate_regs, response, true); response.PutChar(';'); } @@ -2055,7 +2040,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { packet, "P packet missing '=' char after register number"); // Parse out the value. - uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register + uint8_t reg_bytes[RegisterValue::kMaxRegisterByteSize]; size_t reg_size = packet.GetHexBytesAvail(reg_bytes); // Get the thread to use. @@ -2510,7 +2495,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( ConstString name = region_info.GetName(); if (name) { response.PutCString("name:"); - response.PutStringAsRawHex8(name.AsCString()); + response.PutStringAsRawHex8(name.GetStringRef()); response.PutChar(';'); } } @@ -2751,16 +2736,118 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { } llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +GDBRemoteCommunicationServerLLGS::BuildTargetXml() { + // Ensure we have a thread. + NativeThreadProtocol *thread = m_debugged_process_up->GetThreadAtIndex(0); + if (!thread) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No thread available"); + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + // Get the register context for the first thread. + NativeRegisterContext ®_context = thread->GetRegisterContext(); + + StreamString response; + + response.Printf("<?xml version=\"1.0\"?>"); + response.Printf("<target version=\"1.0\">"); + + response.Printf("<architecture>%s</architecture>", + m_debugged_process_up->GetArchitecture() + .GetTriple() + .getArchName() + .str() + .c_str()); + + response.Printf("<feature>"); + + const int registers_count = reg_context.GetUserRegisterCount(); + for (int reg_index = 0; reg_index < registers_count; reg_index++) { + const RegisterInfo *reg_info = + reg_context.GetRegisterInfoAtIndex(reg_index); + + if (!reg_info) { + LLDB_LOGF(log, + "%s failed to get register info for register index %" PRIu32, + "target.xml", reg_index); + continue; + } + + response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" offset=\"%" PRIu32 + "\" regnum=\"%d\" ", + reg_info->name, reg_info->byte_size * 8, + reg_info->byte_offset, reg_index); + + if (reg_info->alt_name && reg_info->alt_name[0]) + response.Printf("altname=\"%s\" ", reg_info->alt_name); + + llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info); + if (!encoding.empty()) + response << "encoding=\"" << encoding << "\" "; + + llvm::StringRef format = GetFormatNameOrEmpty(*reg_info); + if (!format.empty()) + response << "format=\"" << format << "\" "; + + const char *const register_set_name = + reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index); + if (register_set_name) + response << "group=\"" << register_set_name << "\" "; + + if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != + LLDB_INVALID_REGNUM) + response.Printf("ehframe_regnum=\"%" PRIu32 "\" ", + reg_info->kinds[RegisterKind::eRegisterKindEHFrame]); + + if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != + LLDB_INVALID_REGNUM) + response.Printf("dwarf_regnum=\"%" PRIu32 "\" ", + reg_info->kinds[RegisterKind::eRegisterKindDWARF]); + + llvm::StringRef kind_generic = GetKindGenericOrEmpty(*reg_info); + if (!kind_generic.empty()) + response << "generic=\"" << kind_generic << "\" "; + + if (reg_info->value_regs && + reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { + response.PutCString("value_regnums=\""); + CollectRegNums(reg_info->value_regs, response, false); + response.Printf("\" "); + } + + if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) { + response.PutCString("invalidate_regnums=\""); + CollectRegNums(reg_info->invalidate_regs, response, false); + response.Printf("\" "); + } + + if (reg_info->dynamic_size_dwarf_expr_bytes) { + const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; + response.PutCString("dynamic_size_dwarf_expr_bytes=\""); + for (uint32_t i = 0; i < dwarf_opcode_len; ++i) + response.PutHex8(reg_info->dynamic_size_dwarf_expr_bytes[i]); + response.Printf("\" "); + } + + response.Printf("/>"); + } + + response.Printf("</feature>"); + response.Printf("</target>"); + return MemoryBuffer::getMemBufferCopy(response.GetString(), "target.xml"); +} + +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, llvm::StringRef annex) { - if (object == "auxv") { - // Make sure we have a valid process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "No process available"); - } + // Make sure we have a valid process. + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No process available"); + } + if (object == "auxv") { // Grab the auxv data. auto buffer_or_error = m_debugged_process_up->GetAuxvData(); if (!buffer_or_error) @@ -2786,6 +2873,9 @@ GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, return MemoryBuffer::getMemBufferCopy(response.GetString(), __FUNCTION__); } + if (object == "features" && annex == "target.xml") + return BuildTargetXml(); + return llvm::make_error<PacketUnimplementedError>( "Xfer object not supported"); } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 088ba92ad11a..3ce285910c25 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteCommunicationServerLLGS_h_ -#define liblldb_GDBRemoteCommunicationServerLLGS_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERLLGS_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERLLGS_H #include <mutex> #include <unordered_map> @@ -67,7 +67,7 @@ public: void DidExec(NativeProcessProtocol *process) override; - Status InitializeConnection(std::unique_ptr<Connection> &&connection); + Status InitializeConnection(std::unique_ptr<Connection> connection); protected: MainLoop &m_mainloop; @@ -199,6 +199,8 @@ protected: static std::string XMLEncodeAttributeValue(llvm::StringRef value); private: + llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> BuildTargetXml(); + void HandleInferiorState_Exited(NativeProcessProtocol *process); void HandleInferiorState_Stopped(NativeProcessProtocol *process); @@ -222,10 +224,13 @@ private: void StopSTDIOForwarding(); // For GDBRemoteCommunicationServerLLGS only - DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServerLLGS); + GDBRemoteCommunicationServerLLGS(const GDBRemoteCommunicationServerLLGS &) = + delete; + const GDBRemoteCommunicationServerLLGS & + operator=(const GDBRemoteCommunicationServerLLGS &) = delete; }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServerLLGS_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERLLGS_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index 25cebbba8f7b..d14b79a03d17 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteCommunicationServerPlatform.cpp ----------------*- C++ -*-===// +//===-- GDBRemoteCommunicationServerPlatform.cpp --------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -173,7 +173,7 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( uint16_t port = UINT16_MAX; while (packet.GetNameColonValue(name, value)) { if (name.equals("host")) - hostname = value; + hostname = std::string(value); else if (name.equals("port")) value.getAsInteger(0, port); } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index eacc99a012db..a8cacea78835 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_GDBRemoteCommunicationServerPlatform_h_ -#define liblldb_GDBRemoteCommunicationServerPlatform_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H #include <map> #include <mutex> @@ -100,10 +100,13 @@ private: static FileSpec GetDomainSocketPath(const char *prefix); - DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServerPlatform); + GDBRemoteCommunicationServerPlatform( + const GDBRemoteCommunicationServerPlatform &) = delete; + const GDBRemoteCommunicationServerPlatform & + operator=(const GDBRemoteCommunicationServerPlatform &) = delete; }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServerPlatform_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index ec1a54afd727..1f31b45d0fa9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -1,4 +1,4 @@ -//===-- GDBRemoteRegisterContext.cpp ----------------------------*- C++ -*-===// +//===-- GDBRemoteRegisterContext.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index b42c87b5991b..015862587103 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_GDBRemoteRegisterContext_h_ -#define lldb_GDBRemoteRegisterContext_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERCONTEXT_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERCONTEXT_H #include <vector> @@ -88,9 +88,7 @@ protected: void SetAllRegisterValid(bool b); bool GetRegisterIsValid(uint32_t reg) const { -#if defined(LLDB_CONFIGURATION_DEBUG) assert(reg < m_reg_valid.size()); -#endif if (reg < m_reg_valid.size()) return m_reg_valid[reg]; return false; @@ -103,9 +101,7 @@ protected: } void SetRegisterIsValid(uint32_t reg, bool valid) { -#if defined(LLDB_CONFIGURATION_DEBUG) assert(reg < m_reg_valid.size()); -#endif if (reg < m_reg_valid.size()) m_reg_valid[reg] = valid; } @@ -124,10 +120,12 @@ private: bool SetPrimordialRegister(const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm); - DISALLOW_COPY_AND_ASSIGN(GDBRemoteRegisterContext); + GDBRemoteRegisterContext(const GDBRemoteRegisterContext &) = delete; + const GDBRemoteRegisterContext & + operator=(const GDBRemoteRegisterContext &) = delete; }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // lldb_GDBRemoteRegisterContext_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERCONTEXT_H diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index a49db5d9a934..1fed8e064267 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1,4 +1,4 @@ -//===-- ProcessGDBRemote.cpp ------------------------------------*- C++ -*-===// +//===-- ProcessGDBRemote.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -17,6 +17,9 @@ #include <unistd.h> #endif #include <sys/stat.h> +#if defined(__APPLE__) +#include <sys/sysctl.h> +#endif #include <sys/types.h> #include <time.h> @@ -90,6 +93,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; +LLDB_PLUGIN_DEFINE(ProcessGDBRemote) + namespace lldb { // Provide a function that can easily dump the packet history if we know a // ProcessGDBRemote * value (which we can get from logs or from debugging). We @@ -184,21 +189,6 @@ static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { #define HIGH_PORT (49151u) #endif -#if defined(__APPLE__) && \ - (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) -static bool rand_initialized = false; - -static inline uint16_t get_random_port() { - if (!rand_initialized) { - time_t seed = time(NULL); - - rand_initialized = true; - srand(seed); - } - return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; -} -#endif - ConstString ProcessGDBRemote::GetPluginNameStatic() { static ConstString g_name("gdb-remote"); return g_name; @@ -359,7 +349,8 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition( StructuredData::ObjectSP triple_value = host_info_dict->GetValueForKey("triple"); if (auto triple_string_value = triple_value->GetAsString()) { - std::string triple_string = triple_string_value->GetValue(); + std::string triple_string = + std::string(triple_string_value->GetValue()); ArchSpec host_arch(triple_string.c_str()); if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture())) { GetTarget().SetArchitecture(host_arch); @@ -638,15 +629,17 @@ Status ProcessGDBRemote::WillAttachToProcessWithName(const char *process_name, return WillLaunchOrAttach(); } -Status ProcessGDBRemote::DoConnectRemote(Stream *strm, - llvm::StringRef remote_url) { +Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); Status error(WillLaunchOrAttach()); if (error.Fail()) return error; - error = ConnectToDebugserver(remote_url); + if (repro::Reproducer::Instance().IsReplaying()) + error = ConnectToReplayServer(); + else + error = ConnectToDebugserver(remote_url); if (error.Fail()) return error; @@ -824,22 +817,23 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, // since 'O' packets can really slow down debugging if the inferior // does a lot of output. if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) && - pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, nullptr, 0)) { - FileSpec slave_name{pty.GetSlaveName(nullptr, 0)}; + pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY, nullptr, 0)) { + FileSpec secondary_name{pty.GetSecondaryName(nullptr, 0)}; if (!stdin_file_spec) - stdin_file_spec = slave_name; + stdin_file_spec = secondary_name; if (!stdout_file_spec) - stdout_file_spec = slave_name; + stdout_file_spec = secondary_name; if (!stderr_file_spec) - stderr_file_spec = slave_name; + stderr_file_spec = secondary_name; } LLDB_LOGF( log, "ProcessGDBRemote::%s adjusted STDIO paths for local platform " - "(IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s", + "(IsHost() is true) using secondary: stdin=%s, stdout=%s, " + "stderr=%s", __FUNCTION__, stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", @@ -924,8 +918,8 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, SetPrivateState(SetThreadStopInfo(response)); if (!disable_stdio) { - if (pty.GetMasterFileDescriptor() != PseudoTerminal::invalid_fd) - SetSTDIOFileDescriptor(pty.ReleaseMasterFileDescriptor()); + if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd) + SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor()); } } } else { @@ -957,7 +951,7 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { uint32_t retry_count = 0; while (!m_gdb_comm.IsConnected()) { if (conn_up->Connect(connect_url, &error) == eConnectionStatusSuccess) { - m_gdb_comm.SetConnection(conn_up.release()); + m_gdb_comm.SetConnection(std::move(conn_up)); break; } else if (error.WasInterrupted()) { // If we were interrupted, don't keep retrying. @@ -1023,122 +1017,113 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - LLDB_LOGF(log, "ProcessGDBRemote::%s()", __FUNCTION__); - if (GetID() != LLDB_INVALID_PROCESS_ID) { - BuildDynamicRegisterInfo(false); + BuildDynamicRegisterInfo(false); - // See if the GDB server supports the qHostInfo information + // See if the GDB server supports qHostInfo or qProcessInfo packets. Prefer + // qProcessInfo as it will be more specific to our process. - // See if the GDB server supports the qProcessInfo packet, if so prefer - // that over the Host information as it will be more specific to our - // process. + const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); + if (remote_process_arch.IsValid()) { + process_arch = remote_process_arch; + LLDB_LOG(log, "gdb-remote had process architecture, using {0} {1}", + process_arch.GetArchitectureName(), + process_arch.GetTriple().getTriple()); + } else { + process_arch = m_gdb_comm.GetHostArchitecture(); + LLDB_LOG(log, + "gdb-remote did not have process architecture, using gdb-remote " + "host architecture {0} {1}", + process_arch.GetArchitectureName(), + process_arch.GetTriple().getTriple()); + } - const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); - if (remote_process_arch.IsValid()) { - process_arch = remote_process_arch; - LLDB_LOGF(log, - "ProcessGDBRemote::%s gdb-remote had process architecture, " - "using %s %s", - __FUNCTION__, - process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", - process_arch.GetTriple().getTriple().c_str() - ? process_arch.GetTriple().getTriple().c_str() - : "<null>"); - } else { - process_arch = m_gdb_comm.GetHostArchitecture(); - LLDB_LOGF(log, - "ProcessGDBRemote::%s gdb-remote did not have process " - "architecture, using gdb-remote host architecture %s %s", - __FUNCTION__, - process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", - process_arch.GetTriple().getTriple().c_str() - ? process_arch.GetTriple().getTriple().c_str() - : "<null>"); - } + if (process_arch.IsValid()) { + const ArchSpec &target_arch = GetTarget().GetArchitecture(); + if (target_arch.IsValid()) { + LLDB_LOG(log, "analyzing target arch, currently {0} {1}", + target_arch.GetArchitectureName(), + target_arch.GetTriple().getTriple()); + + // If the remote host is ARM and we have apple as the vendor, then + // ARM executables and shared libraries can have mixed ARM + // architectures. + // You can have an armv6 executable, and if the host is armv7, then the + // system will load the best possible architecture for all shared + // libraries it has, so we really need to take the remote host + // architecture as our defacto architecture in this case. + + if ((process_arch.GetMachine() == llvm::Triple::arm || + process_arch.GetMachine() == llvm::Triple::thumb) && + process_arch.GetTriple().getVendor() == llvm::Triple::Apple) { + GetTarget().SetArchitecture(process_arch); + LLDB_LOG(log, + "remote process is ARM/Apple, " + "setting target arch to {0} {1}", + process_arch.GetArchitectureName(), + process_arch.GetTriple().getTriple()); + } else { + // Fill in what is missing in the triple + const llvm::Triple &remote_triple = process_arch.GetTriple(); + llvm::Triple new_target_triple = target_arch.GetTriple(); + if (new_target_triple.getVendorName().size() == 0) { + new_target_triple.setVendor(remote_triple.getVendor()); - if (process_arch.IsValid()) { - const ArchSpec &target_arch = GetTarget().GetArchitecture(); - if (target_arch.IsValid()) { - LLDB_LOGF(log, - "ProcessGDBRemote::%s analyzing target arch, currently %s %s", - __FUNCTION__, - target_arch.GetArchitectureName() - ? target_arch.GetArchitectureName() - : "<null>", - target_arch.GetTriple().getTriple().c_str() - ? target_arch.GetTriple().getTriple().c_str() - : "<null>"); - - // If the remote host is ARM and we have apple as the vendor, then - // ARM executables and shared libraries can have mixed ARM - // architectures. - // You can have an armv6 executable, and if the host is armv7, then the - // system will load the best possible architecture for all shared - // libraries it has, so we really need to take the remote host - // architecture as our defacto architecture in this case. - - if ((process_arch.GetMachine() == llvm::Triple::arm || - process_arch.GetMachine() == llvm::Triple::thumb) && - process_arch.GetTriple().getVendor() == llvm::Triple::Apple) { - GetTarget().SetArchitecture(process_arch); - LLDB_LOGF(log, - "ProcessGDBRemote::%s remote process is ARM/Apple, " - "setting target arch to %s %s", - __FUNCTION__, - process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", - process_arch.GetTriple().getTriple().c_str() - ? process_arch.GetTriple().getTriple().c_str() - : "<null>"); - } else { - // Fill in what is missing in the triple - const llvm::Triple &remote_triple = process_arch.GetTriple(); - llvm::Triple new_target_triple = target_arch.GetTriple(); - if (new_target_triple.getVendorName().size() == 0) { - new_target_triple.setVendor(remote_triple.getVendor()); - - if (new_target_triple.getOSName().size() == 0) { - new_target_triple.setOS(remote_triple.getOS()); - - if (new_target_triple.getEnvironmentName().size() == 0) - new_target_triple.setEnvironment( - remote_triple.getEnvironment()); - } + if (new_target_triple.getOSName().size() == 0) { + new_target_triple.setOS(remote_triple.getOS()); - ArchSpec new_target_arch = target_arch; - new_target_arch.SetTriple(new_target_triple); - GetTarget().SetArchitecture(new_target_arch); + if (new_target_triple.getEnvironmentName().size() == 0) + new_target_triple.setEnvironment(remote_triple.getEnvironment()); } - } - LLDB_LOGF(log, - "ProcessGDBRemote::%s final target arch after " - "adjustments for remote architecture: %s %s", - __FUNCTION__, - target_arch.GetArchitectureName() - ? target_arch.GetArchitectureName() - : "<null>", - target_arch.GetTriple().getTriple().c_str() - ? target_arch.GetTriple().getTriple().c_str() - : "<null>"); - } else { - // The target doesn't have a valid architecture yet, set it from the - // architecture we got from the remote GDB server - GetTarget().SetArchitecture(process_arch); + ArchSpec new_target_arch = target_arch; + new_target_arch.SetTriple(new_target_triple); + GetTarget().SetArchitecture(new_target_arch); + } } + + LLDB_LOG(log, + "final target arch after adjustments for remote architecture: " + "{0} {1}", + target_arch.GetArchitectureName(), + target_arch.GetTriple().getTriple()); + } else { + // The target doesn't have a valid architecture yet, set it from the + // architecture we got from the remote GDB server + GetTarget().SetArchitecture(process_arch); } + } + + MaybeLoadExecutableModule(); + + // Find out which StructuredDataPlugins are supported by the debug monitor. + // These plugins transmit data over async $J packets. + if (StructuredData::Array *supported_packets = + m_gdb_comm.GetSupportedStructuredDataPlugins()) + MapSupportedStructuredDataPlugins(*supported_packets); +} + +void ProcessGDBRemote::MaybeLoadExecutableModule() { + ModuleSP module_sp = GetTarget().GetExecutableModule(); + if (!module_sp) + return; + + llvm::Optional<QOffsets> offsets = m_gdb_comm.GetQOffsets(); + if (!offsets) + return; - // Find out which StructuredDataPlugins are supported by the debug monitor. - // These plugins transmit data over async $J packets. - auto supported_packets_array = - m_gdb_comm.GetSupportedStructuredDataPlugins(); - if (supported_packets_array) - MapSupportedStructuredDataPlugins(*supported_packets_array); + bool is_uniform = + size_t(llvm::count(offsets->offsets, offsets->offsets[0])) == + offsets->offsets.size(); + if (!is_uniform) + return; // TODO: Handle non-uniform responses. + + bool changed = false; + module_sp->SetLoadAddress(GetTarget(), offsets->offsets[0], + /*value_is_offset=*/true, changed); + if (changed) { + ModuleList list; + list.Append(module_sp); + m_process->GetTarget().ModulesDidLoad(list); } } @@ -1576,7 +1561,8 @@ bool ProcessGDBRemote::UpdateThreadIDList() { for (int i = 0; i < nItems; i++) { // Get the thread stop info StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; - const std::string &stop_info_str = stop_info.GetStringRef(); + const std::string &stop_info_str = + std::string(stop_info.GetStringRef()); m_thread_pcs.clear(); const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:"); @@ -2040,14 +2026,14 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { }); } } else if (key == g_key_name) { - thread_name = object->GetStringValue(); + thread_name = std::string(object->GetStringValue()); } else if (key == g_key_qaddr) { thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS); } else if (key == g_key_queue_name) { queue_vars_valid = true; - queue_name = object->GetStringValue(); + queue_name = std::string(object->GetStringValue()); } else if (key == g_key_queue_kind) { - std::string queue_kind_str = object->GetStringValue(); + std::string queue_kind_str = std::string(object->GetStringValue()); if (queue_kind_str == "serial") { queue_vars_valid = true; queue_kind = eQueueKindSerial; @@ -2071,9 +2057,9 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { else associated_with_dispatch_queue = eLazyBoolNo; } else if (key == g_key_reason) { - reason = object->GetStringValue(); + reason = std::string(object->GetStringValue()); } else if (key == g_key_description) { - description = object->GetStringValue(); + description = std::string(object->GetStringValue()); } else if (key == g_key_registers) { StructuredData::Dictionary *registers_dict = object->GetAsDictionary(); @@ -2084,7 +2070,8 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { const uint32_t reg = StringConvert::ToUInt32(key.GetCString(), UINT32_MAX, 10); if (reg != UINT32_MAX) - expedited_register_map[reg] = object->GetStringValue(); + expedited_register_map[reg] = + std::string(object->GetStringValue()); return true; // Keep iterating through all array items }); } @@ -2227,7 +2214,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { // Now convert the HEX bytes into a string value name_extractor.GetHexByteString(thread_name); } else if (key.compare("name") == 0) { - thread_name = value; + thread_name = std::string(value); } else if (key.compare("qaddr") == 0) { value.getAsInteger(16, thread_dispatch_qaddr); } else if (key.compare("dispatch_queue_t") == 0) { @@ -2248,7 +2235,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { if (!value.getAsInteger(0, queue_serial_number)) queue_vars_valid = true; } else if (key.compare("reason") == 0) { - reason = value; + reason = std::string(value); } else if (key.compare("description") == 0) { StringExtractor desc_extractor(value); // Now convert the HEX bytes into a string value @@ -2297,7 +2284,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { reason = "watchpoint"; StreamString ostr; ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index); - description = ostr.GetString(); + description = std::string(ostr.GetString()); } else if (key.compare("library") == 0) { auto error = LoadModules(); if (error) { @@ -2308,7 +2295,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { } else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) { uint32_t reg = UINT32_MAX; if (!key.getAsInteger(16, reg)) - expedited_register_map[reg] = std::move(value); + expedited_register_map[reg] = std::string(std::move(value)); } } @@ -2585,7 +2572,7 @@ Status ProcessGDBRemote::DoDestroy() { "to k packet: %s", response.GetStringRef().data()); exit_string.assign("got unexpected response to k packet: "); - exit_string.append(response.GetStringRef()); + exit_string.append(std::string(response.GetStringRef())); } } else { LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy - failed to send k packet"); @@ -3127,7 +3114,7 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) { if (error_no != UINT8_MAX) error.SetErrorStringWithFormat( - "error: %d sending the breakpoint request", errno); + "error: %d sending the breakpoint request", error_no); else error.SetErrorString("error sending the breakpoint request"); return error; @@ -3356,30 +3343,10 @@ Status ProcessGDBRemote::DoSignal(int signo) { return error; } -Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { - if (!loader) - return Status("No loader provided."); - - static std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>> - multi_loader = repro::MultiLoader<repro::GDBRemoteProvider>::Create( - repro::Reproducer::Instance().GetLoader()); - - if (!multi_loader) - return Status("No gdb remote provider found."); - - llvm::Optional<std::string> history_file = multi_loader->GetNextFile(); - if (!history_file) - return Status("No gdb remote packet log found."); - - // Load replay history. - if (auto error = - m_gdb_replay_server.LoadReplayHistory(FileSpec(*history_file))) - return Status("Unable to load replay history"); - - // Make a local connection. - if (auto error = GDBRemoteCommunication::ConnectLocally(m_gdb_comm, - m_gdb_replay_server)) - return Status("Unable to connect to replay server"); +Status ProcessGDBRemote::ConnectToReplayServer() { + Status status = m_gdb_replay_server.Connect(m_gdb_comm); + if (status.Fail()) + return status; // Enable replay mode. m_replay_mode = true; @@ -3404,8 +3371,8 @@ ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) { if (platform_sp && !platform_sp->IsHost()) return Status("Lost debug server connection"); - if (repro::Loader *loader = repro::Reproducer::Instance().GetLoader()) - return ConnectToReplayServer(loader); + if (repro::Reproducer::Instance().IsReplaying()) + return ConnectToReplayServer(); auto error = LaunchAndConnectToDebugserver(process_info); if (error.Fail()) { @@ -3452,6 +3419,23 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver( std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3, _4), false); debugserver_launch_info.SetUserID(process_info.GetUserID()); +#if defined(__APPLE__) + // On macOS 11, we need to support x86_64 applications translated to + // arm64. We check whether a binary is translated and spawn the correct + // debugserver accordingly. + int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, + static_cast<int>(process_info.GetProcessID()) }; + struct kinfo_proc processInfo; + size_t bufsize = sizeof(processInfo); + if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, + &bufsize, NULL, 0) == 0 && bufsize > 0) { + if (processInfo.kp_proc.p_flag & P_TRANSLATED) { + FileSpec rosetta_debugserver("/Library/Apple/usr/libexec/oah/debugserver"); + debugserver_launch_info.SetExecutableFile(rosetta_debugserver, false); + } + } +#endif + int communication_fd = -1; #ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION // Use a socketpair on non-Windows systems for security and performance @@ -3486,7 +3470,8 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver( // Our process spawned correctly, we can now set our connection to use // our end of the socket pair cleanup_our.release(); - m_gdb_comm.SetConnection(new ConnectionFileDescriptor(our_socket, true)); + m_gdb_comm.SetConnection( + std::make_unique<ConnectionFileDescriptor>(our_socket, true)); #endif StartAsyncThread(); } @@ -3648,7 +3633,7 @@ void ProcessGDBRemote::StopAsyncThread() { bool ProcessGDBRemote::HandleNotifyPacket(StringExtractorGDBRemote &packet) { // get the packet at a string - const std::string &pkt = packet.GetStringRef(); + const std::string &pkt = std::string(packet.GetStringRef()); // skip %stop: StringExtractorGDBRemote stop_info(pkt.c_str() + 5); @@ -3794,7 +3779,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { } // switch(stop_state) } // else // if in All-stop-mode } // if (continue_packet) - } // case eBroadcastBitAysncContinue + } // case eBroadcastBitAsyncContinue break; case eBroadcastBitAsyncThreadShouldExit: @@ -4030,7 +4015,8 @@ ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) { response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) { if (!response.Empty()) { - object_sp = StructuredData::ParseJSON(response.GetStringRef()); + object_sp = + StructuredData::ParseJSON(std::string(response.GetStringRef())); } } } @@ -4102,7 +4088,8 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender( response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) { if (!response.Empty()) { - object_sp = StructuredData::ParseJSON(response.GetStringRef()); + object_sp = + StructuredData::ParseJSON(std::string(response.GetStringRef())); } } } @@ -4135,7 +4122,8 @@ StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() { response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) { if (!response.Empty()) { - object_sp = StructuredData::ParseJSON(response.GetStringRef()); + object_sp = + StructuredData::ParseJSON(std::string(response.GetStringRef())); } } } @@ -4419,7 +4407,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, }); if (!gdb_type.empty() && !(encoding_set || format_set)) { - if (gdb_type.find("int") == 0) { + if (llvm::StringRef(gdb_type).startswith("int")) { reg_info.format = eFormatHex; reg_info.encoding = eEncodingUint; } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") { @@ -4682,7 +4670,7 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() { // value. module.set_base_is_offset(true); } else if (name == "l_ld") { - // the memory address of the libraries PT_DYAMIC section. + // the memory address of the libraries PT_DYNAMIC section. module.set_dynamic(StringConvert::ToUInt64( value.data(), LLDB_INVALID_ADDRESS, 0)); } @@ -5069,7 +5057,8 @@ ParseStructuredDataPacket(llvm::StringRef packet) { } // This is an asynchronous JSON packet, destined for a StructuredDataPlugin. - StructuredData::ObjectSP json_sp = StructuredData::ParseJSON(packet); + StructuredData::ObjectSP json_sp = + StructuredData::ParseJSON(std::string(packet)); if (log) { if (json_sp) { StreamString json_str; @@ -5276,7 +5265,7 @@ public: result.SetStatus(eReturnStatusSuccessFinishResult); Stream &output_strm = result.GetOutputStream(); output_strm.Printf(" packet: %s\n", packet_cstr); - std::string response_str = response.GetStringRef(); + std::string response_str = std::string(response.GetStringRef()); if (strstr(packet_cstr, "qGetProfileData") != nullptr) { response_str = process->HarmonizeThreadIdsForProfileData(response); @@ -5329,7 +5318,7 @@ public: [&output_strm](llvm::StringRef output) { output_strm << output; }); result.SetStatus(eReturnStatusSuccessFinishResult); output_strm.Printf(" packet: %s\n", packet.GetData()); - const std::string &response_str = response.GetStringRef(); + const std::string &response_str = std::string(response.GetStringRef()); if (response_str.empty()) output_strm.PutCString("response: \nerror: UNIMPLEMENTED\n"); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 9ea3940103b6..ba967727ae3b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ProcessGDBRemote_h_ -#define liblldb_ProcessGDBRemote_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTE_H #include <atomic> #include <map> @@ -85,7 +85,7 @@ public: Status WillAttachToProcessWithName(const char *process_name, bool wait_for_launch) override; - Status DoConnectRemote(Stream *strm, llvm::StringRef remote_url) override; + Status DoConnectRemote(llvm::StringRef remote_url) override; Status WillLaunchOrAttach(); @@ -312,7 +312,7 @@ protected: bool UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) override; - Status ConnectToReplayServer(repro::Loader *loader); + Status ConnectToReplayServer(); Status EstablishConnectionIfNeeded(const ProcessInfo &process_info); @@ -377,6 +377,7 @@ protected: bool UpdateThreadIDList(); void DidLaunchOrAttach(ArchSpec &process_arch); + void MaybeLoadExecutableModule(); Status ConnectToDebugserver(llvm::StringRef host_port); @@ -386,7 +387,7 @@ protected: DynamicLoader *GetDynamicLoader() override; bool GetGDBServerRegisterInfoXMLAndProcess(ArchSpec &arch_to_use, - std::string xml_filename, + std::string xml_filename, uint32_t &cur_reg_num, uint32_t ®_offset); @@ -449,10 +450,11 @@ private: llvm::DenseMap<ModuleCacheKey, ModuleSpec, ModuleCacheInfo> m_cached_module_specs; - DISALLOW_COPY_AND_ASSIGN(ProcessGDBRemote); + ProcessGDBRemote(const ProcessGDBRemote &) = delete; + const ProcessGDBRemote &operator=(const ProcessGDBRemote &) = delete; }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_ProcessGDBRemote_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTE_H diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp index 8cadc45824b3..40990ef66494 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp @@ -1,4 +1,4 @@ -//===-- ProcessGDBRemoteLog.cpp ---------------------------------*- C++ -*-===// +//===-- ProcessGDBRemoteLog.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h index d9b8d4536afe..bd3e993cf72a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h @@ -6,9 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ProcessGDBRemoteLog_h_ -#define liblldb_ProcessGDBRemoteLog_h_ - +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTELOG_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTELOG_H #include "lldb/Utility/Log.h" @@ -43,4 +42,4 @@ public: } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_ProcessGDBRemoteLog_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTELOG_H diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td index 9cbe3d40ca2c..d4c3c8b94b7e 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td @@ -11,8 +11,8 @@ let Definition = "processgdbremote" in { Desc<"The file that provides the description for remote target registers.">; def UseSVR4: Property<"use-libraries-svr4", "Boolean">, Global, - DefaultFalse, - Desc<"If true, the libraries-svr4 feature will be used to get a hold of the process's loaded modules.">; + DefaultTrue, + Desc<"If true, the libraries-svr4 feature will be used to get a hold of the process's loaded modules. This setting is only effective if lldb was build with xml support.">; def UseGPacketForReading: Property<"use-g-packet-for-reading", "Boolean">, Global, DefaultFalse, diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 9da481979f73..6deabf8d5d71 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -1,4 +1,4 @@ -//===-- ThreadGDBRemote.cpp -------------------------------------*- C++ -*-===// +//===-- ThreadGDBRemote.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -311,9 +311,7 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { read_all_registers_at_once, write_all_registers_at_once); } } else { - Unwind *unwinder = GetUnwinder(); - if (unwinder != nullptr) - reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); + reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); } return reg_ctx_sp; } diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index c74be169abaf..5ad11170fec4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ThreadGDBRemote_h_ -#define liblldb_ThreadGDBRemote_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_THREADGDBREMOTE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_THREADGDBREMOTE_H #include <string> @@ -116,4 +116,4 @@ protected: } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_ThreadGDBRemote_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_THREADGDBREMOTE_H diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index 3c0e1cb49d1d..0c7f4cbbb859 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -1,4 +1,4 @@ -//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===// +//===-- MinidumpParser.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h index 4bcb2b47d45a..c4d7612b5f8d 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_MinidumpParser_h_ -#define liblldb_MinidumpParser_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H #include "MinidumpTypes.h" @@ -100,7 +100,6 @@ private: MinidumpParser(lldb::DataBufferSP data_sp, std::unique_ptr<llvm::object::MinidumpFile> file); -private: lldb::DataBufferSP m_data_sp; std::unique_ptr<llvm::object::MinidumpFile> m_file; ArchSpec m_arch; @@ -108,4 +107,4 @@ private: } // end namespace minidump } // end namespace lldb_private -#endif // liblldb_MinidumpParser_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp b/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp index ed00b1cc07db..abddd79ad7dc 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp @@ -1,4 +1,4 @@ -//===-- MinidumpTypes.cpp ---------------------------------------*- C++ -*-===// +//===-- MinidumpTypes.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h index a9c807930ebf..a7ac65120e2b 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h +++ b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h @@ -6,9 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_MinidumpTypes_h_ -#define liblldb_MinidumpTypes_h_ - +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H #include "lldb/Utility/Status.h" @@ -120,4 +119,4 @@ private: } // namespace minidump } // namespace lldb_private -#endif // liblldb_MinidumpTypes_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H diff --git a/lldb/source/Plugins/Process/minidump/NtStructures.h b/lldb/source/Plugins/Process/minidump/NtStructures.h index fdb0cfb7981e..1dafbe4a4f50 100644 --- a/lldb/source/Plugins/Process/minidump/NtStructures.h +++ b/lldb/source/Plugins/Process/minidump/NtStructures.h @@ -1,3 +1,7 @@ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_NTSTRUCTURES_H + +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_NTSTRUCTURES_H + //===-- NtStructures.h ------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -34,3 +38,5 @@ struct TEB64 { #endif // liblldb_Plugins_Process_Minidump_NtStructures_h_ } // namespace minidump } // namespace lldb_private + +#endif diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index 5c090dc6e12f..fc8ee346f449 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -1,4 +1,4 @@ -//===-- ProcessMinidump.cpp -------------------------------------*- C++ -*-===// +//===-- ProcessMinidump.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -41,6 +41,8 @@ using namespace lldb; using namespace lldb_private; using namespace minidump; +LLDB_PLUGIN_DEFINE(ProcessMinidump) + namespace { /// A minimal ObjectFile implementation providing a dummy object file for the @@ -226,8 +228,10 @@ Status ProcessMinidump::DoLoadCore() { llvm::Optional<lldb::pid_t> pid = m_minidump_parser->GetPid(); if (!pid) { - error.SetErrorString("failed to parse PID"); - return error; + GetTarget().GetDebugger().GetAsyncErrorStream()->PutCString( + "Unable to retrieve process ID from minidump file, setting process ID " + "to 1.\n"); + pid = 1; } SetID(pid.getValue()); @@ -253,7 +257,7 @@ void ProcessMinidump::RefreshStateAfterStop() { // TODO: The definition and use of this "dump requested" constant // in Breakpad are actually Linux-specific, and for similar use - // cases on Mac/Windows it defines differnt constants, referring + // cases on Mac/Windows it defines different constants, referring // to them as "simulated" exceptions; consider moving this check // down to the OS-specific paths and checking each OS for its own // constant. diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index 750164cf8aaf..839b0e7563f7 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ProcessMinidump_h_ -#define liblldb_ProcessMinidump_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H #include "MinidumpParser.h" #include "MinidumpTypes.h" @@ -119,4 +119,4 @@ private: } // namespace minidump } // namespace lldb_private -#endif // liblldb_ProcessMinidump_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp index 72dead07dcb4..eb48785263fc 100644 --- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp +++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextMinidump_ARM.cpp -------------------------*- C++ -*-===// +//===-- RegisterContextMinidump_ARM.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h index 7af3b98a6fe7..857f9c0a3767 100644 --- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h +++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextMinidump_ARM_h_ -#define liblldb_RegisterContextMinidump_ARM_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H #include "MinidumpTypes.h" @@ -95,4 +95,4 @@ protected: } // end namespace minidump } // end namespace lldb_private -#endif // liblldb_RegisterContextMinidump_ARM_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp index bbd0e14a3267..c7809c5f19b6 100644 --- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp +++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextMinidump_ARM64.cpp -----------------------*- C++ -*-===// +//===-- RegisterContextMinidump_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. diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h index f9e7f39eea60..8ae751095c04 100644 --- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h +++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextMinidump_ARM64_h_ -#define liblldb_RegisterContextMinidump_ARM64_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H #include "MinidumpTypes.h" @@ -79,4 +79,4 @@ protected: } // end namespace minidump } // end namespace lldb_private -#endif // liblldb_RegisterContextMinidump_ARM64_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp index 8ac2abb22093..38d7de77e3bf 100644 --- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp +++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextMinidump_x86_32.cpp ----------------------*- C++ -*-===// +//===-- RegisterContextMinidump_x86_32.cpp --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h index d787f78ec7d3..9592d335eff7 100644 --- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h +++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextMinidump_x86_32_h_ -#define liblldb_RegisterContextMinidump_x86_32_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H #include "MinidumpTypes.h" @@ -132,4 +132,4 @@ enum class MinidumpContext_x86_32_Flags : uint32_t { } // end namespace minidump } // end namespace lldb_private -#endif // liblldb_RegisterContextMinidump_x86_32_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp index 515ccf6b2c3c..3c593f0db6ec 100644 --- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp +++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextMinidump_x86_64.cpp ----------------------*- C++ -*-===// +//===-- RegisterContextMinidump_x86_64.cpp --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h index 34ddd477a9d1..d920ea9d823f 100644 --- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h +++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_RegisterContextMinidump_h_ -#define liblldb_RegisterContextMinidump_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H #include "MinidumpTypes.h" @@ -177,4 +177,4 @@ enum class MinidumpContext_x86_64_Flags : uint32_t { } // end namespace minidump } // end namespace lldb_private -#endif // liblldb_RegisterContextMinidump_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H diff --git a/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp b/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp index 5262de5a94c4..e146a1a1af92 100644 --- a/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp @@ -1,4 +1,4 @@ -//===-- ThreadMinidump.cpp --------------------------------------*- C++ -*-===// +//===-- ThreadMinidump.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/Process/minidump/ThreadMinidump.h b/lldb/source/Plugins/Process/minidump/ThreadMinidump.h index 44c41bc9f50e..aed7cfbc1b16 100644 --- a/lldb/source/Plugins/Process/minidump/ThreadMinidump.h +++ b/lldb/source/Plugins/Process/minidump/ThreadMinidump.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ThreadMinidump_h_ -#define liblldb_ThreadMinidump_h_ +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H +#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H #include "MinidumpTypes.h" @@ -42,4 +42,4 @@ protected: } // namespace minidump } // namespace lldb_private -#endif // liblldb_ThreadMinidump_h_ +#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp index ecee8cc674f8..acd6128d84c5 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp @@ -57,3 +57,35 @@ llvm::Error Lua::LoadModule(llvm::StringRef filename) { lua_setglobal(m_lua_state, module_name.GetCString()); return llvm::Error::success(); } + +llvm::Error Lua::ChangeIO(FILE *out, FILE *err) { + assert(out != nullptr); + assert(err != nullptr); + + lua_getglobal(m_lua_state, "io"); + + lua_getfield(m_lua_state, -1, "stdout"); + if (luaL_Stream *s = static_cast<luaL_Stream *>( + luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { + s->f = out; + lua_pop(m_lua_state, 1); + } else { + lua_pop(m_lua_state, 2); + return llvm::make_error<llvm::StringError>("could not get stdout", + llvm::inconvertibleErrorCode()); + } + + lua_getfield(m_lua_state, -1, "stderr"); + if (luaL_Stream *s = static_cast<luaL_Stream *>( + luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { + s->f = out; + lua_pop(m_lua_state, 1); + } else { + lua_pop(m_lua_state, 2); + return llvm::make_error<llvm::StringError>("could not get stderr", + llvm::inconvertibleErrorCode()); + } + + lua_pop(m_lua_state, 1); + return llvm::Error::success(); +} diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h index f2984a925dfe..300115aac8a7 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h @@ -38,6 +38,7 @@ public: llvm::Error Run(llvm::StringRef buffer); llvm::Error LoadModule(llvm::StringRef filename); + llvm::Error ChangeIO(FILE *out, FILE *err); private: lua_State *m_lua_state; diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp index 701d68d1ec08..8cbeac4563c3 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp @@ -1,4 +1,4 @@ -//===-- ScriptInterpreterLua.cpp --------------------------------*- C++ -*-===// +//===-- ScriptInterpreterLua.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -15,10 +15,13 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/Timer.h" +#include "llvm/Support/FormatAdapters.h" using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ScriptInterpreterLua) + class IOHandlerLuaInterpreter : public IOHandlerDelegate, public IOHandlerEditline { public: @@ -28,15 +31,23 @@ public: ">>> ", "..> ", true, debugger.GetUseColor(), 0, *this, nullptr), m_script_interpreter(script_interpreter) { + llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( + debugger.GetOutputFile().GetStream(), + debugger.GetErrorFile().GetStream())); llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID())); } - ~IOHandlerLuaInterpreter() { + ~IOHandlerLuaInterpreter() override { llvm::cantFail(m_script_interpreter.LeaveSession()); } void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override { + if (llvm::StringRef(data).rtrim() == "quit") { + io_handler.SetIsDone(true); + return; + } + if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) { *GetOutputStreamFileSP() << llvm::toString(std::move(error)); } @@ -55,12 +66,43 @@ ScriptInterpreterLua::~ScriptInterpreterLua() {} bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, CommandReturnObject *result, const ExecuteScriptOptions &options) { + if (command.empty()) { + if (result) + result->AppendError("empty command passed to lua\n"); + return false; + } + + llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> + io_redirect_or_error = ScriptInterpreterIORedirect::Create( + options.GetEnableIO(), m_debugger, result); + if (!io_redirect_or_error) { + if (result) + result->AppendErrorWithFormatv( + "failed to redirect I/O: {0}\n", + llvm::fmt_consume(io_redirect_or_error.takeError())); + else + llvm::consumeError(io_redirect_or_error.takeError()); + return false; + } + + ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; + + if (llvm::Error e = + m_lua->ChangeIO(io_redirect.GetOutputFile()->GetStream(), + io_redirect.GetErrorFile()->GetStream())) { + result->AppendErrorWithFormatv("lua failed to redirect I/O: {0}\n", + llvm::toString(std::move(e))); + return false; + } + if (llvm::Error e = m_lua->Run(command)) { result->AppendErrorWithFormatv( "lua failed attempting to evaluate '{0}': {1}\n", command, llvm::toString(std::move(e))); return false; } + + io_redirect.Flush(); return true; } @@ -68,25 +110,23 @@ void ScriptInterpreterLua::ExecuteInterpreterLoop() { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); - Debugger &debugger = m_debugger; - // At the moment, the only time the debugger does not have an input file // handle is when this is called directly from lua, in which case it is // both dangerous and unnecessary (not to mention confusing) to try to embed // a running interpreter loop inside the already running lua interpreter // loop, so we won't do it. - - if (!debugger.GetInputFile().IsValid()) + if (!m_debugger.GetInputFile().IsValid()) return; - IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(debugger, *this)); - debugger.PushIOHandler(io_handler_sp); + IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(m_debugger, *this)); + m_debugger.RunIOHandlerAsync(io_handler_sp); } bool ScriptInterpreterLua::LoadScriptingModule( const char *filename, bool init_session, lldb_private::Status &error, StructuredData::ObjectSP *module_sp) { + FileSystem::Instance().Collect(filename); if (llvm::Error e = m_lua->LoadModule(filename)) { error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n", filename, llvm::toString(std::move(e))); diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h index 4e922151385b..bcc6ab24f6d0 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h @@ -25,7 +25,7 @@ public: void ExecuteInterpreterLoop() override; - virtual bool + bool LoadScriptingModule(const char *filename, bool init_session, lldb_private::Status &error, StructuredData::ObjectSP *module_sp = nullptr) override; diff --git a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp index 3517f831970d..d9c32cc132d4 100644 --- a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp @@ -1,4 +1,4 @@ -//===-- ScriptInterpreterNone.cpp -------------------------------*- C++ -*-===// +//===-- ScriptInterpreterNone.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -20,6 +20,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ScriptInterpreterNone) + ScriptInterpreterNone::ScriptInterpreterNone(Debugger &debugger) : ScriptInterpreter(debugger, eScriptLanguageNone) {} diff --git a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h index 242065cc23e8..c438b6315c5d 100644 --- a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h +++ b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ScriptInterpreterNone_h_ -#define liblldb_ScriptInterpreterNone_h_ +#ifndef LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_NONE_SCRIPTINTERPRETERNONE_H +#define LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_NONE_SCRIPTINTERPRETERNONE_H #include "lldb/Interpreter/ScriptInterpreter.h" @@ -44,4 +44,4 @@ public: } // namespace lldb_private -#endif // liblldb_ScriptInterpreterNone_h_ +#endif // LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_NONE_SCRIPTINTERPRETERNONE_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index e5a67653e334..6f040fdef09b 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -1,4 +1,4 @@ -//===-- PythonDataObjects.cpp -----------------------------------*- C++ -*-===// +//===-- PythonDataObjects.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -44,7 +44,15 @@ template <> Expected<long long> python::As<long long>(Expected<PythonObject> &&obj) { if (!obj) return obj.takeError(); - return obj.get().AsLongLong(); + return obj->AsLongLong(); +} + +template <> +Expected<unsigned long long> +python::As<unsigned long long>(Expected<PythonObject> &&obj) { + if (!obj) + return obj.takeError(); + return obj->AsUnsignedLongLong(); } template <> @@ -58,7 +66,56 @@ Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) { auto utf8 = str.AsUTF8(); if (!utf8) return utf8.takeError(); - return utf8.get(); + return std::string(utf8.get()); +} + +Expected<long long> PythonObject::AsLongLong() const { + if (!m_py_obj) + return nullDeref(); +#if PY_MAJOR_VERSION < 3 + if (!PyLong_Check(m_py_obj)) { + PythonInteger i(PyRefType::Borrowed, m_py_obj); + return i.AsLongLong(); + } +#endif + assert(!PyErr_Occurred()); + long long r = PyLong_AsLongLong(m_py_obj); + if (PyErr_Occurred()) + return exception(); + return r; +} + +Expected<long long> PythonObject::AsUnsignedLongLong() const { + if (!m_py_obj) + return nullDeref(); +#if PY_MAJOR_VERSION < 3 + if (!PyLong_Check(m_py_obj)) { + PythonInteger i(PyRefType::Borrowed, m_py_obj); + return i.AsUnsignedLongLong(); + } +#endif + assert(!PyErr_Occurred()); + long long r = PyLong_AsUnsignedLongLong(m_py_obj); + if (PyErr_Occurred()) + return exception(); + return r; +} + +// wraps on overflow, instead of raising an error. +Expected<unsigned long long> PythonObject::AsModuloUnsignedLongLong() const { + if (!m_py_obj) + return nullDeref(); +#if PY_MAJOR_VERSION < 3 + if (!PyLong_Check(m_py_obj)) { + PythonInteger i(PyRefType::Borrowed, m_py_obj); + return i.AsModuloUnsignedLongLong(); + } +#endif + assert(!PyErr_Occurred()); + unsigned long long r = PyLong_AsUnsignedLongLongMask(m_py_obj); + if (PyErr_Occurred()) + return exception(); + return r; } void StructuredPythonObject::Serialize(llvm::json::OStream &s) const { @@ -463,32 +520,22 @@ void PythonInteger::Convert(PyRefType &type, PyObject *&py_obj) { #endif } -int64_t PythonInteger::GetInteger() const { - if (m_py_obj) { - assert(PyLong_Check(m_py_obj) && - "PythonInteger::GetInteger has a PyObject that isn't a PyLong"); - - int overflow = 0; - int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow); - if (overflow != 0) { - // We got an integer that overflows, like 18446744072853913392L we can't - // use PyLong_AsLongLong() as it will return 0xffffffffffffffff. If we - // use the unsigned long long it will work as expected. - const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj); - result = static_cast<int64_t>(uval); - } - return result; - } - return UINT64_MAX; -} - void PythonInteger::SetInteger(int64_t value) { *this = Take<PythonInteger>(PyLong_FromLongLong(value)); } StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const { StructuredData::IntegerSP result(new StructuredData::Integer); - result->SetValue(GetInteger()); + // FIXME this is really not ideal. Errors are silently converted to 0 + // and overflows are silently wrapped. But we'd need larger changes + // to StructuredData to fix it, so that's how it is for now. + llvm::Expected<unsigned long long> value = AsModuloUnsignedLongLong(); + if (!value) { + llvm::consumeError(value.takeError()); + result->SetValue(0); + } else { + result->SetValue(value.get()); + } return result; } @@ -1044,7 +1091,7 @@ std::string PythonException::ReadBacktrace() const { if (!backtrace) { std::string message = std::string(toCString()) + "\n" + - "Traceback unavailble, an error occurred while reading it:\n"; + "Traceback unavailable, an error occurred while reading it:\n"; return (message + llvm::toString(backtrace.takeError())); } diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index b75045b239a8..22f6c67eb7a5 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -36,7 +36,7 @@ // can never fail to assert instead, such as the creation of // PythonString from a string literal. // -// * Elimintate Reset(), and make all non-default constructors private. +// * Eliminate Reset(), and make all non-default constructors private. // Python objects should be created with Retain<> or Take<>, and they // should be assigned with operator= // @@ -90,7 +90,9 @@ public: void Serialize(llvm::json::OStream &s) const override; private: - DISALLOW_COPY_AND_ASSIGN(StructuredPythonObject); + StructuredPythonObject(const StructuredPythonObject &) = delete; + const StructuredPythonObject & + operator=(const StructuredPythonObject &) = delete; }; enum class PyObjectType { @@ -319,7 +321,6 @@ public: StructuredData::ObjectSP CreateStructuredObject() const; -public: template <typename... T> llvm::Expected<PythonObject> CallMethod(const char *name, const T &... t) const { @@ -360,15 +361,12 @@ public: return !!r; } - llvm::Expected<long long> AsLongLong() { - if (!m_py_obj) - return nullDeref(); - assert(!PyErr_Occurred()); - long long r = PyLong_AsLongLong(m_py_obj); - if (PyErr_Occurred()) - return exception(); - return r; - } + llvm::Expected<long long> AsLongLong() const; + + llvm::Expected<long long> AsUnsignedLongLong() const; + + // wraps on overflow, instead of raising an error. + llvm::Expected<unsigned long long> AsModuloUnsignedLongLong() const; llvm::Expected<bool> IsInstance(const PythonObject &cls) { if (!m_py_obj || !cls.IsValid()) @@ -400,6 +398,10 @@ template <> llvm::Expected<long long> As<long long>(llvm::Expected<PythonObject> &&obj); template <> +llvm::Expected<unsigned long long> +As<unsigned long long>(llvm::Expected<PythonObject> &&obj); + +template <> llvm::Expected<std::string> As<std::string>(llvm::Expected<PythonObject> &&obj); @@ -491,8 +493,6 @@ public: static bool Check(PyObject *py_obj); static void Convert(PyRefType &type, PyObject *&py_obj); - int64_t GetInteger() const; - void SetInteger(int64_t value); StructuredData::IntegerSP CreateStructuredInteger() const; @@ -595,7 +595,7 @@ public: // safe, returns invalid on error; static PythonModule ImportModule(llvm::StringRef name) { - std::string s = name; + std::string s = std::string(name); auto mod = Import(s.c_str()); if (!mod) { llvm::consumeError(mod.takeError()); diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 06e0d5bfa63f..9f56b4fa60a5 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -1,4 +1,4 @@ -//===-- ScriptInterpreterPython.cpp -----------------------------*- C++ -*-===// +//===-- ScriptInterpreterPython.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -16,7 +16,6 @@ #include "PythonDataObjects.h" #include "PythonReadline.h" #include "ScriptInterpreterPythonImpl.h" - #include "lldb/API/SBFrame.h" #include "lldb/API/SBValue.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -26,7 +25,6 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" -#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Pipe.h" @@ -35,13 +33,9 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Utility/Timer.h" - -#if defined(_WIN32) -#include "lldb/Host/windows/ConnectionGenericFileWindows.h" -#endif - #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" @@ -56,6 +50,8 @@ using namespace lldb_private; using namespace lldb_private::python; using llvm::Expected; +LLDB_PLUGIN_DEFINE(ScriptInterpreterPython) + // Defined in the SWIG source file #if PY_MAJOR_VERSION >= 3 extern "C" PyObject *PyInit__lldb(void); @@ -222,10 +218,6 @@ struct InitializePythonRAII { public: InitializePythonRAII() : m_gil_state(PyGILState_UNLOCKED), m_was_already_initialized(false) { - // Python will muck with STDIN terminal state, so save off any current TTY - // settings so we can restore them. - m_stdin_tty_state.Save(STDIN_FILENO, false); - InitializePythonHome(); #ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE @@ -269,20 +261,40 @@ public: // We initialized the threads in this function, just unlock the GIL. PyEval_SaveThread(); } - - m_stdin_tty_state.Restore(); } private: void InitializePythonHome() { -#if defined(LLDB_PYTHON_HOME) +#if LLDB_EMBED_PYTHON_HOME #if PY_MAJOR_VERSION >= 3 - size_t size = 0; - static wchar_t *g_python_home = Py_DecodeLocale(LLDB_PYTHON_HOME, &size); + typedef wchar_t* str_type; #else - static char g_python_home[] = LLDB_PYTHON_HOME; + typedef char* str_type; #endif - Py_SetPythonHome(g_python_home); + static str_type g_python_home = []() -> str_type { + const char *lldb_python_home = LLDB_PYTHON_HOME; + const char *absolute_python_home = nullptr; + llvm::SmallString<64> path; + if (llvm::sys::path::is_absolute(lldb_python_home)) { + absolute_python_home = lldb_python_home; + } else { + FileSpec spec = HostInfo::GetShlibDir(); + if (!spec) + return nullptr; + spec.GetPath(path); + llvm::sys::path::append(path, lldb_python_home); + absolute_python_home = path.c_str(); + } +#if PY_MAJOR_VERSION >= 3 + size_t size = 0; + return Py_DecodeLocale(absolute_python_home, &size); +#else + return strdup(absolute_python_home); +#endif + }(); + if (g_python_home != nullptr) { + Py_SetPythonHome(g_python_home); + } #else #if defined(__APPLE__) && PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION == 7 // For Darwin, the only Python version supported is the one shipped in the @@ -471,7 +483,7 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger) m_run_one_line_str_global(), m_dictionary_name(m_debugger.GetInstanceName().AsCString()), m_active_io_handler(eIOHandlerNone), m_session_is_active(false), - m_pty_slave_is_open(false), m_valid_session(true), m_lock_count(0), + m_pty_secondary_is_open(false), m_valid_session(true), m_lock_count(0), m_command_thread_state(nullptr) { InitializePrivate(); @@ -853,7 +865,7 @@ static std::string GenerateUniqueName(const char *base_name_wanted, else sstr.Printf("%s_%p", base_name_wanted, name_token); - return sstr.GetString(); + return std::string(sstr.GetString()); } bool ScriptInterpreterPythonImpl::GetEmbeddedInterpreterModuleObjects() { @@ -877,15 +889,6 @@ bool ScriptInterpreterPythonImpl::GetEmbeddedInterpreterModuleObjects() { return m_run_one_line_function.IsValid(); } -static void ReadThreadBytesReceived(void *baton, const void *src, - size_t src_len) { - if (src && src_len) { - Stream *strm = (Stream *)baton; - strm->Write(src, src_len); - strm->Flush(); - } -} - bool ScriptInterpreterPythonImpl::ExecuteOneLine( llvm::StringRef command, CommandReturnObject *result, const ExecuteScriptOptions &options) { @@ -901,77 +904,21 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( // another string to pass to PyRun_SimpleString messes up the escaping. So // we use the following more complicated method to pass the command string // directly down to Python. - Debugger &debugger = m_debugger; - - FileSP input_file_sp; - StreamFileSP output_file_sp; - StreamFileSP error_file_sp; - Communication output_comm( - "lldb.ScriptInterpreterPythonImpl.ExecuteOneLine.comm"); - bool join_read_thread = false; - if (options.GetEnableIO()) { - if (result) { - input_file_sp = debugger.GetInputFileSP(); - // Set output to a temporary file so we can forward the results on to - // the result object - - Pipe pipe; - Status pipe_result = pipe.CreateNew(false); - if (pipe_result.Success()) { -#if defined(_WIN32) - lldb::file_t read_file = pipe.GetReadNativeHandle(); - pipe.ReleaseReadFileDescriptor(); - std::unique_ptr<ConnectionGenericFile> conn_up( - new ConnectionGenericFile(read_file, true)); -#else - std::unique_ptr<ConnectionFileDescriptor> conn_up( - new ConnectionFileDescriptor(pipe.ReleaseReadFileDescriptor(), - true)); -#endif - if (conn_up->IsConnected()) { - output_comm.SetConnection(conn_up.release()); - output_comm.SetReadThreadBytesReceivedCallback( - ReadThreadBytesReceived, &result->GetOutputStream()); - output_comm.StartReadThread(); - join_read_thread = true; - FILE *outfile_handle = - fdopen(pipe.ReleaseWriteFileDescriptor(), "w"); - output_file_sp = std::make_shared<StreamFile>(outfile_handle, true); - error_file_sp = output_file_sp; - if (outfile_handle) - ::setbuf(outfile_handle, nullptr); - - result->SetImmediateOutputFile( - debugger.GetOutputStream().GetFileSP()); - result->SetImmediateErrorFile( - debugger.GetErrorStream().GetFileSP()); - } - } - } - if (!input_file_sp || !output_file_sp || !error_file_sp) - debugger.AdoptTopIOHandlerFilesIfInvalid(input_file_sp, output_file_sp, - error_file_sp); - } else { - auto nullin = FileSystem::Instance().Open( - FileSpec(FileSystem::DEV_NULL), - File::eOpenOptionRead); - auto nullout = FileSystem::Instance().Open( - FileSpec(FileSystem::DEV_NULL), - File::eOpenOptionWrite); - if (!nullin) { - result->AppendErrorWithFormatv("failed to open /dev/null: {0}\n", - llvm::fmt_consume(nullin.takeError())); - return false; - } - if (!nullout) { - result->AppendErrorWithFormatv("failed to open /dev/null: {0}\n", - llvm::fmt_consume(nullout.takeError())); - return false; - } - input_file_sp = std::move(nullin.get()); - error_file_sp = output_file_sp = std::make_shared<StreamFile>(std::move(nullout.get())); + llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> + io_redirect_or_error = ScriptInterpreterIORedirect::Create( + options.GetEnableIO(), m_debugger, result); + if (!io_redirect_or_error) { + if (result) + result->AppendErrorWithFormatv( + "failed to redirect I/O: {0}\n", + llvm::fmt_consume(io_redirect_or_error.takeError())); + else + llvm::consumeError(io_redirect_or_error.takeError()); + return false; } + ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; + bool success = false; { // WARNING! It's imperative that this RAII scope be as tight as @@ -987,8 +934,9 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( Locker::AcquireLock | Locker::InitSession | (options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) | ((result && result->GetInteractive()) ? 0 : Locker::NoSTDIN), - Locker::FreeAcquiredLock | Locker::TearDownSession, input_file_sp, - output_file_sp->GetFileSP(), error_file_sp->GetFileSP()); + Locker::FreeAcquiredLock | Locker::TearDownSession, + io_redirect.GetInputFile(), io_redirect.GetOutputFile(), + io_redirect.GetErrorFile()); // Find the correct script interpreter dictionary in the main module. PythonDictionary &session_dict = GetSessionDictionary(); @@ -1014,21 +962,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( } } - // Flush our output and error file handles - output_file_sp->Flush(); - error_file_sp->Flush(); - } - - if (join_read_thread) { - // Close the write end of the pipe since we are done with our one line - // script. This should cause the read thread that output_comm is using to - // exit - output_file_sp->GetFile().Close(); - // The close above should cause this thread to exit when it gets to the - // end of file, so let it get all its data - output_comm.JoinReadThread(); - // Now we can close the read end of the pipe - output_comm.Disconnect(); + io_redirect.Flush(); } if (success) @@ -1064,7 +998,7 @@ void ScriptInterpreterPythonImpl::ExecuteInterpreterLoop() { IOHandlerSP io_handler_sp(new IOHandlerPythonInterpreter(debugger, this)); if (io_handler_sp) { - debugger.PushIOHandler(io_handler_sp); + debugger.RunIOHandlerAsync(io_handler_sp); } } @@ -1343,8 +1277,8 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( bp_options->SetCallback( ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp); return error; - } else - return error; + } + return error; } // Set a Python one-liner as the callback for the watchpoint. @@ -1970,8 +1904,7 @@ lldb::StateType ScriptInterpreterPythonImpl::ScriptedThreadPlanGetRunState( } if (should_step) return lldb::eStateStepping; - else - return lldb::eStateRunning; + return lldb::eStateRunning; } StructuredData::GenericSP @@ -2043,8 +1976,7 @@ ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( if (depth_as_int <= lldb::kLastSearchDepthKind) return (lldb::SearchDepth)depth_as_int; - else - return lldb::eSearchDepthModule; + return lldb::eSearchDepthModule; } StructuredData::ObjectSP @@ -2748,6 +2680,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( { FileSpec target_file(pathname); FileSystem::Instance().Resolve(target_file); + FileSystem::Instance().Collect(target_file); std::string basename(target_file.GetFilename().GetCString()); StreamString command_stream; @@ -3010,39 +2943,42 @@ bool ScriptInterpreterPythonImpl::RunScriptBasedCommand( return ret_val; } -// in Python, a special attribute __doc__ contains the docstring for an object -// (function, method, class, ...) if any is defined Otherwise, the attribute's -// value is None +/// In Python, a special attribute __doc__ contains the docstring for an object +/// (function, method, class, ...) if any is defined Otherwise, the attribute's +/// value is None. bool ScriptInterpreterPythonImpl::GetDocumentationForItem(const char *item, std::string &dest) { dest.clear(); + if (!item || !*item) return false; + std::string command(item); command += ".__doc__"; - char *result_ptr = nullptr; // Python is going to point this to valid data if - // ExecuteOneLineWithReturn returns successfully + // Python is going to point this to valid data if ExecuteOneLineWithReturn + // returns successfully. + char *result_ptr = nullptr; if (ExecuteOneLineWithReturn( - command.c_str(), ScriptInterpreter::eScriptReturnTypeCharStrOrNone, + command, ScriptInterpreter::eScriptReturnTypeCharStrOrNone, &result_ptr, ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false))) { if (result_ptr) dest.assign(result_ptr); return true; - } else { - StreamString str_stream; - str_stream.Printf( - "Function %s was not found. Containing module might be missing.", item); - dest = str_stream.GetString(); - return false; } + + StreamString str_stream; + str_stream << "Function " << item + << " was not found. Containing module might be missing."; + dest = std::string(str_stream.GetString()); + + return false; } bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject( StructuredData::GenericSP cmd_obj_sp, std::string &dest) { - bool got_string = false; dest.clear(); Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); @@ -3076,12 +3012,12 @@ bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject( if (PyErr_Occurred()) PyErr_Clear(); - // right now we know this function exists and is callable.. + // Right now we know this function exists and is callable. PythonObject py_return( PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, nullptr)); - // if it fails, print the error but otherwise go on + // If it fails, print the error but otherwise go on. if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); @@ -3091,9 +3027,10 @@ bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject( PythonString py_string(PyRefType::Borrowed, py_return.get()); llvm::StringRef return_data(py_string.GetString()); dest.assign(return_data.data(), return_data.size()); - got_string = true; + return true; } - return got_string; + + return false; } uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject( @@ -3131,20 +3068,15 @@ uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject( if (PyErr_Occurred()) PyErr_Clear(); - // right now we know this function exists and is callable.. - PythonObject py_return( - PyRefType::Owned, - PyObject_CallMethod(implementor.get(), callee_name, nullptr)); + long long py_return = unwrapOrSetPythonException( + As<long long>(implementor.CallMethod(callee_name))); // if it fails, print the error but otherwise go on if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); - } - - if (py_return.IsAllocated() && PythonInteger::Check(py_return.get())) { - PythonInteger int_value(PyRefType::Borrowed, py_return.get()); - result = int_value.GetInteger(); + } else { + result = py_return; } return result; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 1fa198b07e54..22b2c8152eac 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -395,7 +395,7 @@ public: std::string m_dictionary_name; ActiveIOHandler m_active_io_handler; bool m_session_is_active; - bool m_pty_slave_is_open; + bool m_pty_secondary_is_open; bool m_valid_session; uint32_t m_lock_count; PyThreadState *m_command_thread_state; diff --git a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp index c6b234baa8c8..5ceaf886b812 100644 --- a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp +++ b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp @@ -1,4 +1,4 @@ -//===-- StructuredDataDarwinLog.cpp -----------------------------*- C++ -*-===// +//===-- StructuredDataDarwinLog.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -36,6 +36,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(StructuredDataDarwinLog) + #pragma mark - #pragma mark Anonymous Namespace @@ -706,9 +708,9 @@ private: attribute_end_pos + 1, operation_end_pos - (attribute_end_pos + 1)); // add filter spec - auto rule_sp = - FilterRule::CreateRule(accept, attribute_index, ConstString(operation), - rule_text.substr(operation_end_pos + 1), error); + auto rule_sp = FilterRule::CreateRule( + accept, attribute_index, ConstString(operation), + std::string(rule_text.substr(operation_end_pos + 1)), error); if (rule_sp && error.Success()) m_filter_rules.push_back(rule_sp); @@ -979,7 +981,7 @@ EnableOptionsSP ParseAutoEnableOptions(Status &error, Debugger &debugger) { EnableOptionsSP options_sp(new EnableOptions()); options_sp->NotifyOptionParsingStarting(&exe_ctx); - CommandReturnObject result; + CommandReturnObject result(debugger.GetUseColor()); // Parse the arguments. auto options_property_sp = @@ -1034,7 +1036,7 @@ bool RunEnableCommand(CommandInterpreter &interpreter) { } // Run the command. - CommandReturnObject return_object; + CommandReturnObject return_object(interpreter.GetDebugger().GetUseColor()); interpreter.HandleCommand(command_stream.GetData(), eLazyBoolNo, return_object); return return_object.Succeeded(); diff --git a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h index 8fa1eed66efb..caa94af1f30e 100644 --- a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h +++ b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef StructuredDataDarwinLog_h -#define StructuredDataDarwinLog_h +#ifndef LLDB_SOURCE_PLUGINS_STRUCTUREDDATA_DARWINLOG_STRUCTUREDDATADARWINLOG_H +#define LLDB_SOURCE_PLUGINS_STRUCTUREDDATA_DARWINLOG_STRUCTUREDDATADARWINLOG_H #include "lldb/Target/StructuredDataPlugin.h" @@ -34,7 +34,7 @@ public: /// Return whether the DarwinLog functionality is enabled. /// - /// The DarwinLog functionality is enabled if the user expicitly enabled + /// The DarwinLog functionality is enabled if the user explicitly enabled /// it with the enable command, or if the user has the setting set /// that controls if we always enable it for newly created/attached /// processes. @@ -115,4 +115,4 @@ private: }; } -#endif /* StructuredDataPluginDarwinLog_hpp */ +#endif // LLDB_SOURCE_PLUGINS_STRUCTUREDDATA_DARWINLOG_STRUCTUREDDATADARWINLOG_H diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp index b2c4d0883341..eeec7296747e 100644 --- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -1,4 +1,4 @@ -//===-- SymbolFileBreakpad.cpp ----------------------------------*- C++ -*-===// +//===-- SymbolFileBreakpad.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -25,6 +25,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::breakpad; +LLDB_PLUGIN_DEFINE(SymbolFileBreakpad) + char SymbolFileBreakpad::ID; class SymbolFileBreakpad::LineIterator { @@ -292,7 +294,7 @@ uint32_t SymbolFileBreakpad::ResolveSymbolContext( } void SymbolFileBreakpad::FindFunctions( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) { // TODO @@ -305,7 +307,7 @@ void SymbolFileBreakpad::FindFunctions(const RegularExpression ®ex, } void SymbolFileBreakpad::FindTypes( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {} @@ -406,20 +408,25 @@ GetRule(llvm::StringRef &unwind_rules) { } static const RegisterInfo * -ResolveRegister(const SymbolFile::RegisterInfoResolver &resolver, +ResolveRegister(const llvm::Triple &triple, + const SymbolFile::RegisterInfoResolver &resolver, llvm::StringRef name) { - if (name.consume_front("$")) - return resolver.ResolveName(name); - - return nullptr; + if (triple.isX86() || triple.isMIPS()) { + // X86 and MIPS registers have '$' in front of their register names. Arm and + // AArch64 don't. + if (!name.consume_front("$")) + return nullptr; + } + return resolver.ResolveName(name); } static const RegisterInfo * -ResolveRegisterOrRA(const SymbolFile::RegisterInfoResolver &resolver, +ResolveRegisterOrRA(const llvm::Triple &triple, + const SymbolFile::RegisterInfoResolver &resolver, llvm::StringRef name) { if (name == ".ra") return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - return ResolveRegister(resolver, name); + return ResolveRegister(triple, resolver, name); } llvm::ArrayRef<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) { @@ -438,6 +445,7 @@ bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules, Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); llvm::BumpPtrAllocator node_alloc; + llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple(); while (auto rule = GetRule(unwind_rules)) { node_alloc.Reset(); llvm::StringRef lhs = rule->first; @@ -453,7 +461,8 @@ bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules, if (name == ".cfa" && lhs != ".cfa") return postfix::MakeNode<postfix::InitialValueNode>(node_alloc); - if (const RegisterInfo *info = ResolveRegister(resolver, name)) { + if (const RegisterInfo *info = + ResolveRegister(triple, resolver, name)) { return postfix::MakeNode<postfix::RegisterNode>( node_alloc, info->kinds[eRegisterKindLLDB]); } @@ -468,7 +477,8 @@ bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules, llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*rhs); if (lhs == ".cfa") { row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size()); - } else if (const RegisterInfo *info = ResolveRegisterOrRA(resolver, lhs)) { + } else if (const RegisterInfo *info = + ResolveRegisterOrRA(triple, resolver, lhs)) { UnwindPlan::Row::RegisterLocation loc; loc.SetIsDWARFExpression(saved.data(), saved.size()); row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc); @@ -572,6 +582,7 @@ SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark, return nullptr; } auto it = program.begin(); + llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple(); const auto &symbol_resolver = [&](postfix::SymbolNode &symbol) -> postfix::Node * { llvm::StringRef name = symbol.GetName(); @@ -579,7 +590,7 @@ SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark, if (rule.first == name) return rule.second; } - if (const RegisterInfo *info = ResolveRegister(resolver, name)) + if (const RegisterInfo *info = ResolveRegister(triple, resolver, name)) return postfix::MakeNode<postfix::RegisterNode>( node_alloc, info->kinds[eRegisterKindLLDB]); return nullptr; @@ -609,7 +620,7 @@ SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark, // Now process the rest of the assignments. for (++it; it != program.end(); ++it) { - const RegisterInfo *info = ResolveRegister(resolver, it->first); + const RegisterInfo *info = ResolveRegister(triple, resolver, it->first); // It is not an error if the resolution fails because the program may // contain temporary variables. if (!info) @@ -694,18 +705,18 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, "How did we create compile units without a base address?"); SupportFileMap map; - data.line_table_up = std::make_unique<LineTable>(&cu); - std::unique_ptr<LineSequence> line_seq_up( - data.line_table_up->CreateLineSequenceContainer()); + std::vector<std::unique_ptr<LineSequence>> sequences; + std::unique_ptr<LineSequence> line_seq_up = + LineTable::CreateLineSequenceContainer(); llvm::Optional<addr_t> next_addr; auto finish_sequence = [&]() { - data.line_table_up->AppendLineEntryToSequence( + LineTable::AppendLineEntryToSequence( line_seq_up.get(), *next_addr, /*line*/ 0, /*column*/ 0, /*file_idx*/ 0, /*is_start_of_statement*/ false, /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false, /*is_epilogue_begin*/ false, /*is_terminal_entry*/ true); - data.line_table_up->InsertSequence(line_seq_up.get()); - line_seq_up->Clear(); + sequences.push_back(std::move(line_seq_up)); + line_seq_up = LineTable::CreateLineSequenceContainer(); }; LineIterator It(*m_objfile_sp, Record::Func, data.bookmark), @@ -722,7 +733,7 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, // Discontiguous entries. Finish off the previous sequence and reset. finish_sequence(); } - data.line_table_up->AppendLineEntryToSequence( + LineTable::AppendLineEntryToSequence( line_seq_up.get(), record->Address, record->LineNum, /*column*/ 0, map[record->FileNum], /*is_start_of_statement*/ true, /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false, @@ -731,6 +742,7 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, } if (next_addr) finish_sequence(); + data.line_table_up = std::make_unique<LineTable>(&cu, std::move(sequences)); data.support_files = map.translate(cu.GetPrimaryFile(), *m_files); } diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h index de271224a65d..90dbcc77627a 100644 --- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H -#define LLDB_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h" #include "lldb/Core/FileSpecList.h" @@ -82,7 +82,7 @@ public: size_t ParseBlocksRecursive(Function &func) override { return 0; } void FindGlobalVariables(ConstString name, - const CompilerDeclContext *parent_decl_ctx, + const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, VariableList &variables) override {} @@ -110,14 +110,14 @@ public: TypeList &type_list) override {} void FindFunctions(ConstString name, - const CompilerDeclContext *parent_decl_ctx, + const CompilerDeclContext &parent_decl_ctx, lldb::FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) override; void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) override; - void FindTypes(ConstString name, const CompilerDeclContext *parent_decl_ctx, + void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) override; @@ -135,7 +135,7 @@ public: CompilerDeclContext FindNamespace(ConstString name, - const CompilerDeclContext *parent_decl_ctx) override { + const CompilerDeclContext &parent_decl_ctx) override { return CompilerDeclContext(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp index 0a5073b8cd9e..33ab11a3ca40 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -1,4 +1,4 @@ -//===-- AppleDWARFIndex.cpp ------------------------------------*- C++ -*-===// +//===-- AppleDWARFIndex.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -52,54 +52,70 @@ std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create( return nullptr; } -void AppleDWARFIndex::GetGlobalVariables(ConstString basename, DIEArray &offsets) { - if (m_apple_names_up) - m_apple_names_up->FindByName(basename.GetStringRef(), offsets); +void AppleDWARFIndex::GetGlobalVariables( + ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) { + if (!m_apple_names_up) + return; + m_apple_names_up->FindByName( + basename.GetStringRef(), + DIERefCallback(callback, basename.GetStringRef())); } -void AppleDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, - DIEArray &offsets) { +void AppleDWARFIndex::GetGlobalVariables( + const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) { if (!m_apple_names_up) return; DWARFMappedHash::DIEInfoArray hash_data; - if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) - DWARFMappedHash::ExtractDIEArray(hash_data, offsets); + m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data); + // This is not really the DIE name. + DWARFMappedHash::ExtractDIEArray(hash_data, + DIERefCallback(callback, regex.GetText())); } -void AppleDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, - DIEArray &offsets) { +void AppleDWARFIndex::GetGlobalVariables( + const DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) { if (!m_apple_names_up) return; DWARFMappedHash::DIEInfoArray hash_data; - if (m_apple_names_up->AppendAllDIEsInRange(cu.GetOffset(), - cu.GetNextUnitOffset(), hash_data)) - DWARFMappedHash::ExtractDIEArray(hash_data, offsets); + m_apple_names_up->AppendAllDIEsInRange(cu.GetOffset(), cu.GetNextUnitOffset(), + hash_data); + DWARFMappedHash::ExtractDIEArray(hash_data, DIERefCallback(callback)); } -void AppleDWARFIndex::GetObjCMethods(ConstString class_name, - DIEArray &offsets) { - if (m_apple_objc_up) - m_apple_objc_up->FindByName(class_name.GetStringRef(), offsets); +void AppleDWARFIndex::GetObjCMethods( + ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) { + if (!m_apple_objc_up) + return; + m_apple_objc_up->FindByName( + class_name.GetStringRef(), + DIERefCallback(callback, class_name.GetStringRef())); } -void AppleDWARFIndex::GetCompleteObjCClass(ConstString class_name, - bool must_be_implementation, - DIEArray &offsets) { - if (m_apple_types_up) { - m_apple_types_up->FindCompleteObjCClassByName( - class_name.GetStringRef(), offsets, must_be_implementation); - } +void AppleDWARFIndex::GetCompleteObjCClass( + ConstString class_name, bool must_be_implementation, + llvm::function_ref<bool(DWARFDIE die)> callback) { + if (!m_apple_types_up) + return; + m_apple_types_up->FindCompleteObjCClassByName( + class_name.GetStringRef(), + DIERefCallback(callback, class_name.GetStringRef()), + must_be_implementation); } -void AppleDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { - if (m_apple_types_up) - m_apple_types_up->FindByName(name.GetStringRef(), offsets); +void AppleDWARFIndex::GetTypes( + ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { + if (!m_apple_types_up) + return; + m_apple_types_up->FindByName(name.GetStringRef(), + DIERefCallback(callback, name.GetStringRef())); } -void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context, - DIEArray &offsets) { +void AppleDWARFIndex::GetTypes( + const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) { if (!m_apple_types_up) return; @@ -119,7 +135,8 @@ void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context, if (log) m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()"); m_apple_types_up->FindByNameAndTagAndQualifiedNameHash( - type_name.GetStringRef(), tag, qualified_name_hash, offsets); + type_name.GetStringRef(), tag, qualified_name_hash, + DIERefCallback(callback, type_name.GetStringRef())); return; } @@ -133,54 +150,52 @@ void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context, if (!has_qualified_name_hash && (context.GetSize() > 1) && (context[1].tag == DW_TAG_class_type || context[1].tag == DW_TAG_structure_type)) { - DIEArray class_matches; - m_apple_types_up->FindByName(context[1].name, class_matches); - if (class_matches.empty()) + if (m_apple_types_up->FindByName(context[1].name, + [&](DIERef ref) { return false; })) return; } if (log) m_module.LogMessage(log, "FindByNameAndTag()"); - m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets); + m_apple_types_up->FindByNameAndTag( + type_name.GetStringRef(), tag, + DIERefCallback(callback, type_name.GetStringRef())); return; } - m_apple_types_up->FindByName(type_name.GetStringRef(), offsets); + m_apple_types_up->FindByName( + type_name.GetStringRef(), + DIERefCallback(callback, type_name.GetStringRef())); } -void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { - if (m_apple_namespaces_up) - m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets); +void AppleDWARFIndex::GetNamespaces( + ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { + if (!m_apple_namespaces_up) + return; + m_apple_namespaces_up->FindByName( + name.GetStringRef(), DIERefCallback(callback, name.GetStringRef())); } -void AppleDWARFIndex::GetFunctions(ConstString name, SymbolFileDWARF &dwarf, - const CompilerDeclContext &parent_decl_ctx, - uint32_t name_type_mask, - std::vector<DWARFDIE> &dies) { - DIEArray offsets; - m_apple_names_up->FindByName(name.GetStringRef(), offsets); - for (const DIERef &die_ref : offsets) { - ProcessFunctionDIE(name.GetStringRef(), die_ref, dwarf, parent_decl_ctx, - name_type_mask, dies); - } +void AppleDWARFIndex::GetFunctions( + ConstString name, SymbolFileDWARF &dwarf, + const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, + llvm::function_ref<bool(DWARFDIE die)> callback) { + m_apple_names_up->FindByName(name.GetStringRef(), [&](DIERef die_ref) { + return ProcessFunctionDIE(name.GetStringRef(), die_ref, dwarf, + parent_decl_ctx, name_type_mask, callback); + }); } -void AppleDWARFIndex::GetFunctions(const RegularExpression ®ex, - DIEArray &offsets) { +void AppleDWARFIndex::GetFunctions( + const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) { if (!m_apple_names_up) return; DWARFMappedHash::DIEInfoArray hash_data; - if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) - DWARFMappedHash::ExtractDIEArray(hash_data, offsets); -} - -void AppleDWARFIndex::ReportInvalidDIERef(const DIERef &ref, - llvm::StringRef name) { - m_module.ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (accelerator table had " - "bad die 0x%8.8x for '%s')\n", - ref.die_offset(), name.str().c_str()); + m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data); + DWARFMappedHash::ExtractDIEArray(hash_data, + DIERefCallback(callback, regex.GetText())); } void AppleDWARFIndex::Dump(Stream &s) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h index d15d61e270b3..a7032f50e590 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_APPLEDWARFINDEX_H -#define LLDB_APPLEDWARFINDEX_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_APPLEDWARFINDEX_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_APPLEDWARFINDEX_H #include "Plugins/SymbolFile/DWARF/DWARFIndex.h" #include "Plugins/SymbolFile/DWARF/HashedNameToDIE.h" @@ -32,23 +32,33 @@ public: void Preload() override {} - void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; - void GetGlobalVariables(const RegularExpression ®ex, - DIEArray &offsets) override; - void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; - void GetObjCMethods(ConstString class_name, DIEArray &offsets) override; - void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, - DIEArray &offsets) override; - void GetTypes(ConstString name, DIEArray &offsets) override; - void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; - void GetNamespaces(ConstString name, DIEArray &offsets) override; + void + GetGlobalVariables(ConstString basename, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void + GetGlobalVariables(const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void + GetGlobalVariables(const DWARFUnit &cu, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetObjCMethods(ConstString class_name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetCompleteObjCClass( + ConstString class_name, bool must_be_implementation, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetTypes(ConstString name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetTypes(const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetNamespaces(ConstString name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; void GetFunctions(ConstString name, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, - std::vector<DWARFDIE> &dies) override; - void GetFunctions(const RegularExpression ®ex, DIEArray &offsets) override; + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetFunctions(const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) override; - void ReportInvalidDIERef(const DIERef &ref, llvm::StringRef name) override; void Dump(Stream &s) override; private: @@ -59,4 +69,4 @@ private: }; } // namespace lldb_private -#endif // LLDB_APPLEDWARFINDEX_H +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_APPLEDWARFINDEX_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp index f7f2a5bf006b..7a8ab9c9bcfd 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp @@ -1,4 +1,4 @@ -//===-- DIERef.cpp ----------------------------------------------*- C++ -*-===// +//===-- DIERef.cpp --------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h b/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h index 5546bb7e8b86..f7e09ee17283 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DIERef_h_ -#define SymbolFileDWARF_DIERef_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DIEREF_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DIEREF_H #include "lldb/Core/dwarf.h" #include "llvm/ADT/Optional.h" @@ -44,6 +44,16 @@ public: dw_offset_t die_offset() const { return m_die_offset; } + bool operator<(DIERef other) const { + if (m_dwo_num_valid != other.m_dwo_num_valid) + return m_dwo_num_valid < other.m_dwo_num_valid; + if (m_dwo_num_valid && (m_dwo_num != other.m_dwo_num)) + return m_dwo_num < other.m_dwo_num; + if (m_section != other.m_section) + return m_section < other.m_section; + return m_die_offset < other.m_die_offset; + } + private: uint32_t m_dwo_num : 30; uint32_t m_dwo_num_valid : 1; @@ -60,4 +70,4 @@ template<> struct format_provider<DIERef> { }; } // namespace llvm -#endif // SymbolFileDWARF_DIERef_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DIEREF_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h index 7ee4727cde91..2e0a7fd3ecd3 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFASTParser_h_ -#define SymbolFileDWARF_DWARFASTParser_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSER_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSER_H #include "DWARFDefines.h" #include "lldb/Core/PluginInterface.h" @@ -55,4 +55,4 @@ public: const lldb_private::ExecutionContext *exe_ctx = nullptr); }; -#endif // SymbolFileDWARF_DWARFASTParser_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSER_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 232063a6f339..2d1db66e7fd9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1,4 +1,4 @@ -//===-- DWARFASTParserClang.cpp ---------------------------------*- C++ -*-===// +//===-- DWARFASTParserClang.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,17 +13,17 @@ #include "DWARFDeclContext.h" #include "DWARFDefines.h" #include "SymbolFileDWARF.h" -#include "SymbolFileDWARFDwo.h" #include "SymbolFileDWARFDebugMap.h" +#include "SymbolFileDWARFDwo.h" #include "UniqueDWARFASTType.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Host/Host.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" @@ -35,6 +35,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +#include "llvm/Demangle/Demangle.h" + #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -55,7 +57,7 @@ using namespace lldb; using namespace lldb_private; -DWARFASTParserClang::DWARFASTParserClang(ClangASTContext &ast) +DWARFASTParserClang::DWARFASTParserClang(TypeSystemClang &ast) : m_ast(ast), m_die_to_decl_ctx(), m_decl_ctx_to_die() {} DWARFASTParserClang::~DWARFASTParserClang() {} @@ -85,39 +87,10 @@ static bool DeclKindIsCXXClass(clang::Decl::Kind decl_kind) { return false; } -struct BitfieldInfo { - uint64_t bit_size; - uint64_t bit_offset; - - BitfieldInfo() - : bit_size(LLDB_INVALID_ADDRESS), bit_offset(LLDB_INVALID_ADDRESS) {} - - void Clear() { - bit_size = LLDB_INVALID_ADDRESS; - bit_offset = LLDB_INVALID_ADDRESS; - } - - bool IsValid() const { - return (bit_size != LLDB_INVALID_ADDRESS) && - (bit_offset != LLDB_INVALID_ADDRESS); - } - - bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const { - if (IsValid()) { - // This bitfield info is valid, so any subsequent bitfields must not - // overlap and must be at a higher bit offset than any previous bitfield - // + size. - return (bit_size + bit_offset) <= next_bit_offset; - } else { - // If the this BitfieldInfo is not valid, then any offset isOK - return true; - } - } -}; ClangASTImporter &DWARFASTParserClang::GetClangASTImporter() { if (!m_clang_ast_importer_up) { - m_clang_ast_importer_up.reset(new ClangASTImporter); + m_clang_ast_importer_up = std::make_unique<ClangASTImporter>(); } return *m_clang_ast_importer_up; } @@ -184,7 +157,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, // The type in the Clang module must have the same language as the current CU. LanguageSet languages; - languages.Insert(die.GetCU()->GetLanguageType()); + languages.Insert(SymbolFileDWARF::GetLanguage(*die.GetCU())); llvm::DenseSet<SymbolFile *> searched_symbol_files; clang_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, searched_symbol_files, pcm_types); @@ -239,14 +212,15 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, TypeSP type_sp(new Type( die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, - &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward)); + &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward, + TypePayloadClang(GetOwningClangModule(die)))); dwarf->GetTypeList().Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - clang::TagDecl *tag_decl = ClangASTContext::GetAsTagDecl(type); - if (tag_decl) + clang::TagDecl *tag_decl = TypeSystemClang::GetAsTagDecl(type); + if (tag_decl) { LinkDeclContextToDIE(tag_decl, die); - else { + } else { clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(die); if (defn_decl_ctx) LinkDeclContextToDIE(defn_decl_ctx, die); @@ -255,7 +229,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, return type_sp; } -static void CompleteExternalTagDeclType(ClangASTContext &ast, +static void CompleteExternalTagDeclType(TypeSystemClang &ast, ClangASTImporter &ast_importer, clang::DeclContext *decl_ctx, DWARFDIE die, @@ -277,8 +251,8 @@ static void CompleteExternalTagDeclType(ClangASTContext &ast, type_name_cstr ? type_name_cstr : "", die.GetOffset()); // We need to make the type look complete otherwise, we might crash in // Clang when adding children. - if (ClangASTContext::StartTagDeclarationDefinition(type)) - ClangASTContext::CompleteTagDeclarationDefinition(type); + if (TypeSystemClang::StartTagDeclarationDefinition(type)) + TypeSystemClang::CompleteTagDeclarationDefinition(type); } } @@ -533,7 +507,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, DWARF_LOG_LOOKUPS)); SymbolFileDWARF *dwarf = die.GetDWARF(); const dw_tag_t tag = die.Tag(); - LanguageType cu_language = die.GetLanguage(); + LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU()); Type::ResolveState resolve_state = Type::ResolveState::Unresolved; Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; TypeSP type_sp; @@ -735,7 +709,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, type_sp = std::make_shared<Type>( die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, dwarf->GetUID(attrs.type.Reference()), encoding_data_type, &attrs.decl, - clang_type, resolve_state); + clang_type, resolve_state, TypePayloadClang(GetOwningClangModule(die))); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); return type_sp; @@ -755,8 +729,7 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, if (type_sp) return type_sp; - DWARFDeclContext die_decl_ctx; - die.GetDWARFDeclContext(die_decl_ctx); + DWARFDeclContext die_decl_ctx = SymbolFileDWARF::GetDWARFDeclContext(die); type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx); @@ -818,27 +791,28 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, clang_type = m_ast.CreateEnumerationType( attrs.name.GetCString(), GetClangDeclContextContainingDIE(die, nullptr), - attrs.decl, enumerator_clang_type, attrs.is_scoped_enum); + GetOwningClangModule(die), attrs.decl, enumerator_clang_type, + attrs.is_scoped_enum); } else { - enumerator_clang_type = - m_ast.GetEnumerationIntegerType(clang_type.GetOpaqueQualType()); + enumerator_clang_type = m_ast.GetEnumerationIntegerType(clang_type); } - LinkDeclContextToDIE(ClangASTContext::GetDeclContextForType(clang_type), die); + LinkDeclContextToDIE(TypeSystemClang::GetDeclContextForType(clang_type), die); type_sp = std::make_shared<Type>( die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, dwarf->GetUID(attrs.type.Reference()), Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::ResolveState::Forward); + clang_type, Type::ResolveState::Forward, + TypePayloadClang(GetOwningClangModule(die))); - if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { + if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) { if (die.HasChildren()) { bool is_signed = false; enumerator_clang_type.IsIntegerType(is_signed); ParseChildEnumerators(clang_type, is_signed, type_sp->GetByteSize().getValueOr(0), die); } - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); } else { dwarf->GetObjectFile()->GetModule()->ReportError( "DWARF DIE at 0x%8.8x named \"%s\" was not able to start its " @@ -948,7 +922,7 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, if (complete_objc_class_type_sp) { CompilerType type_clang_forward_type = complete_objc_class_type_sp->GetForwardCompilerType(); - if (ClangASTContext::IsObjCObjectOrInterfaceType( + if (TypeSystemClang::IsObjCObjectOrInterfaceType( type_clang_forward_type)) class_opaque_type = type_clang_forward_type; } @@ -1053,7 +1027,7 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, } else { CompilerType class_opaque_type = class_type->GetForwardCompilerType(); - if (ClangASTContext::IsCXXClassType(class_opaque_type)) { + if (TypeSystemClang::IsCXXClassType(class_opaque_type)) { if (class_opaque_type.IsBeingDefined() || alternate_defn) { if (!is_static && !die.HasChildren()) { // We have a C++ member function with no children (this @@ -1198,27 +1172,38 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, } if (!function_decl) { + const char *name = attrs.name.GetCString(); + + // We currently generate function templates with template parameters in + // their name. In order to get closer to the AST that clang generates + // we want to strip these from the name when creating the AST. + if (attrs.mangled_name) { + llvm::ItaniumPartialDemangler D; + if (!D.partialDemangle(attrs.mangled_name)) + name = D.getFunctionBaseName(nullptr, nullptr); + } + // We just have a function that isn't part of a class function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, + GetOwningClangModule(die), name, clang_type, attrs.storage, attrs.is_inline); if (has_template_params) { - ClangASTContext::TemplateParameterInfos template_param_infos; + TypeSystemClang::TemplateParameterInfos template_param_infos; ParseTemplateParameterInfos(die, template_param_infos); template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, - attrs.is_inline); + GetOwningClangModule(die), attrs.name.GetCString(), clang_type, + attrs.storage, attrs.is_inline); clang::FunctionTemplateDecl *func_template_decl = m_ast.CreateFunctionTemplateDecl( - containing_decl_ctx, template_function_decl, - attrs.name.GetCString(), template_param_infos); + containing_decl_ctx, GetOwningClangModule(die), + template_function_decl, name, template_param_infos); m_ast.CreateFunctionTemplateSpecializationInfo( - function_decl, func_template_decl, template_param_infos); + template_function_decl, func_template_decl, template_param_infos); } lldbassert(function_decl); @@ -1278,44 +1263,7 @@ TypeSP DWARFASTParserClang::ParseArrayType(const DWARFDIE &die, if (attrs.byte_stride == 0 && attrs.bit_stride == 0) attrs.byte_stride = element_type->GetByteSize().getValueOr(0); CompilerType array_element_type = element_type->GetForwardCompilerType(); - - if (ClangASTContext::IsCXXClassType(array_element_type) && - !array_element_type.GetCompleteType()) { - ModuleSP module_sp = die.GetModule(); - if (module_sp) { - if (die.GetCU()->GetProducer() == eProducerClang) - module_sp->ReportError( - "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " - "class/union/struct element type DIE 0x%8.8x that is a " - "forward declaration, not a complete definition.\nTry " - "compiling the source file with -fstandalone-debug or " - "disable -gmodules", - die.GetOffset(), type_die.GetOffset()); - else - module_sp->ReportError( - "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " - "class/union/struct element type DIE 0x%8.8x that is a " - "forward declaration, not a complete definition.\nPlease " - "file a bug against the compiler and include the " - "preprocessed output for %s", - die.GetOffset(), type_die.GetOffset(), GetUnitName(die).c_str()); - } - - // We have no choice other than to pretend that the element class - // type is complete. If we don't do this, clang will crash when - // trying to layout the class. Since we provide layout - // assistance, all ivars in this class and other classes will be - // fine, this is the best we can do short of crashing. - if (ClangASTContext::StartTagDeclarationDefinition(array_element_type)) { - ClangASTContext::CompleteTagDeclarationDefinition(array_element_type); - } else { - module_sp->ReportError("DWARF DIE at 0x%8.8x was not able to " - "start its definition.\nPlease file a " - "bug and attach the file at the start " - "of this error message", - type_die.GetOffset()); - } - } + CompleteType(array_element_type); uint64_t array_element_bit_stride = attrs.byte_stride * 8 + attrs.bit_stride; @@ -1357,7 +1305,7 @@ TypeSP DWARFASTParserClang::ParsePointerToMemberType( CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType(); CompilerType class_clang_type = class_type->GetLayoutCompilerType(); - CompilerType clang_type = ClangASTContext::CreateMemberPointerType( + CompilerType clang_type = TypeSystemClang::CreateMemberPointerType( class_clang_type, pointee_clang_type); if (llvm::Optional<uint64_t> clang_type_size = @@ -1370,6 +1318,28 @@ TypeSP DWARFASTParserClang::ParsePointerToMemberType( return nullptr; } +void DWARFASTParserClang::CompleteType(CompilerType type) { + // Technically, enums can be incomplete too, but we don't handle those as they + // are emitted even under -flimit-debug-info. + if (!TypeSystemClang::IsCXXClassType(type)) + return; + + if (type.GetCompleteType()) + return; + + // No complete definition in this module. Mark the class as complete to + // satisfy local ast invariants, but make a note of the fact that + // it is not _really_ complete so we can later search for a definition in a + // different module. + // Since we provide layout assistance, layouts of types containing this class + // will be correct even if we are not able to find the definition elsewhere. + bool started = TypeSystemClang::StartTagDeclarationDefinition(type); + lldbassert(started && "Unable to start a class type definition."); + TypeSystemClang::CompleteTagDeclarationDefinition(type); + const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type); + m_ast.GetMetadata(td)->SetIsForcefullyCompleted(); +} + TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( const SymbolContext &sc, const DWARFDIE &die, TypeSP type_sp) { if (!type_sp) @@ -1412,7 +1382,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, CompilerType clang_type; const dw_tag_t tag = die.Tag(); SymbolFileDWARF *dwarf = die.GetDWARF(); - LanguageType cu_language = die.GetLanguage(); + LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU()); Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_TYPE_COMPLETION | DWARF_LOG_LOOKUPS); @@ -1544,8 +1514,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, if (type_sp) return type_sp; - DWARFDeclContext die_decl_ctx; - die.GetDWARFDeclContext(die_decl_ctx); + DWARFDeclContext die_decl_ctx = SymbolFileDWARF::GetDWARFDeclContext(die); // type_sp = FindDefinitionTypeForDIE (dwarf_cu, die, // type_name_const_str); @@ -1611,12 +1580,12 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); if (attrs.name.GetStringRef().contains('<')) { - ClangASTContext::TemplateParameterInfos template_param_infos; + TypeSystemClang::TemplateParameterInfos template_param_infos; if (ParseTemplateParameterInfos(die, template_param_infos)) { clang::ClassTemplateDecl *class_template_decl = - m_ast.ParseClassTemplateDecl(decl_ctx, attrs.accessibility, - attrs.name.GetCString(), tag_decl_kind, - template_param_infos); + m_ast.ParseClassTemplateDecl( + decl_ctx, GetOwningClangModule(die), attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, template_param_infos); if (!class_template_decl) { if (log) { dwarf->GetObjectFile()->GetModule()->LogMessage( @@ -1631,8 +1600,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, clang::ClassTemplateSpecializationDecl *class_specialization_decl = m_ast.CreateClassTemplateSpecializationDecl( - decl_ctx, class_template_decl, tag_decl_kind, - template_param_infos); + decl_ctx, GetOwningClangModule(die), class_template_decl, + tag_decl_kind, template_param_infos); clang_type = m_ast.CreateClassTemplateSpecializationType( class_specialization_decl); clang_type_was_created = true; @@ -1645,8 +1614,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, if (!clang_type_was_created) { clang_type_was_created = true; clang_type = m_ast.CreateRecordType( - decl_ctx, attrs.accessibility, attrs.name.GetCString(), tag_decl_kind, - attrs.class_language, &metadata, attrs.exports_symbols); + decl_ctx, GetOwningClangModule(die), attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, attrs.class_language, + &metadata, attrs.exports_symbols); } } @@ -1654,12 +1624,11 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, // parameters in any class methods need it for the clang types for // function prototypes. LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); - type_sp = std::make_shared<Type>(die.GetID(), dwarf, attrs.name, - attrs.byte_size, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::ResolveState::Forward); - - type_sp->SetIsCompleteObjCClass(attrs.is_complete_objc_class); + type_sp = std::make_shared<Type>( + die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, + Type::ResolveState::Forward, + TypePayloadClang(OptionalClangModuleID(), attrs.is_complete_objc_class)); // Add our type to the unique type map so we don't end up creating many // copies of the same type over and over in the ASTContext for our @@ -1705,8 +1674,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, // these child definitions. if (!die.HasChildren()) { // No children for this struct/union/class, lets finish it - if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) { + TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); } else { dwarf->GetObjectFile()->GetModule()->ReportError( "DWARF DIE at 0x%8.8x named \"%s\" was not able to start its " @@ -1718,7 +1687,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, if (tag == DW_TAG_structure_type) // this only applies in C { clang::RecordDecl *record_decl = - ClangASTContext::GetAsRecordDecl(clang_type); + TypeSystemClang::GetAsRecordDecl(clang_type); if (record_decl) { GetClangASTImporter().SetRecordLayout( @@ -1736,7 +1705,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, if (attrs.class_language != eLanguageTypeObjC && attrs.class_language != eLanguageTypeObjC_plus_plus) - ClangASTContext::StartTagDeclarationDefinition(clang_type); + TypeSystemClang::StartTagDeclarationDefinition(clang_type); // Leave this as a forward declaration until we need to know the // details of the type. lldb_private::Type will automatically call @@ -1752,9 +1721,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, // binaries. dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = clang_type.GetOpaqueQualType(); - dwarf->GetForwardDeclClangTypeToDie() - [ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType()] = - die.GetID(); + dwarf->GetForwardDeclClangTypeToDie().try_emplace( + ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(), + *die.GetDIERef()); m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); } } @@ -1799,7 +1768,7 @@ public: m_property_getter_name(property_getter_name), m_property_attributes(property_attributes) { if (metadata != nullptr) { - m_metadata_up.reset(new ClangASTMetadata()); + m_metadata_up = std::make_unique<ClangASTMetadata>(); *m_metadata_up = *metadata; } } @@ -1819,14 +1788,14 @@ public: m_property_attributes = rhs.m_property_attributes; if (rhs.m_metadata_up) { - m_metadata_up.reset(new ClangASTMetadata()); + m_metadata_up = std::make_unique<ClangASTMetadata>(); *m_metadata_up = *rhs.m_metadata_up; } return *this; } bool Finalize() { - return ClangASTContext::AddObjCClassProperty( + return TypeSystemClang::AddObjCClassProperty( m_class_opaque_type, m_property_name, m_property_opaque_type, m_ivar_decl, m_property_setter_name, m_property_getter_name, m_property_attributes, m_metadata_up.get()); @@ -1845,14 +1814,14 @@ private: bool DWARFASTParserClang::ParseTemplateDIE( const DWARFDIE &die, - ClangASTContext::TemplateParameterInfos &template_param_infos) { + TypeSystemClang::TemplateParameterInfos &template_param_infos) { const dw_tag_t tag = die.Tag(); bool is_template_template_argument = false; switch (tag) { case DW_TAG_GNU_template_parameter_pack: { - template_param_infos.packed_args.reset( - new ClangASTContext::TemplateParameterInfos); + template_param_infos.packed_args = + std::make_unique<TypeSystemClang::TemplateParameterInfos>(); for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid(); child_die = child_die.GetSibling()) { if (!ParseTemplateDIE(child_die, *template_param_infos.packed_args)) @@ -1954,7 +1923,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( bool DWARFASTParserClang::ParseTemplateParameterInfos( const DWARFDIE &parent_die, - ClangASTContext::TemplateParameterInfos &template_param_infos) { + TypeSystemClang::TemplateParameterInfos &template_param_infos) { if (!parent_die) return false; @@ -1988,141 +1957,102 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, ClangASTImporter::LayoutInfo layout_info; - { - if (die.HasChildren()) { - LanguageType class_language = eLanguageTypeUnknown; - if (ClangASTContext::IsObjCObjectOrInterfaceType(clang_type)) { - class_language = eLanguageTypeObjC; - // For objective C we don't start the definition when the class is - // created. - ClangASTContext::StartTagDeclarationDefinition(clang_type); - } - - int tag_decl_kind = -1; - AccessType default_accessibility = eAccessNone; - if (tag == DW_TAG_structure_type) { - tag_decl_kind = clang::TTK_Struct; - default_accessibility = eAccessPublic; - } else if (tag == DW_TAG_union_type) { - tag_decl_kind = clang::TTK_Union; - default_accessibility = eAccessPublic; - } else if (tag == DW_TAG_class_type) { - tag_decl_kind = clang::TTK_Class; - default_accessibility = eAccessPrivate; - } - - std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; - std::vector<int> member_accessibilities; - bool is_a_class = false; - // Parse members and base classes first - std::vector<DWARFDIE> member_function_dies; - - DelayedPropertyList delayed_properties; - ParseChildMembers(die, clang_type, class_language, bases, - member_accessibilities, member_function_dies, - delayed_properties, default_accessibility, is_a_class, - layout_info); - - // Now parse any methods if there were any... - for (const DWARFDIE &die : member_function_dies) - dwarf->ResolveType(die); - - if (class_language == eLanguageTypeObjC) { - ConstString class_name(clang_type.GetTypeName()); - if (class_name) { - DIEArray method_die_offsets; - dwarf->GetObjCMethodDIEOffsets(class_name, method_die_offsets); - - if (!method_die_offsets.empty()) { - DWARFDebugInfo *debug_info = dwarf->DebugInfo(); - - const size_t num_matches = method_die_offsets.size(); - for (size_t i = 0; i < num_matches; ++i) { - const DIERef &die_ref = method_die_offsets[i]; - DWARFDIE method_die = debug_info->GetDIE(die_ref); - - if (method_die) - method_die.ResolveType(); - } - } - - for (DelayedPropertyList::iterator pi = delayed_properties.begin(), - pe = delayed_properties.end(); - pi != pe; ++pi) - pi->Finalize(); - } - } + if (die.HasChildren()) { + const bool type_is_objc_object_or_interface = + TypeSystemClang::IsObjCObjectOrInterfaceType(clang_type); + if (type_is_objc_object_or_interface) { + // For objective C we don't start the definition when the class is + // created. + TypeSystemClang::StartTagDeclarationDefinition(clang_type); + } + + int tag_decl_kind = -1; + AccessType default_accessibility = eAccessNone; + if (tag == DW_TAG_structure_type) { + tag_decl_kind = clang::TTK_Struct; + default_accessibility = eAccessPublic; + } else if (tag == DW_TAG_union_type) { + tag_decl_kind = clang::TTK_Union; + default_accessibility = eAccessPublic; + } else if (tag == DW_TAG_class_type) { + tag_decl_kind = clang::TTK_Class; + default_accessibility = eAccessPrivate; + } + + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; + std::vector<int> member_accessibilities; + bool is_a_class = false; + // Parse members and base classes first + std::vector<DWARFDIE> member_function_dies; + + DelayedPropertyList delayed_properties; + ParseChildMembers(die, clang_type, bases, member_accessibilities, + member_function_dies, delayed_properties, + default_accessibility, is_a_class, layout_info); + + // Now parse any methods if there were any... + for (const DWARFDIE &die : member_function_dies) + dwarf->ResolveType(die); + + if (type_is_objc_object_or_interface) { + ConstString class_name(clang_type.GetTypeName()); + if (class_name) { + dwarf->GetObjCMethods(class_name, [&](DWARFDIE method_die) { + method_die.ResolveType(); + return true; + }); - // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we - // need to tell the clang type it is actually a class. - if (class_language != eLanguageTypeObjC) { - if (is_a_class && tag_decl_kind != clang::TTK_Class) - m_ast.SetTagTypeKind(ClangUtil::GetQualType(clang_type), - clang::TTK_Class); + for (DelayedPropertyList::iterator pi = delayed_properties.begin(), + pe = delayed_properties.end(); + pi != pe; ++pi) + pi->Finalize(); } + } - // Since DW_TAG_structure_type gets used for both classes and - // structures, we may need to set any DW_TAG_member fields to have a - // "private" access if none was specified. When we parsed the child - // members we tracked that actual accessibility value for each - // DW_TAG_member in the "member_accessibilities" array. If the value - // for the member is zero, then it was set to the - // "default_accessibility" which for structs was "public". Below we - // correct this by setting any fields to "private" that weren't - // correctly set. - if (is_a_class && !member_accessibilities.empty()) { - // This is a class and all members that didn't have their access - // specified are private. - m_ast.SetDefaultAccessForRecordFields( - m_ast.GetAsRecordDecl(clang_type), eAccessPrivate, - &member_accessibilities.front(), member_accessibilities.size()); + // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we + // need to tell the clang type it is actually a class. + if (!type_is_objc_object_or_interface) { + if (is_a_class && tag_decl_kind != clang::TTK_Class) + m_ast.SetTagTypeKind(ClangUtil::GetQualType(clang_type), + clang::TTK_Class); + } + + // Since DW_TAG_structure_type gets used for both classes and + // structures, we may need to set any DW_TAG_member fields to have a + // "private" access if none was specified. When we parsed the child + // members we tracked that actual accessibility value for each + // DW_TAG_member in the "member_accessibilities" array. If the value + // for the member is zero, then it was set to the + // "default_accessibility" which for structs was "public". Below we + // correct this by setting any fields to "private" that weren't + // correctly set. + if (is_a_class && !member_accessibilities.empty()) { + // This is a class and all members that didn't have their access + // specified are private. + m_ast.SetDefaultAccessForRecordFields( + m_ast.GetAsRecordDecl(clang_type), eAccessPrivate, + &member_accessibilities.front(), member_accessibilities.size()); + } + + if (!bases.empty()) { + // Make sure all base classes refer to complete types and not forward + // declarations. If we don't do this, clang will crash with an + // assertion in the call to clang_type.TransferBaseClasses() + for (const auto &base_class : bases) { + clang::TypeSourceInfo *type_source_info = + base_class->getTypeSourceInfo(); + if (type_source_info) + CompleteType(m_ast.GetType(type_source_info->getType())); } - if (!bases.empty()) { - // Make sure all base classes refer to complete types and not forward - // declarations. If we don't do this, clang will crash with an - // assertion in the call to clang_type.TransferBaseClasses() - for (const auto &base_class : bases) { - clang::TypeSourceInfo *type_source_info = - base_class->getTypeSourceInfo(); - if (type_source_info) { - CompilerType base_class_type = - m_ast.GetType(type_source_info->getType()); - if (!base_class_type.GetCompleteType()) { - auto module = dwarf->GetObjectFile()->GetModule(); - module->ReportError(":: Class '%s' has a base class '%s' which " - "does not have a complete definition.", - die.GetName(), - base_class_type.GetTypeName().GetCString()); - if (die.GetCU()->GetProducer() == eProducerClang) - module->ReportError(":: Try compiling the source file with " - "-fstandalone-debug."); - - // We have no choice other than to pretend that the base class - // is complete. If we don't do this, clang will crash when we - // call setBases() inside of - // "clang_type.TransferBaseClasses()" below. Since we - // provide layout assistance, all ivars in this class and other - // classes will be fine, this is the best we can do short of - // crashing. - if (ClangASTContext::StartTagDeclarationDefinition( - base_class_type)) { - ClangASTContext::CompleteTagDeclarationDefinition( - base_class_type); - } - } - } - } - - m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), - std::move(bases)); - } + m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), + std::move(bases)); } } m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType()); - ClangASTContext::BuildIndirectFields(clang_type); - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + TypeSystemClang::BuildIndirectFields(clang_type); + TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); if (!layout_info.field_offsets.empty() || !layout_info.base_offsets.empty() || !layout_info.vbase_offsets.empty()) { @@ -2144,14 +2074,14 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, bool DWARFASTParserClang::CompleteEnumType(const DWARFDIE &die, lldb_private::Type *type, CompilerType &clang_type) { - if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { + if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) { if (die.HasChildren()) { bool is_signed = false; clang_type.IsIntegerType(is_signed); ParseChildEnumerators(clang_type, is_signed, type->GetByteSize().getValueOr(0), die); } - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); } return (bool)clang_type; } @@ -2211,7 +2141,7 @@ void DWARFASTParserClang::EnsureAllDIEsInDeclContextHaveBeenParsed( CompilerDecl DWARFASTParserClang::GetDeclForUIDFromDWARF(const DWARFDIE &die) { clang::Decl *clang_decl = GetClangDeclForDIE(die); if (clang_decl != nullptr) - return CompilerDecl(&m_ast, clang_decl); + return m_ast.GetCompilerDecl(clang_decl); return CompilerDecl(); } @@ -2340,9 +2270,11 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, func_name.SetValue(ConstString(mangled), true); else if ((die.GetParent().Tag() == DW_TAG_compile_unit || die.GetParent().Tag() == DW_TAG_partial_unit) && - Language::LanguageIsCPlusPlus(die.GetLanguage()) && - !Language::LanguageIsObjC(die.GetLanguage()) && name && - strcmp(name, "main") != 0) { + Language::LanguageIsCPlusPlus( + SymbolFileDWARF::GetLanguage(*die.GetCU())) && + !Language::LanguageIsObjC( + SymbolFileDWARF::GetLanguage(*die.GetCU())) && + name && strcmp(name, "main") != 0) { // If the mangled name is not present in the DWARF, generate the // demangled name using the decl context. We skip if the function is // "main" as its name is never mangled. @@ -2352,10 +2284,9 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, unsigned type_quals = 0; std::vector<CompilerType> param_types; std::vector<clang::ParmVarDecl *> param_decls; - DWARFDeclContext decl_ctx; StreamString sstr; - die.GetDWARFDeclContext(decl_ctx); + DWARFDeclContext decl_ctx = SymbolFileDWARF::GetDWARFDeclContext(die); sstr << decl_ctx.GetQualifiedName(); clang::DeclContext *containing_decl_ctx = @@ -2382,8 +2313,8 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, FunctionSP func_sp; std::unique_ptr<Declaration> decl_up; if (decl_file != 0 || decl_line != 0 || decl_column != 0) - decl_up.reset(new Declaration(die.GetCU()->GetFile(decl_file), - decl_line, decl_column)); + decl_up = std::make_unique<Declaration>(die.GetCU()->GetFile(decl_file), + decl_line, decl_column); SymbolFileDWARF *dwarf = die.GetDWARF(); // Supply the type _only_ if it has already been parsed @@ -2413,13 +2344,12 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, void DWARFASTParserClang::ParseSingleMember( const DWARFDIE &die, const DWARFDIE &parent_die, - lldb_private::CompilerType &class_clang_type, - const lldb::LanguageType class_language, + const lldb_private::CompilerType &class_clang_type, std::vector<int> &member_accessibilities, - lldb::AccessType &default_accessibility, + lldb::AccessType default_accessibility, DelayedPropertyList &delayed_properties, lldb_private::ClangASTImporter::LayoutInfo &layout_info, - BitfieldInfo &last_field_info) { + FieldInfo &last_field_info) { ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); const dw_tag_t tag = die.Tag(); // Get the parent byte size so we can verify any members will fit @@ -2430,453 +2360,400 @@ void DWARFASTParserClang::ParseSingleMember( DWARFAttributes attributes; const size_t num_attributes = die.GetAttributes(attributes); - if (num_attributes > 0) { - const char *name = nullptr; - const char *prop_name = nullptr; - const char *prop_getter_name = nullptr; - const char *prop_setter_name = nullptr; - uint32_t prop_attributes = 0; - - bool is_artificial = false; - DWARFFormValue encoding_form; - AccessType accessibility = eAccessNone; - uint32_t member_byte_offset = - (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX; - llvm::Optional<uint64_t> byte_size; - int64_t bit_offset = 0; - uint64_t data_bit_offset = UINT64_MAX; - size_t bit_size = 0; - bool is_external = - false; // On DW_TAG_members, this means the member is static - uint32_t i; - for (i = 0; i < num_attributes && !is_artificial; ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - name = form_value.AsCString(); - break; - case DW_AT_type: - encoding_form = form_value; - break; - case DW_AT_bit_offset: - bit_offset = form_value.Signed(); - break; - case DW_AT_bit_size: - bit_size = form_value.Unsigned(); - break; - case DW_AT_byte_size: - byte_size = form_value.Unsigned(); - break; - case DW_AT_data_bit_offset: - 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 (num_attributes == 0) + return; + + const char *name = nullptr; + const char *prop_name = nullptr; + const char *prop_getter_name = nullptr; + const char *prop_setter_name = nullptr; + uint32_t prop_attributes = 0; + + bool is_artificial = false; + DWARFFormValue encoding_form; + AccessType accessibility = eAccessNone; + uint32_t member_byte_offset = + (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX; + llvm::Optional<uint64_t> byte_size; + int64_t bit_offset = 0; + uint64_t data_bit_offset = UINT64_MAX; + size_t bit_size = 0; + bool is_external = + false; // On DW_TAG_members, this means the member is static + uint32_t i; + for (i = 0; i < num_attributes && !is_artificial; ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + // DW_AT_data_member_location indicates the byte offset of the + // word from the base address of the structure. + // + // DW_AT_bit_offset indicates how many bits into the word + // (according to the host endianness) the low-order bit of the + // field starts. AT_bit_offset can be negative. + // + // DW_AT_bit_size indicates the size of the field in bits. + switch (attr) { + case DW_AT_name: + name = form_value.AsCString(); + break; + case DW_AT_type: + encoding_form = form_value; + break; + case DW_AT_bit_offset: + bit_offset = form_value.Signed(); + break; + case DW_AT_bit_size: + bit_size = form_value.Unsigned(); + break; + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + break; + case DW_AT_data_bit_offset: + 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(); } - break; + } 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(); + } + break; - case DW_AT_accessibility: - accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); - break; - case DW_AT_artificial: - is_artificial = form_value.Boolean(); - break; - case DW_AT_APPLE_property_name: - prop_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_getter: - prop_getter_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_setter: - prop_setter_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_attribute: - prop_attributes = form_value.Unsigned(); - break; - case DW_AT_external: - is_external = form_value.Boolean(); - break; + case DW_AT_accessibility: + accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); + break; + case DW_AT_artificial: + is_artificial = form_value.Boolean(); + break; + case DW_AT_APPLE_property_name: + prop_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_getter: + prop_getter_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_setter: + prop_setter_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_attribute: + prop_attributes = form_value.Unsigned(); + break; + case DW_AT_external: + is_external = form_value.Boolean(); + break; - default: - case DW_AT_declaration: - case DW_AT_description: - case DW_AT_mutable: - case DW_AT_visibility: - case DW_AT_sibling: - break; - } + default: + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_mutable: + case DW_AT_visibility: + case DW_AT_sibling: + break; } } + } - if (prop_name) { - ConstString fixed_setter; + if (prop_name) { + ConstString fixed_setter; - // Check if the property getter/setter were provided as full names. - // We want basenames, so we extract them. + // Check if the property getter/setter were provided as full names. + // We want basenames, so we extract them. - if (prop_getter_name && prop_getter_name[0] == '-') { - ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true); - prop_getter_name = prop_getter_method.GetSelector().GetCString(); - } + if (prop_getter_name && prop_getter_name[0] == '-') { + ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true); + prop_getter_name = prop_getter_method.GetSelector().GetCString(); + } - if (prop_setter_name && prop_setter_name[0] == '-') { - ObjCLanguage::MethodName prop_setter_method(prop_setter_name, true); - prop_setter_name = prop_setter_method.GetSelector().GetCString(); - } + if (prop_setter_name && prop_setter_name[0] == '-') { + ObjCLanguage::MethodName prop_setter_method(prop_setter_name, true); + prop_setter_name = prop_setter_method.GetSelector().GetCString(); + } - // If the names haven't been provided, they need to be filled in. + // If the names haven't been provided, they need to be filled in. - if (!prop_getter_name) { - prop_getter_name = prop_name; - } - if (!prop_setter_name && prop_name[0] && - !(prop_attributes & DW_APPLE_PROPERTY_readonly)) { - StreamString ss; + if (!prop_getter_name) { + prop_getter_name = prop_name; + } + if (!prop_setter_name && prop_name[0] && + !(prop_attributes & DW_APPLE_PROPERTY_readonly)) { + StreamString ss; - ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]); + ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]); - fixed_setter.SetString(ss.GetString()); - prop_setter_name = fixed_setter.GetCString(); - } + fixed_setter.SetString(ss.GetString()); + prop_setter_name = fixed_setter.GetCString(); } + } - // Clang has a DWARF generation bug where sometimes it represents - // fields that are references with bad byte size and bit size/offset - // information such as: - // - // DW_AT_byte_size( 0x00 ) - // DW_AT_bit_size( 0x40 ) - // DW_AT_bit_offset( 0xffffffffffffffc0 ) - // - // So check the bit offset to make sure it is sane, and if the values - // are not sane, remove them. If we don't do this then we will end up - // with a crash if we try to use this type in an expression when clang - // becomes unhappy with its recycled debug info. + // Clang has a DWARF generation bug where sometimes it represents + // fields that are references with bad byte size and bit size/offset + // information such as: + // + // DW_AT_byte_size( 0x00 ) + // DW_AT_bit_size( 0x40 ) + // DW_AT_bit_offset( 0xffffffffffffffc0 ) + // + // So check the bit offset to make sure it is sane, and if the values + // are not sane, remove them. If we don't do this then we will end up + // with a crash if we try to use this type in an expression when clang + // becomes unhappy with its recycled debug info. + + if (byte_size.getValueOr(0) == 0 && bit_offset < 0) { + bit_size = 0; + bit_offset = 0; + } + + 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) + accessibility = eAccessNone; - if (byte_size.getValueOr(0) == 0 && bit_offset < 0) { - bit_size = 0; - bit_offset = 0; + // Handle static members + if (is_external && member_byte_offset == UINT32_MAX) { + Type *var_type = die.ResolveTypeUID(encoding_form.Reference()); + + if (var_type) { + if (accessibility == eAccessNone) + accessibility = eAccessPublic; + TypeSystemClang::AddVariableToRecordType( + class_clang_type, name, var_type->GetLayoutCompilerType(), + accessibility); } + return; + } - // FIXME: Make Clang ignore Objective-C accessibility for expressions - if (class_language == eLanguageTypeObjC || - class_language == eLanguageTypeObjC_plus_plus) - accessibility = eAccessNone; + if (!is_artificial) { + Type *member_type = die.ResolveTypeUID(encoding_form.Reference()); - // Handle static members - if (is_external && member_byte_offset == UINT32_MAX) { - Type *var_type = die.ResolveTypeUID(encoding_form.Reference()); + clang::FieldDecl *field_decl = nullptr; + const uint64_t character_width = 8; + const uint64_t word_width = 32; + if (tag == DW_TAG_member) { + if (member_type) { + CompilerType member_clang_type = member_type->GetLayoutCompilerType(); - if (var_type) { if (accessibility == eAccessNone) - accessibility = eAccessPublic; - ClangASTContext::AddVariableToRecordType( - class_clang_type, name, var_type->GetLayoutCompilerType(), - accessibility); - } - return; - } - - if (!is_artificial) { - Type *member_type = die.ResolveTypeUID(encoding_form.Reference()); - - clang::FieldDecl *field_decl = nullptr; - if (tag == DW_TAG_member) { - if (member_type) { - if (accessibility == eAccessNone) - accessibility = default_accessibility; - member_accessibilities.push_back(accessibility); - - uint64_t field_bit_offset = - (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); - if (bit_size > 0) { - - BitfieldInfo this_field_info; - this_field_info.bit_offset = field_bit_offset; - this_field_info.bit_size = bit_size; - - ///////////////////////////////////////////////////////////// - // How to locate a field given the DWARF debug information - // - // AT_byte_size indicates the size of the word in which the bit - // offset must be interpreted. - // - // AT_data_member_location indicates the byte offset of the - // word from the base address of the structure. - // - // AT_bit_offset indicates how many bits into the word - // (according to the host endianness) the low-order bit of the - // field starts. AT_bit_offset can be negative. - // - // AT_bit_size indicates the size of the field in bits. - ///////////////////////////////////////////////////////////// - - if (data_bit_offset != UINT64_MAX) { - this_field_info.bit_offset = data_bit_offset; - } else { - if (!byte_size) - byte_size = member_type->GetByteSize(); + accessibility = default_accessibility; + member_accessibilities.push_back(accessibility); - ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); - if (objfile->GetByteOrder() == eByteOrderLittle) { - this_field_info.bit_offset += byte_size.getValueOr(0) * 8; - this_field_info.bit_offset -= (bit_offset + bit_size); - } else { - this_field_info.bit_offset += bit_offset; - } + uint64_t field_bit_offset = + (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); + + if (bit_size > 0) { + FieldInfo this_field_info; + this_field_info.bit_offset = field_bit_offset; + this_field_info.bit_size = bit_size; + + if (data_bit_offset != UINT64_MAX) { + this_field_info.bit_offset = data_bit_offset; + } else { + if (!byte_size) + byte_size = member_type->GetByteSize(); + + ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); + if (objfile->GetByteOrder() == eByteOrderLittle) { + this_field_info.bit_offset += byte_size.getValueOr(0) * 8; + this_field_info.bit_offset -= (bit_offset + bit_size); + } else { + this_field_info.bit_offset += bit_offset; } + } + + if ((this_field_info.bit_offset >= parent_bit_size) || + (last_field_info.IsBitfield() && + !last_field_info.NextBitfieldOffsetIsValid( + this_field_info.bit_offset))) { + ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); + objfile->GetModule()->ReportWarning( + "0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid " + "bit offset (0x%8.8" PRIx64 + ") member will be ignored. Please file a bug against the " + "compiler and include the preprocessed output for %s\n", + die.GetID(), DW_TAG_value_to_name(tag), name, + this_field_info.bit_offset, GetUnitName(parent_die).c_str()); + return; + } + + // Update the field bit offset we will report for layout + field_bit_offset = this_field_info.bit_offset; + + // Objective-C has invalid DW_AT_bit_offset values in older + // versions of clang, so we have to be careful and only insert + // unnamed bitfields if we have a new enough clang. + bool detect_unnamed_bitfields = true; + + if (class_is_objc_object_or_interface) + detect_unnamed_bitfields = + die.GetCU()->Supports_unnamed_objc_bitfields(); - if ((this_field_info.bit_offset >= parent_bit_size) || - !last_field_info.NextBitfieldOffsetIsValid( - this_field_info.bit_offset)) { - ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); - objfile->GetModule()->ReportWarning( - "0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid " - "bit offset (0x%8.8" PRIx64 - ") member will be ignored. Please file a bug against the " - "compiler and include the preprocessed output for %s\n", - die.GetID(), DW_TAG_value_to_name(tag), name, - this_field_info.bit_offset, GetUnitName(parent_die).c_str()); - this_field_info.Clear(); - return; + if (detect_unnamed_bitfields) { + clang::Optional<FieldInfo> unnamed_field_info; + uint64_t last_field_end = 0; + + last_field_end = + last_field_info.bit_offset + last_field_info.bit_size; + + if (!last_field_info.IsBitfield()) { + // The last field was not a bit-field... + // but if it did take up the entire word then we need to extend + // last_field_end so the bit-field does not step into the last + // fields padding. + if (last_field_end != 0 && ((last_field_end % word_width) != 0)) + last_field_end += word_width - (last_field_end % word_width); } - // Update the field bit offset we will report for layout - field_bit_offset = this_field_info.bit_offset; - - // If the member to be emitted did not start on a character - // boundary and there is empty space between the last field and - // this one, then we need to emit an anonymous member filling - // up the space up to its start. There are three cases here: - // - // 1 If the previous member ended on a character boundary, then - // we can emit an - // anonymous member starting at the most recent character - // boundary. - // - // 2 If the previous member did not end on a character boundary - // and the distance - // from the end of the previous member to the current member - // is less than a - // word width, then we can emit an anonymous member starting - // right after the - // previous member and right before this member. - // - // 3 If the previous member did not end on a character boundary - // and the distance - // from the end of the previous member to the current member - // is greater than - // or equal a word width, then we act as in Case 1. - - const uint64_t character_width = 8; - const uint64_t word_width = 32; - - // Objective-C has invalid DW_AT_bit_offset values in older - // versions of clang, so we have to be careful and only insert - // unnamed bitfields if we have a new enough clang. - bool detect_unnamed_bitfields = true; - - if (class_language == eLanguageTypeObjC || - class_language == eLanguageTypeObjC_plus_plus) - detect_unnamed_bitfields = - die.GetCU()->Supports_unnamed_objc_bitfields(); - - if (detect_unnamed_bitfields) { - BitfieldInfo anon_field_info; - - if ((this_field_info.bit_offset % character_width) != - 0) // not char aligned - { - uint64_t last_field_end = 0; - - if (last_field_info.IsValid()) - last_field_end = - last_field_info.bit_offset + last_field_info.bit_size; - - if (this_field_info.bit_offset != last_field_end) { - if (((last_field_end % character_width) == 0) || // case 1 - (this_field_info.bit_offset - last_field_end >= - word_width)) // case 3 - { - anon_field_info.bit_size = - this_field_info.bit_offset % character_width; - anon_field_info.bit_offset = - this_field_info.bit_offset - anon_field_info.bit_size; - } else // case 2 - { - anon_field_info.bit_size = - this_field_info.bit_offset - last_field_end; - anon_field_info.bit_offset = last_field_end; - } - } - } + // If we have a gap between the last_field_end and the current + // field we have an unnamed bit-field. + // If we have a base class, we assume there is no unnamed + // bit-field if this is the first field since the gap can be + // attributed to the members from the base class. This assumption + // is not correct if the first field of the derived class is + // indeed an unnamed bit-field. We currently do not have the + // machinary to track the offset of the last field of classes we + // have seen before, so we are not handling this case. + if (this_field_info.bit_offset != last_field_end && + this_field_info.bit_offset > last_field_end && + !(last_field_info.bit_offset == 0 && + last_field_info.bit_size == 0 && + layout_info.base_offsets.size() != 0)) { + unnamed_field_info = FieldInfo{}; + unnamed_field_info->bit_size = + this_field_info.bit_offset - last_field_end; + unnamed_field_info->bit_offset = last_field_end; + } - if (anon_field_info.IsValid()) { - clang::FieldDecl *unnamed_bitfield_decl = - ClangASTContext::AddFieldToRecordType( - class_clang_type, llvm::StringRef(), - m_ast.GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, - word_width), - accessibility, anon_field_info.bit_size); + if (unnamed_field_info) { + clang::FieldDecl *unnamed_bitfield_decl = + TypeSystemClang::AddFieldToRecordType( + class_clang_type, llvm::StringRef(), + m_ast.GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, + word_width), + accessibility, unnamed_field_info->bit_size); - layout_info.field_offsets.insert(std::make_pair( - unnamed_bitfield_decl, anon_field_info.bit_offset)); - } + layout_info.field_offsets.insert(std::make_pair( + unnamed_bitfield_decl, unnamed_field_info->bit_offset)); } - last_field_info = this_field_info; - } else { - last_field_info.Clear(); } - CompilerType member_clang_type = member_type->GetLayoutCompilerType(); - if (!member_clang_type.IsCompleteType()) - 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]. - - CompilerType member_array_element_type; - uint64_t member_array_size; - bool member_array_is_incomplete; - - if (member_clang_type.IsArrayType(&member_array_element_type, - &member_array_size, - &member_array_is_incomplete) && - !member_array_is_incomplete) { - uint64_t parent_byte_size = - parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, - UINT64_MAX); - - if (member_byte_offset >= parent_byte_size) { - if (member_array_size != 1 && - (member_array_size != 0 || - member_byte_offset > parent_byte_size)) { - module_sp->ReportError( - "0x%8.8" PRIx64 - ": DW_TAG_member '%s' refers to type 0x%8.8x" - " which extends beyond the bounds of 0x%8.8" PRIx64, - die.GetID(), name, encoding_form.Reference().GetOffset(), - parent_die.GetID()); - } + last_field_info = this_field_info; + last_field_info.SetIsBitfield(true); + } else { + last_field_info.bit_offset = field_bit_offset; - member_clang_type = - m_ast.CreateArrayType(member_array_element_type, 0, false); - } - } + if (llvm::Optional<uint64_t> clang_type_size = + member_clang_type.GetByteSize(nullptr)) { + last_field_info.bit_size = *clang_type_size * character_width; } - if (ClangASTContext::IsCXXClassType(member_clang_type) && - !member_clang_type.GetCompleteType()) { - if (die.GetCU()->GetProducer() == eProducerClang) - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type is a forward declaration, not a " - "complete definition.\nTry compiling the source file " - "with -fstandalone-debug", - parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), - name); - else - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type is a forward declaration, not a " - "complete definition.\nPlease file a bug against the " - "compiler and include the preprocessed output for %s", - parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), - name, GetUnitName(parent_die).c_str()); - // We have no choice other than to pretend that the member - // class is complete. If we don't do this, clang will crash - // when trying to layout the class. Since we provide layout - // assistance, all ivars in this class and other classes will - // be fine, this is the best we can do short of crashing. - if (ClangASTContext::StartTagDeclarationDefinition( - member_clang_type)) { - ClangASTContext::CompleteTagDeclarationDefinition( - member_clang_type); - } else { - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type claims to be a C++ class but we " - "were not able to start its definition.\nPlease file a " - "bug and attach the file at the start of this error " - "message", - parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), - name); + last_field_info.SetIsBitfield(false); + } + + if (!member_clang_type.IsCompleteType()) + 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]. + + CompilerType member_array_element_type; + uint64_t member_array_size; + bool member_array_is_incomplete; + + if (member_clang_type.IsArrayType(&member_array_element_type, + &member_array_size, + &member_array_is_incomplete) && + !member_array_is_incomplete) { + uint64_t parent_byte_size = + parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, + UINT64_MAX); + + if (member_byte_offset >= parent_byte_size) { + if (member_array_size != 1 && + (member_array_size != 0 || + member_byte_offset > parent_byte_size)) { + module_sp->ReportError( + "0x%8.8" PRIx64 + ": DW_TAG_member '%s' refers to type 0x%8.8x" + " which extends beyond the bounds of 0x%8.8" PRIx64, + die.GetID(), name, encoding_form.Reference().GetOffset(), + parent_die.GetID()); + } + + member_clang_type = + m_ast.CreateArrayType(member_array_element_type, 0, false); } } + } - field_decl = ClangASTContext::AddFieldToRecordType( - class_clang_type, name, member_clang_type, accessibility, - bit_size); + CompleteType(member_clang_type); - m_ast.SetMetadataAsUserID(field_decl, die.GetID()); + field_decl = TypeSystemClang::AddFieldToRecordType( + class_clang_type, name, member_clang_type, accessibility, + bit_size); - layout_info.field_offsets.insert( - std::make_pair(field_decl, field_bit_offset)); - } else { - if (name) - module_sp->ReportError( - "0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8x" - " which was unable to be parsed", - die.GetID(), name, encoding_form.Reference().GetOffset()); - else - module_sp->ReportError( - "0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8x" - " which was unable to be parsed", - die.GetID(), encoding_form.Reference().GetOffset()); - } + m_ast.SetMetadataAsUserID(field_decl, die.GetID()); + + layout_info.field_offsets.insert( + std::make_pair(field_decl, field_bit_offset)); + } else { + if (name) + module_sp->ReportError( + "0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8x" + " which was unable to be parsed", + die.GetID(), name, encoding_form.Reference().GetOffset()); + else + module_sp->ReportError( + "0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8x" + " which was unable to be parsed", + die.GetID(), encoding_form.Reference().GetOffset()); } + } - if (prop_name != nullptr && member_type) { - clang::ObjCIvarDecl *ivar_decl = nullptr; + if (prop_name != nullptr && member_type) { + clang::ObjCIvarDecl *ivar_decl = nullptr; - if (field_decl) { - ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl); - assert(ivar_decl != nullptr); - } + if (field_decl) { + ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl); + assert(ivar_decl != nullptr); + } - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - delayed_properties.push_back(DelayedAddObjCClassProperty( - class_clang_type, prop_name, member_type->GetLayoutCompilerType(), - ivar_decl, prop_setter_name, prop_getter_name, prop_attributes, - &metadata)); + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + delayed_properties.push_back(DelayedAddObjCClassProperty( + class_clang_type, prop_name, member_type->GetLayoutCompilerType(), + ivar_decl, prop_setter_name, prop_getter_name, prop_attributes, + &metadata)); - if (ivar_decl) - m_ast.SetMetadataAsUserID(ivar_decl, die.GetID()); - } + if (ivar_decl) + m_ast.SetMetadataAsUserID(ivar_decl, die.GetID()); } } } bool DWARFASTParserClang::ParseChildMembers( const DWARFDIE &parent_die, CompilerType &class_clang_type, - const LanguageType class_language, std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, std::vector<int> &member_accessibilities, std::vector<DWARFDIE> &member_function_dies, @@ -2885,11 +2762,11 @@ bool DWARFASTParserClang::ParseChildMembers( if (!parent_die) return false; - BitfieldInfo last_field_info; + FieldInfo last_field_info; ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); - ClangASTContext *ast = - llvm::dyn_cast_or_null<ClangASTContext>(class_clang_type.GetTypeSystem()); + TypeSystemClang *ast = + llvm::dyn_cast_or_null<TypeSystemClang>(class_clang_type.GetTypeSystem()); if (ast == nullptr) return false; @@ -2900,7 +2777,7 @@ bool DWARFASTParserClang::ParseChildMembers( switch (tag) { case DW_TAG_member: case DW_TAG_APPLE_property: - ParseSingleMember(die, parent_die, class_clang_type, class_language, + ParseSingleMember(die, parent_die, class_clang_type, member_accessibilities, default_accessibility, delayed_properties, layout_info, last_field_info); break; @@ -2990,7 +2867,7 @@ bool DWARFASTParserClang::ParseChildMembers( CompilerType base_class_clang_type = base_class_type->GetFullCompilerType(); assert(base_class_clang_type); - if (class_language == eLanguageTypeObjC) { + if (TypeSystemClang::IsObjCObjectOrInterfaceType(class_clang_type)) { ast->SetObjCSuperClass(class_clang_type, base_class_clang_type); } else { std::unique_ptr<clang::CXXBaseSpecifier> result = @@ -3121,9 +2998,9 @@ size_t DWARFASTParserClang::ParseChildParameters( function_param_types.push_back(type->GetForwardCompilerType()); clang::ParmVarDecl *param_var_decl = - m_ast.CreateParameterDeclaration(containing_decl_ctx, name, - type->GetForwardCompilerType(), - storage); + m_ast.CreateParameterDeclaration( + containing_decl_ctx, GetOwningClangModule(die), name, + type->GetForwardCompilerType(), storage); assert(param_var_decl); function_param_decls.push_back(param_var_decl); @@ -3318,10 +3195,10 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { if (dwarf && type) { const char *name = die.GetName(); clang::DeclContext *decl_context = - ClangASTContext::DeclContextGetAsDeclContext( + TypeSystemClang::DeclContextGetAsDeclContext( dwarf->GetDeclContextContainingUID(die.GetID())); decl = m_ast.CreateVariableDeclaration( - decl_context, name, + decl_context, GetOwningClangModule(die), name, ClangUtil::GetQualType(type->GetForwardCompilerType())); } break; @@ -3330,16 +3207,16 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { SymbolFileDWARF *dwarf = die.GetDWARF(); DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import); if (imported_uid) { - CompilerDecl imported_decl = imported_uid.GetDecl(); + CompilerDecl imported_decl = SymbolFileDWARF::GetDecl(imported_uid); if (imported_decl) { clang::DeclContext *decl_context = - ClangASTContext::DeclContextGetAsDeclContext( + TypeSystemClang::DeclContextGetAsDeclContext( dwarf->GetDeclContextContainingUID(die.GetID())); if (clang::NamedDecl *clang_imported_decl = llvm::dyn_cast<clang::NamedDecl>( (clang::Decl *)imported_decl.GetOpaqueDecl())) - decl = - m_ast.CreateUsingDeclaration(decl_context, clang_imported_decl); + decl = m_ast.CreateUsingDeclaration( + decl_context, OptionalClangModuleID(), clang_imported_decl); } } break; @@ -3349,15 +3226,17 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import); if (imported_uid) { - CompilerDeclContext imported_decl_ctx = imported_uid.GetDeclContext(); + CompilerDeclContext imported_decl_ctx = + SymbolFileDWARF::GetDeclContext(imported_uid); if (imported_decl_ctx) { clang::DeclContext *decl_context = - ClangASTContext::DeclContextGetAsDeclContext( + TypeSystemClang::DeclContextGetAsDeclContext( dwarf->GetDeclContextContainingUID(die.GetID())); if (clang::NamespaceDecl *ns_decl = - ClangASTContext::DeclContextGetAsNamespaceDecl( + TypeSystemClang::DeclContextGetAsNamespaceDecl( imported_decl_ctx)) - decl = m_ast.CreateUsingDirectiveDeclaration(decl_context, ns_decl); + decl = m_ast.CreateUsingDirectiveDeclaration( + decl_context, OptionalClangModuleID(), ns_decl); } } break; @@ -3415,6 +3294,32 @@ DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) { return nullptr; } +OptionalClangModuleID +DWARFASTParserClang::GetOwningClangModule(const DWARFDIE &die) { + if (!die.IsValid()) + return {}; + + for (DWARFDIE parent = die.GetParent(); parent.IsValid(); + parent = parent.GetParent()) { + const dw_tag_t tag = parent.Tag(); + if (tag == DW_TAG_module) { + DWARFDIE module_die = parent; + auto it = m_die_to_module.find(module_die.GetDIE()); + if (it != m_die_to_module.end()) + return it->second; + const char *name = module_die.GetAttributeValueAsString(DW_AT_name, 0); + if (!name) + return {}; + + OptionalClangModuleID id = + m_ast.GetOrCreateClangModule(name, GetOwningClangModule(module_die)); + m_die_to_module.insert({module_die.GetDIE(), id}); + return id; + } + } + return {}; +} + static bool IsSubroutine(const DWARFDIE &die) { switch (die.Tag()) { case DW_TAG_subprogram: @@ -3487,7 +3392,8 @@ clang::BlockDecl *DWARFASTParserClang::ResolveBlockDIE(const DWARFDIE &die) { DWARFDIE decl_context_die; clang::DeclContext *decl_context = GetClangDeclContextContainingDIE(die, &decl_context_die); - decl = m_ast.CreateBlockDeclaration(decl_context); + decl = + m_ast.CreateBlockDeclaration(decl_context, GetOwningClangModule(die)); if (decl) LinkDeclContextToDIE((clang::DeclContext *)decl, die); @@ -3515,7 +3421,8 @@ DWARFASTParserClang::ResolveNamespaceDIE(const DWARFDIE &die) { die.GetAttributeValueAsUnsigned(DW_AT_export_symbols, 0) != 0; namespace_decl = m_ast.GetUniqueNamespaceDeclaration( - namespace_name, containing_decl_ctx, is_inline); + namespace_name, containing_decl_ctx, GetOwningClangModule(die), + is_inline); Log *log = nullptr; // (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); if (log) { @@ -3697,9 +3604,11 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( } DWARFASTParserClang *src_dwarf_ast_parser = - (DWARFASTParserClang *)src_die.GetDWARFParser(); + static_cast<DWARFASTParserClang *>( + SymbolFileDWARF::GetDWARFParser(*src_die.GetCU())); DWARFASTParserClang *dst_dwarf_ast_parser = - (DWARFASTParserClang *)dst_die.GetDWARFParser(); + static_cast<DWARFASTParserClang *>( + SymbolFileDWARF::GetDWARFParser(*dst_die.GetCU())); // Now do the work of linking the DeclContexts and Types. if (fast_path) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 4ad757247c3e..2ef49abc1da1 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFASTParserClang_h_ -#define SymbolFileDWARF_DWARFASTParserClang_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H #include "clang/AST/CharUnits.h" #include "llvm/ADT/DenseMap.h" @@ -19,10 +19,10 @@ #include "DWARFDefines.h" #include "DWARFFormValue.h" #include "LogChannelDWARF.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Core/PluginInterface.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTImporter.h" + +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include <vector> @@ -36,7 +36,7 @@ struct ParsedDWARFTypeAttributes; class DWARFASTParserClang : public DWARFASTParser { public: - DWARFASTParserClang(lldb_private::ClangASTContext &ast); + DWARFASTParserClang(lldb_private::TypeSystemClang &ast); ~DWARFASTParserClang() override; @@ -78,15 +78,19 @@ protected: DIEToDeclContextMap; typedef std::multimap<const clang::DeclContext *, const DWARFDIE> DeclContextToDIEMap; + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, + lldb_private::OptionalClangModuleID> + DIEToModuleMap; typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::Decl *> DIEToDeclMap; typedef llvm::DenseMap<const clang::Decl *, DIEPointerSet> DeclToDIEMap; - lldb_private::ClangASTContext &m_ast; + lldb_private::TypeSystemClang &m_ast; DIEToDeclMap m_die_to_decl; DeclToDIEMap m_decl_to_die; DIEToDeclContextMap m_die_to_decl_ctx; DeclContextToDIEMap m_decl_ctx_to_die; + DIEToModuleMap m_die_to_module; std::unique_ptr<lldb_private::ClangASTImporter> m_clang_ast_importer_up; /// @} @@ -97,16 +101,15 @@ protected: clang::NamespaceDecl *ResolveNamespaceDIE(const DWARFDIE &die); bool ParseTemplateDIE(const DWARFDIE &die, - lldb_private::ClangASTContext::TemplateParameterInfos + lldb_private::TypeSystemClang::TemplateParameterInfos &template_param_infos); bool ParseTemplateParameterInfos( const DWARFDIE &parent_die, - lldb_private::ClangASTContext::TemplateParameterInfos + lldb_private::TypeSystemClang::TemplateParameterInfos &template_param_infos); bool ParseChildMembers( const DWARFDIE &die, lldb_private::CompilerType &class_compiler_type, - const lldb::LanguageType class_language, std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, std::vector<int> &member_accessibilities, std::vector<DWARFDIE> &member_function_dies, @@ -140,6 +143,7 @@ protected: clang::DeclContext *GetClangDeclContextContainingDIE(const DWARFDIE &die, DWARFDIE *decl_ctx_die); + lldb_private::OptionalClangModuleID GetOwningClangModule(const DWARFDIE &die); bool CopyUniqueClassMethodTypes(const DWARFDIE &src_class_die, const DWARFDIE &dst_class_die, @@ -170,45 +174,31 @@ protected: lldb::ModuleSP GetModuleForType(const DWARFDIE &die); private: - struct BitfieldInfo { - uint64_t bit_size; - uint64_t bit_offset; + struct FieldInfo { + uint64_t bit_size = 0; + uint64_t bit_offset = 0; + bool is_bitfield = false; - BitfieldInfo() - : bit_size(LLDB_INVALID_ADDRESS), bit_offset(LLDB_INVALID_ADDRESS) {} + FieldInfo() = default; - void Clear() { - bit_size = LLDB_INVALID_ADDRESS; - bit_offset = LLDB_INVALID_ADDRESS; - } - - bool IsValid() const { - return (bit_size != LLDB_INVALID_ADDRESS) && - (bit_offset != LLDB_INVALID_ADDRESS); - } + void SetIsBitfield(bool flag) { is_bitfield = flag; } + bool IsBitfield() { return is_bitfield; } bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const { - if (IsValid()) { - // This bitfield info is valid, so any subsequent bitfields must not - // overlap and must be at a higher bit offset than any previous bitfield - // + size. - return (bit_size + bit_offset) <= next_bit_offset; - } else { - // If the this BitfieldInfo is not valid, then any offset isOK - return true; - } + // Any subsequent bitfields must not overlap and must be at a higher + // bit offset than any previous bitfield + size. + return (bit_size + bit_offset) <= next_bit_offset; } }; void ParseSingleMember(const DWARFDIE &die, const DWARFDIE &parent_die, - lldb_private::CompilerType &class_clang_type, - const lldb::LanguageType class_language, + const lldb_private::CompilerType &class_clang_type, std::vector<int> &member_accessibilities, - lldb::AccessType &default_accessibility, + lldb::AccessType default_accessibility, DelayedPropertyList &delayed_properties, lldb_private::ClangASTImporter::LayoutInfo &layout_info, - BitfieldInfo &last_field_info); + FieldInfo &last_field_info); bool CompleteRecordType(const DWARFDIE &die, lldb_private::Type *type, lldb_private::CompilerType &clang_type); @@ -227,6 +217,12 @@ private: ParsedDWARFTypeAttributes &attrs); lldb::TypeSP ParsePointerToMemberType(const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs); + + /// Complete a type from debug info, or mark it as forcefully completed if + /// there is no of the type in the current Module. Call this function in + /// contexts where the usual C++ rules require a type to be complete (base + /// class, member, etc.). + void CompleteType(lldb_private::CompilerType type); }; /// Parsed form of all attributes that are relevant for type reconstruction. @@ -264,4 +260,4 @@ struct ParsedDWARFTypeAttributes { uint32_t encoding = 0; }; -#endif // SymbolFileDWARF_DWARFASTParserClang_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp index 741669b05754..0e9370be15fb 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -1,4 +1,4 @@ -//===-- DWARFAbbreviationDeclaration.cpp ------------------------*- C++ -*-===// +//===-- DWARFAbbreviationDeclaration.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h index c0cf8823a368..f70aa71a5958 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_DWARFAbbreviationDeclaration_h_ -#define liblldb_DWARFAbbreviationDeclaration_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFABBREVIATIONDECLARATION_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFABBREVIATIONDECLARATION_H #include "DWARFAttribute.h" #include "DWARFDefines.h" @@ -62,4 +62,4 @@ protected: DWARFAttribute::collection m_attributes; }; -#endif // liblldb_DWARFAbbreviationDeclaration_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFABBREVIATIONDECLARATION_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp index b3594a455680..6c72d9e26221 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -1,4 +1,4 @@ -//===-- DWARFAttribute.cpp --------------------------------------*- C++ -*-===// +//===-- DWARFAttribute.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h index 58427b19100a..9948969f108f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFAttribute_h_ -#define SymbolFileDWARF_DWARFAttribute_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFATTRIBUTE_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFATTRIBUTE_H #include "DWARFDefines.h" #include "DWARFFormValue.h" @@ -82,4 +82,4 @@ protected: collection m_infos; }; -#endif // SymbolFileDWARF_DWARFAttribute_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFATTRIBUTE_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp index 033105efdc53..fcb424029f5a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp @@ -1,4 +1,4 @@ -//===-- DWARFBaseDIE.cpp ---------------------------------------*- C++ -*-===// +//===-- DWARFBaseDIE.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -74,13 +74,6 @@ const char *DWARFBaseDIE::GetName() const { return nullptr; } -lldb::LanguageType DWARFBaseDIE::GetLanguage() const { - if (IsValid()) - return m_cu->GetLanguageType(); - else - return lldb::eLanguageTypeUnknown; -} - lldb::ModuleSP DWARFBaseDIE::GetModule() const { SymbolFileDWARF *dwarf = GetDWARF(); if (dwarf) @@ -103,24 +96,6 @@ SymbolFileDWARF *DWARFBaseDIE::GetDWARF() const { return nullptr; } -llvm::Expected<lldb_private::TypeSystem &> DWARFBaseDIE::GetTypeSystem() const { - if (!m_cu) - return llvm::make_error<llvm::StringError>( - "Unable to get TypeSystem, no compilation unit available", - llvm::inconvertibleErrorCode()); - return m_cu->GetTypeSystem(); -} - -DWARFASTParser *DWARFBaseDIE::GetDWARFParser() const { - auto type_system_or_err = GetTypeSystem(); - if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS), - std::move(err), "Unable to get DWARFASTParser"); - return nullptr; - } - return type_system_or_err->GetDWARFParser(); -} - bool DWARFBaseDIE::HasChildren() const { return m_die && m_die->HasChildren(); } @@ -130,11 +105,10 @@ bool DWARFBaseDIE::Supports_DW_AT_APPLE_objc_complete_type() const { } size_t DWARFBaseDIE::GetAttributes(DWARFAttributes &attributes, - uint32_t depth) const { + Recurse recurse) const { if (IsValid()) - return m_die->GetAttributes(m_cu, attributes, depth); - if (depth == 0) - attributes.Clear(); + return m_die->GetAttributes(m_cu, attributes, recurse); + attributes.Clear(); return 0; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h index 9652d7946e87..059b84864be7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFBaseDIE_h_ -#define SymbolFileDWARF_DWARFBaseDIE_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFBASEDIE_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFBASEDIE_H #include "lldb/Core/dwarf.h" #include "lldb/lldb-types.h" @@ -57,10 +57,6 @@ public: llvm::Optional<DIERef> GetDIERef() const; - llvm::Expected<lldb_private::TypeSystem &> GetTypeSystem() const; - - DWARFASTParser *GetDWARFParser() const; - void Set(DWARFUnit *cu, DWARFDebugInfoEntry *die) { if (cu && die) { m_cu = cu; @@ -98,8 +94,6 @@ public: const char *GetName() const; - lldb::LanguageType GetLanguage() const; - lldb::ModuleSP GetModule() const; // Getting attribute values from the DIE. @@ -116,7 +110,9 @@ public: uint64_t GetAttributeValueAsAddress(const dw_attr_t attr, uint64_t fail_value) const; - size_t GetAttributes(DWARFAttributes &attributes, uint32_t depth = 0) const; + enum class Recurse : bool { no, yes }; + size_t GetAttributes(DWARFAttributes &attributes, + Recurse recurse = Recurse::yes) const; protected: DWARFUnit *m_cu; @@ -126,4 +122,4 @@ protected: bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); -#endif // SymbolFileDWARF_DWARFBaseDIE_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFBASEDIE_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index 718f0537d6ed..f54fe0662aa2 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -1,4 +1,4 @@ -//===-- DWARFCompileUnit.cpp ------------------------------------*- C++ -*-===// +//===-- DWARFCompileUnit.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -33,41 +33,27 @@ void DWARFCompileUnit::BuildAddressRangeTable( size_t num_debug_aranges = debug_aranges->GetNumRanges(); - // First get the compile unit DIE only and check if it has a DW_AT_ranges + // First get the compile unit DIE only and check contains ranges information. const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); const dw_offset_t cu_offset = GetOffset(); if (die) { DWARFRangeList ranges; const size_t num_ranges = - die->GetAttributeAddressRanges(this, ranges, false); + die->GetAttributeAddressRanges(this, ranges, /*check_hi_lo_pc=*/true); if (num_ranges > 0) { - // This compile unit has DW_AT_ranges, assume this is correct if it is - // present since clang no longer makes .debug_aranges by default and it - // emits DW_AT_ranges for DW_TAG_compile_units. GCC also does this with - // recent GCC builds. for (size_t i = 0; i < num_ranges; ++i) { const DWARFRangeList::Entry &range = ranges.GetEntryRef(i); debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), range.GetRangeEnd()); } - return; // We got all of our ranges from the DW_AT_ranges attribute + return; } } - // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF - - // If the DIEs weren't parsed, then we don't want all dies for all compile - // units to stay loaded when they weren't needed. So we can end up parsing - // the DWARF and then throwing them all away to keep memory usage down. - ScopedExtractDIEs clear_dies(ExtractDIEsScoped()); - - die = DIEPtr(); - if (die) - die->BuildAddressRangeTable(this, debug_aranges); if (debug_aranges->GetNumRanges() == num_debug_aranges) { - // We got nothing from the functions, maybe we have a line tables only + // We got nothing from the debug info, maybe we have a line tables only // situation. Check the line tables and build the arange table from this. SymbolContext sc; sc.comp_unit = m_dwarf.GetCompUnitForDWARFCompUnit(*this); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 454637ef981c..3ec161f7dd51 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFCompileUnit_h_ -#define SymbolFileDWARF_DWARFCompileUnit_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCOMPILEUNIT_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCOMPILEUNIT_H #include "DWARFUnit.h" #include "llvm/Support/Error.h" @@ -27,9 +27,10 @@ private: DIERef::Section section, bool is_dwo) : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} - DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); + DWARFCompileUnit(const DWARFCompileUnit &) = delete; + const DWARFCompileUnit &operator=(const DWARFCompileUnit &) = delete; friend class DWARFUnit; }; -#endif // SymbolFileDWARF_DWARFCompileUnit_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCOMPILEUNIT_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp index 5052b825fea6..37e28a09f3c4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp @@ -1,4 +1,4 @@ -//===-- DWARFContext.cpp ----------------------------------------*- C++ -*-===// +//===-- DWARFContext.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -28,18 +28,28 @@ static DWARFDataExtractor LoadSection(SectionList *section_list, } const DWARFDataExtractor & -DWARFContext::LoadOrGetSection(SectionType main_section_type, +DWARFContext::LoadOrGetSection(llvm::Optional<SectionType> main_section_type, llvm::Optional<SectionType> dwo_section_type, SectionData &data) { llvm::call_once(data.flag, [&] { if (dwo_section_type && isDwo()) data.data = LoadSection(m_dwo_section_list, *dwo_section_type); - else - data.data = LoadSection(m_main_section_list, main_section_type); + else if (main_section_type) + data.data = LoadSection(m_main_section_list, *main_section_type); }); return data.data; } +const DWARFDataExtractor &DWARFContext::getOrLoadCuIndexData() { + return LoadOrGetSection(llvm::None, eSectionTypeDWARFDebugCuIndex, + m_data_debug_cu_index); +} + +const DWARFDataExtractor &DWARFContext::getOrLoadTuIndexData() { + return LoadOrGetSection(llvm::None, eSectionTypeDWARFDebugTuIndex, + m_data_debug_tu_index); +} + const DWARFDataExtractor &DWARFContext::getOrLoadAbbrevData() { return LoadOrGetSection(eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAbbrevDwo, m_data_debug_abbrev); @@ -117,32 +127,19 @@ llvm::DWARFContext &DWARFContext::GetAsLLVM() { if (!m_llvm_context) { llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> section_map; uint8_t addr_size = 0; - - auto AddSection = [&](Section §ion) { - DataExtractor section_data; - section.GetSectionData(section_data); - + auto AddSection = [&](llvm::StringRef name, DWARFDataExtractor data) { // Set the address size the first time we see it. if (addr_size == 0) - addr_size = section_data.GetByteSize(); + addr_size = data.GetAddressByteSize(); - llvm::StringRef data = llvm::toStringRef(section_data.GetData()); - llvm::StringRef name = section.GetName().GetStringRef(); - if (name.startswith(".")) - name = name.drop_front(); section_map.try_emplace( - name, llvm::MemoryBuffer::getMemBuffer(data, name, false)); + name, llvm::MemoryBuffer::getMemBuffer(toStringRef(data.GetData()), + name, false)); }; - if (m_main_section_list) { - for (auto §ion : *m_main_section_list) - AddSection(*section); - } - - if (m_dwo_section_list) { - for (auto §ion : *m_dwo_section_list) - AddSection(*section); - } + AddSection("debug_line_str", getOrLoadLineStrData()); + AddSection("debug_cu_index", getOrLoadCuIndexData()); + AddSection("debug_tu_index", getOrLoadTuIndexData()); m_llvm_context = llvm::DWARFContext::create(section_map, addr_size); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h index 8691001b1b76..92161a21d167 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILE_DWARF_DWARFCONTEXT_H -#define LLDB_PLUGINS_SYMBOLFILE_DWARF_DWARFCONTEXT_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCONTEXT_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCONTEXT_H #include "DWARFDataExtractor.h" #include "lldb/Core/Section.h" @@ -31,6 +31,7 @@ private: SectionData m_data_debug_abbrev; SectionData m_data_debug_addr; SectionData m_data_debug_aranges; + SectionData m_data_debug_cu_index; SectionData m_data_debug_info; SectionData m_data_debug_line; SectionData m_data_debug_line_str; @@ -41,13 +42,17 @@ private: SectionData m_data_debug_rnglists; SectionData m_data_debug_str; SectionData m_data_debug_str_offsets; + SectionData m_data_debug_tu_index; SectionData m_data_debug_types; const DWARFDataExtractor & - LoadOrGetSection(lldb::SectionType main_section_type, + LoadOrGetSection(llvm::Optional<lldb::SectionType> main_section_type, llvm::Optional<lldb::SectionType> dwo_section_type, SectionData &data); + const DWARFDataExtractor &getOrLoadCuIndexData(); + const DWARFDataExtractor &getOrLoadTuIndexData(); + public: explicit DWARFContext(SectionList *main_section_list, SectionList *dwo_section_list) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index c5411a17f274..8e995e627978 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDIE.cpp --------------------------------------------*- C++ -*-===// +//===-- DWARFDIE.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,7 +32,7 @@ class ElaboratingDIEIterator // Container sizes are optimized for the case of following DW_AT_specification // and DW_AT_abstract_origin just once. llvm::SmallVector<DWARFDIE, 2> m_worklist; - llvm::SmallSet<lldb::user_id_t, 3> m_seen; + llvm::SmallSet<DWARFDebugInfoEntry *, 3> m_seen; void Next() { assert(!m_worklist.empty() && "Incrementing end iterator?"); @@ -44,7 +44,7 @@ class ElaboratingDIEIterator // And add back any items that elaborate it. for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) { if (DWARFDIE d = die.GetReferencedDIE(attr)) - if (m_seen.insert(die.GetID()).second) + if (m_seen.insert(die.GetDIE()).second) m_worklist.push_back(d); } } @@ -140,25 +140,64 @@ DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { } DWARFDIE -DWARFDIE::LookupDeepestBlock(lldb::addr_t file_addr) const { - if (IsValid()) { - SymbolFileDWARF *dwarf = GetDWARF(); - DWARFUnit *cu = GetCU(); - DWARFDebugInfoEntry *function_die = nullptr; - DWARFDebugInfoEntry *block_die = nullptr; - if (m_die->LookupAddress(file_addr, cu, &function_die, &block_die)) { - if (block_die && block_die != function_die) { - if (cu->ContainsDIEOffset(block_die->GetOffset())) - return DWARFDIE(cu, block_die); - else - return DWARFDIE(dwarf->DebugInfo()->GetUnit(DIERef( - cu->GetSymbolFileDWARF().GetDwoNum(), - cu->GetDebugSection(), block_die->GetOffset())), - block_die); +DWARFDIE::LookupDeepestBlock(lldb::addr_t address) const { + if (!IsValid()) + return DWARFDIE(); + + DWARFDIE result; + bool check_children = false; + bool match_addr_range = false; + switch (Tag()) { + case DW_TAG_class_type: + case DW_TAG_namespace: + case DW_TAG_structure_type: + case DW_TAG_common_block: + check_children = true; + break; + case DW_TAG_compile_unit: + case DW_TAG_module: + case DW_TAG_catch_block: + case DW_TAG_subprogram: + case DW_TAG_try_block: + case DW_TAG_partial_unit: + match_addr_range = true; + break; + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + check_children = true; + match_addr_range = true; + break; + default: + break; + } + + if (match_addr_range) { + DWARFRangeList ranges; + if (m_die->GetAttributeAddressRanges(m_cu, ranges, + /*check_hi_lo_pc=*/true) && + ranges.FindEntryThatContains(address)) { + check_children = true; + switch (Tag()) { + default: + break; + + case DW_TAG_inlined_subroutine: // Inlined Function + case DW_TAG_lexical_block: // Block { } in code + result = *this; + break; } + } else { + check_children = false; } } - return DWARFDIE(); + + if (check_children) { + for (DWARFDIE child = GetFirstChild(); child; child = child.GetSibling()) { + if (DWARFDIE child_result = child.LookupDeepestBlock(address)) + return child_result; + } + } + return result; } const char *DWARFDIE::GetMangledName() const { @@ -333,15 +372,6 @@ std::vector<DWARFDIE> DWARFDIE::GetDeclContextDIEs() const { return result; } -void DWARFDIE::GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const { - if (IsValid()) { - dwarf_decl_ctx.SetLanguage(GetLanguage()); - m_die->GetDWARFDeclContext(GetCU(), dwarf_decl_ctx); - } else { - dwarf_decl_ctx.Clear(); - } -} - void DWARFDIE::GetDeclContext( llvm::SmallVectorImpl<lldb_private::CompilerContext> &context) const { const dw_tag_t tag = Tag(); @@ -418,27 +448,3 @@ bool DWARFDIE::GetDIENamesAndRanges( } else return false; } - -CompilerDecl DWARFDIE::GetDecl() const { - DWARFASTParser *dwarf_ast = GetDWARFParser(); - if (dwarf_ast) - return dwarf_ast->GetDeclForUIDFromDWARF(*this); - else - return CompilerDecl(); -} - -CompilerDeclContext DWARFDIE::GetDeclContext() const { - DWARFASTParser *dwarf_ast = GetDWARFParser(); - if (dwarf_ast) - return dwarf_ast->GetDeclContextForUIDFromDWARF(*this); - else - return CompilerDeclContext(); -} - -CompilerDeclContext DWARFDIE::GetContainingDeclContext() const { - DWARFASTParser *dwarf_ast = GetDWARFParser(); - if (dwarf_ast) - return dwarf_ast->GetDeclContextContainingUIDFromDWARF(*this); - else - return CompilerDeclContext(); -} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 87d52eee9dd9..13737280926c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDIE_h_ -#define SymbolFileDWARF_DWARFDIE_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H #include "DWARFBaseDIE.h" #include "llvm/ADT/SmallSet.h" @@ -70,8 +70,6 @@ public: // DeclContext related functions std::vector<DWARFDIE> GetDeclContextDIEs() const; - void GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const; - /// Return this DIE's decl context as it is needed to look up types /// in Clang's -gmodules debug info format. void GetDeclContext( @@ -90,14 +88,6 @@ public: int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, lldb_private::DWARFExpression *frame_base) const; - - // CompilerDecl related functions - - lldb_private::CompilerDecl GetDecl() const; - - lldb_private::CompilerDeclContext GetDeclContext() const; - - lldb_private::CompilerDeclContext GetContainingDeclContext() const; }; -#endif // SymbolFileDWARF_DWARFDIE_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp index 1678b228137f..cf483286a66d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDataExtractor.cpp ----------------------------------*- C++ -*-===// +//===-- DWARFDataExtractor.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -23,8 +23,7 @@ DWARFDataExtractor::GetDWARFOffset(lldb::offset_t *offset_ptr) const { llvm::DWARFDataExtractor DWARFDataExtractor::GetAsLLVM() const { return llvm::DWARFDataExtractor( - llvm::StringRef(reinterpret_cast<const char *>(GetDataStart()), - GetByteSize()), + llvm::makeArrayRef(GetDataStart(), GetByteSize()), GetByteOrder() == lldb::eByteOrderLittle, GetAddressByteSize()); } } // namespace lldb_private diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h index 22db5e8c0b79..df92bd45d5cc 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_DWARFDataExtractor_h_ -#define liblldb_DWARFDataExtractor_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDATAEXTRACTOR_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDATAEXTRACTOR_H #include "lldb/Core/dwarf.h" #include "lldb/Utility/DataExtractor.h" @@ -34,4 +34,4 @@ public: }; } -#endif // liblldb_DWARFDataExtractor_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDATAEXTRACTOR_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp index 26301566a8e1..0f0f50a645db 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugAbbrev.cpp ------------------------------------*- C++ -*-===// +//===-- 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. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h index 9c4729326081..555864f44967 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDebugAbbrev_h_ -#define SymbolFileDWARF_DWARFDebugAbbrev_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGABBREV_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGABBREV_H #include <list> #include <map> @@ -78,4 +78,4 @@ protected: mutable DWARFAbbreviationDeclarationCollMapConstIter m_prev_abbr_offset_pos; }; -#endif // SymbolFileDWARF_DWARFDebugAbbrev_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGABBREV_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp index 86ce3b329b25..728cefe620a5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugArangeSet.cpp ---------------------------------*- C++ -*-===// +//===-- DWARFDebugArangeSet.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -63,7 +63,8 @@ llvm::Error DWARFDebugArangeSet::extract(const DWARFDataExtractor &data, // 1 - the version looks good // 2 - the address byte size looks plausible // 3 - the length seems to make sense - // size looks plausible + // 4 - size looks plausible + // 5 - the arange tuples do not contain a segment field if (m_header.version < 2 || m_header.version > 5) return llvm::make_error<llvm::object::GenericBinaryError>( "Invalid arange header version"); @@ -81,6 +82,10 @@ llvm::Error DWARFDebugArangeSet::extract(const DWARFDataExtractor &data, return llvm::make_error<llvm::object::GenericBinaryError>( "Invalid arange header length"); + if (m_header.seg_size) + return llvm::make_error<llvm::object::GenericBinaryError>( + "segmented arange entries are not supported"); + // The first tuple following the header in each set begins at an offset // that is a multiple of the size of a single tuple (that is, twice the // size of an address). The header is padded, if necessary, to the diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h index db0cf22a3f45..6b5b69a70a80 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDebugArangeSet_h_ -#define SymbolFileDWARF_DWARFDebugArangeSet_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGESET_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGESET_H #include "lldb/Core/dwarf.h" #include <cstdint> @@ -59,4 +59,4 @@ protected: DescriptorColl m_arange_descriptors; }; -#endif // SymbolFileDWARF_DWARFDebugArangeSet_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGESET_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index c8da2381353e..7dc52c1e2df0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===// +//===-- DWARFDebugAranges.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h index 74ba011b27af..96e82619f985 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDebugAranges_h_ -#define SymbolFileDWARF_DWARFDebugAranges_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGES_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGES_H #include "lldb/Core/dwarf.h" #include "lldb/Utility/RangeMap.h" @@ -52,4 +52,4 @@ protected: RangeToDIE m_aranges; }; -#endif // SymbolFileDWARF_DWARFDebugAranges_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGES_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 1e04baca2c58..874978bf1398 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugInfo.cpp --------------------------------------*- C++ -*-===// +//===-- DWARFDebugInfo.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -72,10 +72,16 @@ void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { DWARFDataExtractor data = section == DIERef::Section::DebugTypes ? m_context.getOrLoadDebugTypesData() : m_context.getOrLoadDebugInfoData(); + const llvm::DWARFUnitIndex *index = nullptr; + if (m_context.isDwo()) + index = &llvm::getDWARFUnitIndex(m_context.GetAsLLVM(), + section == DIERef::Section::DebugTypes + ? llvm::DW_SECT_EXT_TYPES + : llvm::DW_SECT_INFO); lldb::offset_t offset = 0; while (data.ValidOffset(offset)) { - llvm::Expected<DWARFUnitSP> unit_sp = - DWARFUnit::extract(m_dwarf, m_units.size(), data, section, &offset); + llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract( + m_dwarf, m_units.size(), data, section, &offset, index); if (!unit_sp) { // FIXME: Propagate this error up. @@ -96,12 +102,11 @@ void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { } void DWARFDebugInfo::ParseUnitHeadersIfNeeded() { - if (!m_units.empty()) - return; - - ParseUnitsFor(DIERef::Section::DebugInfo); - ParseUnitsFor(DIERef::Section::DebugTypes); - llvm::sort(m_type_hash_to_unit_index, llvm::less_first()); + llvm::call_once(m_units_once_flag, [&] { + ParseUnitsFor(DIERef::Section::DebugInfo); + ParseUnitsFor(DIERef::Section::DebugTypes); + llvm::sort(m_type_hash_to_unit_index, llvm::less_first()); + }); } size_t DWARFDebugInfo::GetNumUnits() { @@ -109,7 +114,7 @@ size_t DWARFDebugInfo::GetNumUnits() { return m_units.size(); } -DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(user_id_t idx) { +DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(size_t idx) { DWARFUnit *cu = nullptr; if (idx < GetNumUnits()) cu = m_units[idx].get(); @@ -191,7 +196,7 @@ DWARFDIE DWARFDebugInfo::GetDIE(const DIERef &die_ref) { DWARFUnit *cu = GetUnit(die_ref); if (cu) - return cu->GetDIE(die_ref.die_offset()); + return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset()); return DWARFDIE(); // Not found } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index 056cf33a202f..bdc718a5c2fa 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDebugInfo_h_ -#define SymbolFileDWARF_DWARFDebugInfo_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFO_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFO_H #include <map> #include <vector> @@ -35,7 +35,7 @@ public: lldb_private::DWARFContext &context); size_t GetNumUnits(); - DWARFUnit *GetUnitAtIndex(lldb::user_id_t idx); + DWARFUnit *GetUnitAtIndex(size_t idx); DWARFUnit *GetUnitAtOffset(DIERef::Section section, dw_offset_t cu_offset, uint32_t *idx_ptr = nullptr); DWARFUnit *GetUnitContainingDIEOffset(DIERef::Section section, @@ -61,7 +61,10 @@ protected: SymbolFileDWARF &m_dwarf; lldb_private::DWARFContext &m_context; + + llvm::once_flag m_units_once_flag; UnitColl m_units; + std::unique_ptr<DWARFDebugAranges> m_cu_aranges_up; // A quick address to compile unit table @@ -76,7 +79,8 @@ private: uint32_t FindUnitIndex(DIERef::Section section, dw_offset_t offset); - DISALLOW_COPY_AND_ASSIGN(DWARFDebugInfo); + DWARFDebugInfo(const DWARFDebugInfo &) = delete; + const DWARFDebugInfo &operator=(const DWARFDebugInfo &) = delete; }; -#endif // SymbolFileDWARF_DWARFDebugInfo_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFO_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 320500fe608d..f6425a889da8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugInfoEntry.cpp ---------------------------------*- C++ -*-===// +//===-- DWARFDebugInfoEntry.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -395,152 +395,14 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( return !ranges.IsEmpty(); } -// Dump -// -// Dumps a debug information entry and all of it's attributes to the specified -// stream. -void DWARFDebugInfoEntry::Dump(const DWARFUnit *cu, Stream &s, - uint32_t recurse_depth) const { - const DWARFDataExtractor &data = cu->GetData(); - lldb::offset_t offset = m_offset; - - if (data.ValidOffset(offset)) { - dw_uleb128_t abbrCode = data.GetULEB128(&offset); - - s.Printf("\n0x%8.8x: ", m_offset); - s.Indent(); - if (abbrCode != m_abbr_idx) { - s.Printf("error: DWARF has been modified\n"); - } else if (abbrCode) { - const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu); - if (abbrevDecl) { - s.PutCString(DW_TAG_value_to_name(abbrevDecl->Tag())); - s.Printf(" [%u] %c\n", abbrCode, abbrevDecl->HasChildren() ? '*' : ' '); - - // Dump all data in the .debug_info/.debug_types for the attributes - const uint32_t numAttributes = abbrevDecl->NumAttributes(); - for (uint32_t i = 0; i < numAttributes; ++i) { - DWARFFormValue form_value(cu); - dw_attr_t attr; - abbrevDecl->GetAttrAndFormValueByIndex(i, attr, form_value); - - DumpAttribute(cu, data, &offset, s, attr, form_value); - } - - const DWARFDebugInfoEntry *child = GetFirstChild(); - if (recurse_depth > 0 && child) { - s.IndentMore(); - - while (child) { - child->Dump(cu, s, recurse_depth - 1); - child = child->GetSibling(); - } - s.IndentLess(); - } - } else - s.Printf("Abbreviation code note found in 'debug_abbrev' class for " - "code: %u\n", - abbrCode); - } else { - s.Printf("NULL\n"); - } - } -} - -// DumpAttribute -// -// Dumps a debug information entry attribute along with it's form. Any special -// display of attributes is done (disassemble location lists, show enumeration -// values for attributes, etc). -void DWARFDebugInfoEntry::DumpAttribute( - const DWARFUnit *cu, const DWARFDataExtractor &data, - lldb::offset_t *offset_ptr, Stream &s, dw_attr_t attr, - DWARFFormValue &form_value) { - bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm); - - s.Printf(" "); - s.Indent(DW_AT_value_to_name(attr)); - - if (show_form) { - s.Printf("[%s", DW_FORM_value_to_name(form_value.Form())); - } - - if (!form_value.ExtractValue(data, offset_ptr)) - return; - - if (show_form) { - if (form_value.Form() == DW_FORM_indirect) { - s.Printf(" [%s]", DW_FORM_value_to_name(form_value.Form())); - } - - s.PutCString("] "); - } - - s.PutCString("( "); - - // Check to see if we have any special attribute formatters - switch (attr) { - case DW_AT_stmt_list: - s.Printf("0x%8.8" PRIx64, form_value.Unsigned()); - break; - - case DW_AT_language: - s.PutCString(DW_LANG_value_to_name(form_value.Unsigned())); - break; - - case DW_AT_encoding: - s.PutCString(DW_ATE_value_to_name(form_value.Unsigned())); - break; - - case DW_AT_frame_base: - case DW_AT_location: - case DW_AT_data_member_location: { - const uint8_t *blockData = form_value.BlockData(); - if (blockData) { - // Location description is inlined in data in the form value - DWARFDataExtractor locationData(data, - (*offset_ptr) - form_value.Unsigned(), - form_value.Unsigned()); - DWARFExpression::PrintDWARFExpression( - s, locationData, DWARFUnit::GetAddressByteSize(cu), 4, false); - } else { - // We have a location list offset as the value that is the offset into - // the .debug_loc section that describes the value over it's lifetime - uint64_t debug_loc_offset = form_value.Unsigned(); - DWARFExpression::PrintDWARFLocationList(s, cu, cu->GetLocationData(), - debug_loc_offset); - } - } break; - - case DW_AT_abstract_origin: - case DW_AT_specification: { - DWARFDIE abstract_die = form_value.Reference(); - form_value.Dump(s); - // *ostrm_ptr << HEX32 << abstract_die.GetOffset() << " ( "; - abstract_die.GetName(s); - } break; - - case DW_AT_type: { - DWARFDIE type_die = form_value.Reference(); - s.PutCString(" ( "); - type_die.AppendTypeName(s); - s.PutCString(" )"); - } break; - - default: - break; - } - - s.PutCString(" )\n"); -} - // Get all attribute values for a given DIE, including following any // specification or abstract origin attributes and including those in the // results. Any duplicate attributes will have the first instance take // precedence (this can happen for declaration attributes). -size_t DWARFDebugInfoEntry::GetAttributes( - const DWARFUnit *cu, DWARFAttributes &attributes, - uint32_t curr_depth) const { +size_t DWARFDebugInfoEntry::GetAttributes(const DWARFUnit *cu, + DWARFAttributes &attributes, + Recurse recurse, + uint32_t curr_depth) const { const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu); if (abbrevDecl) { const DWARFDataExtractor &data = cu->GetData(); @@ -571,11 +433,13 @@ size_t DWARFDebugInfoEntry::GetAttributes( break; } - if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin)) { + if (recurse == Recurse::yes && + ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin))) { if (form_value.ExtractValue(data, &offset)) { DWARFDIE spec_die = form_value.Reference(); if (spec_die) - spec_die.GetAttributes(attributes, curr_depth + 1); + spec_die.GetDIE()->GetAttributes(spec_die.GetCU(), attributes, + recurse, curr_depth + 1); } } else { llvm::Optional<uint8_t> fixed_skip_size = DWARFFormValue::GetFixedSize(form, cu); @@ -819,34 +683,9 @@ const char *DWARFDebugInfoEntry::GetPubname(const DWARFUnit *cu) const { return name; } -// BuildAddressRangeTable -void DWARFDebugInfoEntry::BuildAddressRangeTable( - const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { - if (m_tag) { - if (m_tag == DW_TAG_subprogram) { - dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; - dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; - if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) { - /// printf("BuildAddressRangeTable() 0x%8.8x: %30s: [0x%8.8x - - /// 0x%8.8x)\n", m_offset, DW_TAG_value_to_name(tag), lo_pc, hi_pc); - debug_aranges->AppendRange(cu->GetOffset(), lo_pc, hi_pc); - } - } - - const DWARFDebugInfoEntry *child = GetFirstChild(); - while (child) { - child->BuildAddressRangeTable(cu, debug_aranges); - child = child->GetSibling(); - } - } -} - -// BuildFunctionAddressRangeTable -// -// This function is very similar to the BuildAddressRangeTable function except -// that the actual DIE offset for the function is placed in the table instead -// of the compile unit offset (which is the way the standard .debug_aranges -// section does it). +/// This function is builds a table very similar to the standard .debug_aranges +/// table, except that the actual DIE offset for the function is placed in the +/// table instead of the compile unit offset. void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { if (m_tag) { @@ -854,8 +693,6 @@ void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) { - // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16" PRIx64 " - - // 0x%16.16" PRIx64 ")\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY debug_aranges->AppendRange(GetOffset(), lo_pc, hi_pc); } } @@ -868,25 +705,34 @@ void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( } } -void DWARFDebugInfoEntry::GetDWARFDeclContext( - DWARFUnit *cu, DWARFDeclContext &dwarf_decl_ctx) const { - const dw_tag_t tag = Tag(); - if (tag != DW_TAG_compile_unit && tag != DW_TAG_partial_unit) { - dwarf_decl_ctx.AppendDeclContext(tag, GetName(cu)); - DWARFDIE parent_decl_ctx_die = GetParentDeclContextDIE(cu); - if (parent_decl_ctx_die && parent_decl_ctx_die.GetDIE() != this) { - if (parent_decl_ctx_die.Tag() != DW_TAG_compile_unit && - parent_decl_ctx_die.Tag() != DW_TAG_partial_unit) - parent_decl_ctx_die.GetDIE()->GetDWARFDeclContext( - parent_decl_ctx_die.GetCU(), dwarf_decl_ctx); - } +DWARFDeclContext +DWARFDebugInfoEntry::GetDWARFDeclContextStatic(const DWARFDebugInfoEntry *die, + DWARFUnit *cu) { + DWARFDeclContext dwarf_decl_ctx; + for (;;) { + const dw_tag_t tag = die->Tag(); + if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) + return dwarf_decl_ctx; + dwarf_decl_ctx.AppendDeclContext(tag, die->GetName(cu)); + DWARFDIE parent_decl_ctx_die = die->GetParentDeclContextDIE(cu); + if (!parent_decl_ctx_die || parent_decl_ctx_die.GetDIE() == die) + return dwarf_decl_ctx; + if (parent_decl_ctx_die.Tag() == DW_TAG_compile_unit || + parent_decl_ctx_die.Tag() == DW_TAG_partial_unit) + return dwarf_decl_ctx; + die = parent_decl_ctx_die.GetDIE(); + cu = parent_decl_ctx_die.GetCU(); } } +DWARFDeclContext DWARFDebugInfoEntry::GetDWARFDeclContext(DWARFUnit *cu) const { + return GetDWARFDeclContextStatic(this, cu); +} + DWARFDIE DWARFDebugInfoEntry::GetParentDeclContextDIE(DWARFUnit *cu) const { DWARFAttributes attributes; - GetAttributes(cu, attributes); + GetAttributes(cu, attributes, Recurse::yes); return GetParentDeclContextDIE(cu, attributes); } @@ -936,7 +782,7 @@ DWARFDebugInfoEntry::GetParentDeclContextDIE( const char *DWARFDebugInfoEntry::GetQualifiedName(DWARFUnit *cu, std::string &storage) const { DWARFAttributes attributes; - GetAttributes(cu, attributes); + GetAttributes(cu, attributes, Recurse::yes); return GetQualifiedName(cu, attributes, storage); } @@ -993,209 +839,6 @@ DWARFDebugInfoEntry::GetQualifiedName(DWARFUnit *cu, return storage.c_str(); } -bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, DWARFUnit *cu, - DWARFDebugInfoEntry **function_die, - DWARFDebugInfoEntry **block_die) { - bool found_address = false; - if (m_tag) { - bool check_children = false; - bool match_addr_range = false; - // printf("0x%8.8x: %30s: address = 0x%8.8x - ", m_offset, - // DW_TAG_value_to_name(tag), address); - switch (m_tag) { - case DW_TAG_array_type: - break; - case DW_TAG_class_type: - check_children = true; - break; - case DW_TAG_entry_point: - case DW_TAG_enumeration_type: - case DW_TAG_formal_parameter: - case DW_TAG_imported_declaration: - case DW_TAG_label: - break; - case DW_TAG_lexical_block: - check_children = true; - match_addr_range = true; - break; - case DW_TAG_member: - case DW_TAG_pointer_type: - case DW_TAG_reference_type: - break; - case DW_TAG_compile_unit: - match_addr_range = true; - break; - case DW_TAG_string_type: - break; - case DW_TAG_structure_type: - check_children = true; - break; - case DW_TAG_subroutine_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - case DW_TAG_unspecified_parameters: - case DW_TAG_variant: - break; - case DW_TAG_common_block: - check_children = true; - break; - case DW_TAG_common_inclusion: - case DW_TAG_inheritance: - break; - case DW_TAG_inlined_subroutine: - check_children = true; - match_addr_range = true; - break; - case DW_TAG_module: - match_addr_range = true; - break; - case DW_TAG_ptr_to_member_type: - case DW_TAG_set_type: - case DW_TAG_subrange_type: - case DW_TAG_with_stmt: - case DW_TAG_access_declaration: - case DW_TAG_base_type: - break; - case DW_TAG_catch_block: - match_addr_range = true; - break; - case DW_TAG_const_type: - case DW_TAG_constant: - case DW_TAG_enumerator: - case DW_TAG_file_type: - case DW_TAG_friend: - case DW_TAG_namelist: - case DW_TAG_namelist_item: - case DW_TAG_packed_type: - break; - case DW_TAG_subprogram: - match_addr_range = true; - break; - case DW_TAG_template_type_parameter: - case DW_TAG_template_value_parameter: - case DW_TAG_GNU_template_parameter_pack: - case DW_TAG_thrown_type: - break; - case DW_TAG_try_block: - match_addr_range = true; - break; - case DW_TAG_variant_part: - case DW_TAG_variable: - case DW_TAG_volatile_type: - case DW_TAG_dwarf_procedure: - case DW_TAG_restrict_type: - case DW_TAG_interface_type: - break; - case DW_TAG_namespace: - check_children = true; - break; - case DW_TAG_imported_module: - case DW_TAG_unspecified_type: - break; - case DW_TAG_partial_unit: - match_addr_range = true; - break; - case DW_TAG_imported_unit: - case DW_TAG_shared_type: - default: - break; - } - - if (match_addr_range) { - dw_addr_t lo_pc = - GetAttributeValueAsAddress(cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS); - if (lo_pc != LLDB_INVALID_ADDRESS) { - dw_addr_t hi_pc = GetAttributeHighPC(cu, lo_pc, LLDB_INVALID_ADDRESS); - if (hi_pc != LLDB_INVALID_ADDRESS) { - // printf("\n0x%8.8x: %30s: address = 0x%8.8x [0x%8.8x - 0x%8.8x) ", - // m_offset, DW_TAG_value_to_name(tag), address, lo_pc, hi_pc); - if ((lo_pc <= address) && (address < hi_pc)) { - found_address = true; - // puts("***MATCH***"); - switch (m_tag) { - case DW_TAG_compile_unit: // File - case DW_TAG_partial_unit: // File - check_children = - ((function_die != nullptr) || (block_die != nullptr)); - break; - - case DW_TAG_subprogram: // Function - if (function_die) - *function_die = this; - check_children = (block_die != nullptr); - break; - - case DW_TAG_inlined_subroutine: // Inlined Function - case DW_TAG_lexical_block: // Block { } in code - if (block_die) { - *block_die = this; - check_children = true; - } - break; - - default: - check_children = true; - break; - } - } - } else { - // Compile units may not have a valid high/low pc when there - // are address gaps in subroutines so we must always search - // if there is no valid high and low PC. - check_children = - (m_tag == DW_TAG_compile_unit || m_tag == DW_TAG_partial_unit) && - ((function_die != nullptr) || (block_die != nullptr)); - } - } else { - DWARFRangeList ranges; - if (GetAttributeAddressRanges(cu, ranges, /*check_hi_lo_pc*/ false) && - ranges.FindEntryThatContains(address)) { - found_address = true; - // puts("***MATCH***"); - switch (m_tag) { - case DW_TAG_compile_unit: // File - case DW_TAG_partial_unit: // File - check_children = - ((function_die != nullptr) || (block_die != nullptr)); - break; - - case DW_TAG_subprogram: // Function - if (function_die) - *function_die = this; - check_children = (block_die != nullptr); - break; - - case DW_TAG_inlined_subroutine: // Inlined Function - case DW_TAG_lexical_block: // Block { } in code - if (block_die) { - *block_die = this; - check_children = true; - } - break; - - default: - check_children = true; - break; - } - } else { - check_children = false; - } - } - } - - if (check_children) { - // printf("checking children\n"); - DWARFDebugInfoEntry *child = GetFirstChild(); - while (child) { - if (child->LookupAddress(address, cu, function_die, block_die)) - return true; - child = child->GetSibling(); - } - } - } - return found_address; -} - lldb::offset_t DWARFDebugInfoEntry::GetFirstAttributeOffset() const { return GetOffset() + llvm::getULEB128Size(m_abbr_idx); } @@ -1210,6 +853,29 @@ DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const { return nullptr; } +bool DWARFDebugInfoEntry::IsGlobalOrStaticScopeVariable() const { + if (Tag() != DW_TAG_variable) + return false; + const DWARFDebugInfoEntry *parent_die = GetParent(); + while (parent_die != nullptr) { + switch (parent_die->Tag()) { + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + return false; + + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + return true; + + default: + break; + } + parent_die = parent_die->GetParent(); + } + return false; +} + bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const { return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx && m_sibling_idx == rhs.m_sibling_idx && diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index f35af6e7d498..3019e1767f18 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -6,13 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDebugInfoEntry_h_ -#define SymbolFileDWARF_DWARFDebugInfoEntry_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H #include "SymbolFileDWARF.h" #include "llvm/ADT/SmallVector.h" #include "DWARFAbbreviationDeclaration.h" +#include "DWARFBaseDIE.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugRanges.h" #include <map> @@ -41,23 +42,17 @@ public: bool operator==(const DWARFDebugInfoEntry &rhs) const; bool operator!=(const DWARFDebugInfoEntry &rhs) const; - void BuildAddressRangeTable(const DWARFUnit *cu, - DWARFDebugAranges *debug_aranges) const; - void BuildFunctionAddressRangeTable(const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; bool Extract(const lldb_private::DWARFDataExtractor &data, const DWARFUnit *cu, lldb::offset_t *offset_ptr); - bool LookupAddress(const dw_addr_t address, DWARFUnit *cu, - DWARFDebugInfoEntry **function_die, - DWARFDebugInfoEntry **block_die); - - size_t GetAttributes(const DWARFUnit *cu, - DWARFAttributes &attrs, - uint32_t curr_depth = 0) - const; // "curr_depth" for internal use only, don't set this yourself!!! + using Recurse = DWARFBaseDIE::Recurse; + size_t GetAttributes(const DWARFUnit *cu, DWARFAttributes &attrs, + Recurse recurse = Recurse::yes) const { + return GetAttributes(cu, attrs, recurse, 0 /* curr_depth */); + } dw_offset_t GetAttributeValue(const DWARFUnit *cu, const dw_attr_t attr, @@ -106,15 +101,6 @@ public: const char *GetQualifiedName(DWARFUnit *cu, const DWARFAttributes &attributes, std::string &storage) const; - void Dump(const DWARFUnit *cu, lldb_private::Stream &s, - uint32_t recurse_depth) const; - - static void - DumpAttribute(const DWARFUnit *cu, - const lldb_private::DWARFDataExtractor &data, - lldb::offset_t *offset_ptr, lldb_private::Stream &s, - dw_attr_t attr, DWARFFormValue &form_value); - bool GetDIENamesAndRanges( DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &rangeList, int &decl_file, int &decl_line, @@ -162,8 +148,7 @@ public: return HasChildren() ? this + 1 : nullptr; } - void GetDWARFDeclContext(DWARFUnit *cu, - DWARFDeclContext &dwarf_decl_ctx) const; + DWARFDeclContext GetDWARFDeclContext(DWARFUnit *cu) const; DWARFDIE GetParentDeclContextDIE(DWARFUnit *cu) const; DWARFDIE GetParentDeclContextDIE(DWARFUnit *cu, @@ -172,7 +157,15 @@ public: void SetSiblingIndex(uint32_t idx) { m_sibling_idx = idx; } void SetParentIndex(uint32_t idx) { m_parent_idx = idx; } + // This function returns true if the variable scope is either + // global or (file-static). It will return false for static variables + // that are local to a function, as they have local scope. + bool IsGlobalOrStaticScopeVariable() const; + protected: + static DWARFDeclContext + GetDWARFDeclContextStatic(const DWARFDebugInfoEntry *die, DWARFUnit *cu); + dw_offset_t m_offset; // Offset within the .debug_info/.debug_types uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. // If zero this die has no parent @@ -185,6 +178,10 @@ protected: /// A copy of the DW_TAG value so we don't have to go through the compile /// unit abbrev table dw_tag_t m_tag = llvm::dwarf::DW_TAG_null; + +private: + size_t GetAttributes(const DWARFUnit *cu, DWARFAttributes &attrs, + Recurse recurse, uint32_t curr_depth) const; }; -#endif // SymbolFileDWARF_DWARFDebugInfoEntry_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp index 4238be7ec1c3..278950a9f336 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugMacro.cpp -------------------------------------*- C++ -*-===// +//===-- DWARFDebugMacro.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h index c3a93a9f4d14..5c0338e950eb 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDebugMacro_h_ -#define SymbolFileDWARF_DWARFDebugMacro_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGMACRO_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGMACRO_H #include <map> @@ -58,4 +58,4 @@ public: lldb_private::DebugMacrosSP &debug_macros_sp); }; -#endif // SymbolFileDWARF_DWARFDebugMacro_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGMACRO_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index 6c074002cb20..6a0f11d2a1c4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===// +//===-- DWARFDebugRanges.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h index 1888a7760f27..b587845a67d9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDebugRanges_h_ -#define SymbolFileDWARF_DWARFDebugRanges_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGRANGES_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGRANGES_H #include "lldb/Core/dwarf.h" #include <map> @@ -39,4 +39,4 @@ protected: range_map m_range_map; }; -#endif // SymbolFileDWARF_DWARFDebugRanges_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGRANGES_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp index a664314035e4..f4c8c14cc8af 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDeclContext.cpp ------------------------------------*- C++ -*-===// +//===-- DWARFDeclContext.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h index 348b33464a54..9072b2dc0115 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDeclContext_h_ -#define SymbolFileDWARF_DWARFDeclContext_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H #include <string> #include <vector> @@ -48,6 +48,7 @@ public: } bool operator==(const DWARFDeclContext &rhs) const; + bool operator!=(const DWARFDeclContext &rhs) const { return !(*this == rhs); } uint32_t GetSize() const { return m_entries.size(); } @@ -85,4 +86,4 @@ protected: lldb::LanguageType m_language; }; -#endif // SymbolFileDWARF_DWARFDeclContext_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp index 2ae1bbc9f507..4e99a295ce50 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDefines.cpp ----------------------------------------*- C++ -*-===// +//===-- DWARFDefines.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -58,321 +58,6 @@ const char *DW_OP_value_to_name(uint32_t val) { return llvmstr.data(); } -DRC_class DW_OP_value_to_class(uint32_t val) { - // FIXME: If we just used llvm's DWARFExpression printer, we could delete - // all this code (and more in lldb's DWARFExpression.cpp). - switch (val) { - case 0x03: - return DRC_ONEOPERAND; - case 0x06: - return DRC_ZEROOPERANDS; - case 0x08: - return DRC_ONEOPERAND; - case 0x09: - return DRC_ONEOPERAND; - case 0x0a: - return DRC_ONEOPERAND; - case 0x0b: - return DRC_ONEOPERAND; - case 0x0c: - return DRC_ONEOPERAND; - case 0x0d: - return DRC_ONEOPERAND; - case 0x0e: - return DRC_ONEOPERAND; - case 0x0f: - return DRC_ONEOPERAND; - case 0x10: - return DRC_ONEOPERAND; - case 0x11: - return DRC_ONEOPERAND; - case 0x12: - return DRC_ZEROOPERANDS; - case 0x13: - return DRC_ZEROOPERANDS; - case 0x14: - return DRC_ZEROOPERANDS; - case 0x15: - return DRC_ONEOPERAND; - case 0x16: - return DRC_ZEROOPERANDS; - case 0x17: - return DRC_ZEROOPERANDS; - case 0x18: - return DRC_ZEROOPERANDS; - case 0x19: - return DRC_ZEROOPERANDS; - case 0x1a: - return DRC_ZEROOPERANDS; - case 0x1b: - return DRC_ZEROOPERANDS; - case 0x1c: - return DRC_ZEROOPERANDS; - case 0x1d: - return DRC_ZEROOPERANDS; - case 0x1e: - return DRC_ZEROOPERANDS; - case 0x1f: - return DRC_ZEROOPERANDS; - case 0x20: - return DRC_ZEROOPERANDS; - case 0x21: - return DRC_ZEROOPERANDS; - case 0x22: - return DRC_ZEROOPERANDS; - case 0x23: - return DRC_ONEOPERAND; - case 0x24: - return DRC_ZEROOPERANDS; - case 0x25: - return DRC_ZEROOPERANDS; - case 0x26: - return DRC_ZEROOPERANDS; - case 0x27: - return DRC_ZEROOPERANDS; - case 0x2f: - return DRC_ONEOPERAND; - case 0x28: - return DRC_ONEOPERAND; - case 0x29: - return DRC_ZEROOPERANDS; - case 0x2a: - return DRC_ZEROOPERANDS; - case 0x2b: - return DRC_ZEROOPERANDS; - case 0x2c: - return DRC_ZEROOPERANDS; - case 0x2d: - return DRC_ZEROOPERANDS; - case 0x2e: - return DRC_ZEROOPERANDS; - case 0x30: - return DRC_ZEROOPERANDS; - case 0x31: - return DRC_ZEROOPERANDS; - case 0x32: - return DRC_ZEROOPERANDS; - case 0x33: - return DRC_ZEROOPERANDS; - case 0x34: - return DRC_ZEROOPERANDS; - case 0x35: - return DRC_ZEROOPERANDS; - case 0x36: - return DRC_ZEROOPERANDS; - case 0x37: - return DRC_ZEROOPERANDS; - case 0x38: - return DRC_ZEROOPERANDS; - case 0x39: - return DRC_ZEROOPERANDS; - case 0x3a: - return DRC_ZEROOPERANDS; - case 0x3b: - return DRC_ZEROOPERANDS; - case 0x3c: - return DRC_ZEROOPERANDS; - case 0x3d: - return DRC_ZEROOPERANDS; - case 0x3e: - return DRC_ZEROOPERANDS; - case 0x3f: - return DRC_ZEROOPERANDS; - case 0x40: - return DRC_ZEROOPERANDS; - case 0x41: - return DRC_ZEROOPERANDS; - case 0x42: - return DRC_ZEROOPERANDS; - case 0x43: - return DRC_ZEROOPERANDS; - case 0x44: - return DRC_ZEROOPERANDS; - case 0x45: - return DRC_ZEROOPERANDS; - case 0x46: - return DRC_ZEROOPERANDS; - case 0x47: - return DRC_ZEROOPERANDS; - case 0x48: - return DRC_ZEROOPERANDS; - case 0x49: - return DRC_ZEROOPERANDS; - case 0x4a: - return DRC_ZEROOPERANDS; - case 0x4b: - return DRC_ZEROOPERANDS; - case 0x4c: - return DRC_ZEROOPERANDS; - case 0x4d: - return DRC_ZEROOPERANDS; - case 0x4e: - return DRC_ZEROOPERANDS; - case 0x4f: - return DRC_ZEROOPERANDS; - case 0x50: - return DRC_ZEROOPERANDS; - case 0x51: - return DRC_ZEROOPERANDS; - case 0x52: - return DRC_ZEROOPERANDS; - case 0x53: - return DRC_ZEROOPERANDS; - case 0x54: - return DRC_ZEROOPERANDS; - case 0x55: - return DRC_ZEROOPERANDS; - case 0x56: - return DRC_ZEROOPERANDS; - case 0x57: - return DRC_ZEROOPERANDS; - case 0x58: - return DRC_ZEROOPERANDS; - case 0x59: - return DRC_ZEROOPERANDS; - case 0x5a: - return DRC_ZEROOPERANDS; - case 0x5b: - return DRC_ZEROOPERANDS; - case 0x5c: - return DRC_ZEROOPERANDS; - case 0x5d: - return DRC_ZEROOPERANDS; - case 0x5e: - return DRC_ZEROOPERANDS; - case 0x5f: - return DRC_ZEROOPERANDS; - case 0x60: - return DRC_ZEROOPERANDS; - case 0x61: - return DRC_ZEROOPERANDS; - case 0x62: - return DRC_ZEROOPERANDS; - case 0x63: - return DRC_ZEROOPERANDS; - case 0x64: - return DRC_ZEROOPERANDS; - case 0x65: - return DRC_ZEROOPERANDS; - case 0x66: - return DRC_ZEROOPERANDS; - case 0x67: - return DRC_ZEROOPERANDS; - case 0x68: - return DRC_ZEROOPERANDS; - case 0x69: - return DRC_ZEROOPERANDS; - case 0x6a: - return DRC_ZEROOPERANDS; - case 0x6b: - return DRC_ZEROOPERANDS; - case 0x6c: - return DRC_ZEROOPERANDS; - case 0x6d: - return DRC_ZEROOPERANDS; - case 0x6e: - return DRC_ZEROOPERANDS; - case 0x6f: - return DRC_ZEROOPERANDS; - case 0x70: - return DRC_ONEOPERAND; - case 0x71: - return DRC_ONEOPERAND; - case 0x72: - return DRC_ONEOPERAND; - case 0x73: - return DRC_ONEOPERAND; - case 0x74: - return DRC_ONEOPERAND; - case 0x75: - return DRC_ONEOPERAND; - case 0x76: - return DRC_ONEOPERAND; - case 0x77: - return DRC_ONEOPERAND; - case 0x78: - return DRC_ONEOPERAND; - case 0x79: - return DRC_ONEOPERAND; - case 0x7a: - return DRC_ONEOPERAND; - case 0x7b: - return DRC_ONEOPERAND; - case 0x7c: - return DRC_ONEOPERAND; - case 0x7d: - return DRC_ONEOPERAND; - case 0x7e: - return DRC_ONEOPERAND; - case 0x7f: - return DRC_ONEOPERAND; - case 0x80: - return DRC_ONEOPERAND; - case 0x81: - return DRC_ONEOPERAND; - case 0x82: - return DRC_ONEOPERAND; - case 0x83: - return DRC_ONEOPERAND; - case 0x84: - return DRC_ONEOPERAND; - case 0x85: - return DRC_ONEOPERAND; - case 0x86: - return DRC_ONEOPERAND; - case 0x87: - return DRC_ONEOPERAND; - case 0x88: - return DRC_ONEOPERAND; - case 0x89: - return DRC_ONEOPERAND; - case 0x8a: - return DRC_ONEOPERAND; - case 0x8b: - return DRC_ONEOPERAND; - case 0x8c: - return DRC_ONEOPERAND; - case 0x8d: - return DRC_ONEOPERAND; - case 0x8e: - return DRC_ONEOPERAND; - case 0x8f: - return DRC_ONEOPERAND; - case 0x90: - return DRC_ONEOPERAND; - case 0x91: - return DRC_ONEOPERAND; - case 0x92: - return DRC_TWOOPERANDS; - case 0x93: - return DRC_ONEOPERAND; - case 0x94: - return DRC_ONEOPERAND; - case 0x95: - return DRC_ONEOPERAND; - case 0x96: - return DRC_ZEROOPERANDS; - case 0x97: - return DRC_DWARFv3 | DRC_ZEROOPERANDS; - case 0x98: - return DRC_DWARFv3 | DRC_ONEOPERAND; - case 0x99: - return DRC_DWARFv3 | DRC_ONEOPERAND; - case 0x9a: - return DRC_DWARFv3 | DRC_ONEOPERAND; - case 0xa3: /* DW_OP_entry_value */ - return DRC_TWOOPERANDS; - case 0xf0: - return DRC_ZEROOPERANDS; /* DW_OP_APPLE_uninit */ - case 0xe0: - return 0; - case 0xff: - return 0; - default: - return 0; - } -} - const char *DW_ATE_value_to_name(uint32_t val) { static char invalid[100]; llvm::StringRef llvmstr = llvm::dwarf::AttributeEncodingString(val); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h index d16cb07baf88..1b7102cd7e31 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFDefines_h_ -#define SymbolFileDWARF_DWARFDefines_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEFINES_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEFINES_H #include "lldb/Core/dwarf.h" #include <stdint.h> @@ -26,52 +26,12 @@ const char *DW_FORM_value_to_name(uint32_t val); const char *DW_OP_value_to_name(uint32_t val); -DRC_class DW_OP_value_to_class(uint32_t val); - const char *DW_ATE_value_to_name(uint32_t val); const char *DW_LANG_value_to_name(uint32_t val); const char *DW_LNS_value_to_name(uint32_t val); -/* These DRC are entirely our own construction, - although they are derived from various comments in the DWARF standard. - Most of these are not useful to the parser, but the DW_AT and DW_FORM - classes should prove to be usable in some fashion. */ - -#define DRC_0x65 0x1 -#define DRC_ADDRESS 0x2 -#define DRC_BLOCK 0x4 -#define DRC_CONSTANT 0x8 -#define DRC_DWARFv3 0x10 -#define DRC_FLAG 0x20 -#define DRC_INDIRECT_SPECIAL 0x40 -#define DRC_LINEPTR 0x80 -#define DRC_LOCEXPR 0x100 -#define DRC_LOCLISTPTR 0x200 -#define DRC_MACPTR 0x400 -#define DRC_ONEOPERAND 0x800 -#define DRC_OPERANDONE_1BYTE_DELTA 0x1000 -#define DRC_OPERANDONE_2BYTE_DELTA 0x2000 -#define DRC_OPERANDONE_4BYTE_DELTA 0x4000 -#define DRC_OPERANDONE_ADDRESS 0x8000 -#define DRC_OPERANDONE_BLOCK 0x10000 -#define DRC_OPERANDONE_SLEB128_OFFSET 0x20000 -#define DRC_OPERANDONE_ULEB128_OFFSET 0x40000 -#define DRC_OPERANDONE_ULEB128_REGISTER 0x80000 -#define DRC_OPERANDTWO_BLOCK 0x100000 -#define DRC_OPERANDTWO_SLEB128_OFFSET 0x200000 -#define DRC_OPERANDTWO_ULEB128_OFFSET 0x400000 -#define DRC_OPERANDTWO_ULEB128_REGISTER 0x800000 -#define DRC_OPERNADONE_ULEB128_REGISTER 0x1000000 -#define DRC_RANGELISTPTR 0x2000000 -#define DRC_REFERENCE 0x4000000 -#define DRC_STRING 0x8000000 -#define DRC_TWOOPERANDS 0x10000000 -#define DRC_VENDOR_GNU 0x20000000 -#define DRC_VENDOR_MIPS 0x40000000 -#define DRC_ZEROOPERANDS 0x80000000 - } // namespace lldb_private -#endif // SymbolFileDWARF_DWARFDefines_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEFINES_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index f660cc32b3f8..305f1cbd2826 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -1,4 +1,4 @@ -//===-- DWARFFormValue.cpp --------------------------------------*- C++ -*-===// +//===-- DWARFFormValue.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -454,40 +454,26 @@ void DWARFFormValue::Dump(Stream &s) const { } const char *DWARFFormValue::AsCString() const { - SymbolFileDWARF &symbol_file = m_unit->GetSymbolFileDWARF(); + DWARFContext &context = m_unit->GetSymbolFileDWARF().GetDWARFContext(); - if (m_form == DW_FORM_string) { + if (m_form == DW_FORM_string) return m_value.value.cstr; - } else if (m_form == DW_FORM_strp) { - return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr( - m_value.value.uval); - } else if (m_form == DW_FORM_GNU_str_index) { - uint32_t index_size = 4; - lldb::offset_t offset = m_value.value.uval * index_size; - dw_offset_t str_offset = - symbol_file.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64( - &offset, index_size); - return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr( - str_offset); - } - - if (m_form == DW_FORM_strx || m_form == DW_FORM_strx1 || - m_form == DW_FORM_strx2 || m_form == DW_FORM_strx3 || - m_form == DW_FORM_strx4) { - - // The same code as above. - uint32_t indexSize = 4; - lldb::offset_t offset = - m_unit->GetStrOffsetsBase() + m_value.value.uval * indexSize; - dw_offset_t strOffset = - symbol_file.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64( - &offset, indexSize); - return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr(strOffset); + if (m_form == DW_FORM_strp) + return context.getOrLoadStrData().PeekCStr(m_value.value.uval); + + if (m_form == DW_FORM_GNU_str_index || m_form == DW_FORM_strx || + m_form == DW_FORM_strx1 || m_form == DW_FORM_strx2 || + m_form == DW_FORM_strx3 || m_form == DW_FORM_strx4) { + + llvm::Optional<uint64_t> offset = + m_unit->GetStringOffsetSectionItem(m_value.value.uval); + if (!offset) + return nullptr; + return context.getOrLoadStrData().PeekCStr(*offset); } if (m_form == DW_FORM_line_strp) - return symbol_file.GetDWARFContext().getOrLoadLineStrData().PeekCStr( - m_value.value.uval); + return context.getOrLoadLineStrData().PeekCStr(m_value.value.uval); return nullptr; } @@ -531,7 +517,7 @@ DWARFDIE DWARFFormValue::Reference() const { case DW_FORM_ref_addr: { DWARFUnit *ref_cu = - m_unit->GetSymbolFileDWARF().DebugInfo()->GetUnitContainingDIEOffset( + m_unit->GetSymbolFileDWARF().DebugInfo().GetUnitContainingDIEOffset( DIERef::Section::DebugInfo, value); if (!ref_cu) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( @@ -544,7 +530,7 @@ DWARFDIE DWARFFormValue::Reference() const { case DW_FORM_ref_sig8: { DWARFTypeUnit *tu = - m_unit->GetSymbolFileDWARF().DebugInfo()->GetTypeUnitForHash(value); + m_unit->GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(value); if (!tu) return {}; return tu->GetDIE(tu->GetTypeOffset()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index 848db2990ded..b401352c693d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFFormValue_h_ -#define SymbolFileDWARF_DWARFFormValue_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFFORMVALUE_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFFORMVALUE_H #include "DWARFDataExtractor.h" #include <stddef.h> @@ -86,4 +86,4 @@ protected: ValueType m_value; // Contains all data for the form }; -#endif // SymbolFileDWARF_DWARFFormValue_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFFORMVALUE_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp index c122f756e81a..683033d0ee4c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp @@ -1,4 +1,4 @@ -//===-- DWARFIndex.cpp -----------------------------------------*- C++ -*-===// +//===-- DWARFIndex.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -11,20 +11,21 @@ #include "Plugins/SymbolFile/DWARF/DWARFDIE.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" +#include "lldb/Core/Module.h" + using namespace lldb_private; using namespace lldb; DWARFIndex::~DWARFIndex() = default; -void DWARFIndex::ProcessFunctionDIE(llvm::StringRef name, DIERef ref, - SymbolFileDWARF &dwarf, - const CompilerDeclContext &parent_decl_ctx, - uint32_t name_type_mask, - std::vector<DWARFDIE> &dies) { +bool DWARFIndex::ProcessFunctionDIE( + llvm::StringRef name, DIERef ref, SymbolFileDWARF &dwarf, + const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, + llvm::function_ref<bool(DWARFDIE die)> callback) { DWARFDIE die = dwarf.GetDIE(ref); if (!die) { ReportInvalidDIERef(ref, name); - return; + return true; } // Exit early if we're searching exclusively for methods or selectors and @@ -32,26 +33,22 @@ void DWARFIndex::ProcessFunctionDIE(llvm::StringRef name, DIERef ref, uint32_t looking_for_nonmethods = name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector); if (!looking_for_nonmethods && parent_decl_ctx.IsValid()) - return; + return true; // Otherwise, we need to also check that the context matches. If it does not // match, we do nothing. - if (!SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) - return; + if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) + return true; // In case of a full match, we just insert everything we find. - if (name_type_mask & eFunctionNameTypeFull) { - dies.push_back(die); - return; - } + if (name_type_mask & eFunctionNameTypeFull) + return callback(die); // If looking for ObjC selectors, we need to also check if the name is a // possible selector. if (name_type_mask & eFunctionNameTypeSelector && - ObjCLanguage::IsPossibleObjCMethodName(die.GetName())) { - dies.push_back(die); - return; - } + ObjCLanguage::IsPossibleObjCMethodName(die.GetName())) + return callback(die); bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod; bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase; @@ -61,6 +58,29 @@ void DWARFIndex::ProcessFunctionDIE(llvm::StringRef name, DIERef ref, // searching for. if ((looking_for_methods && looking_for_functions) || looking_for_methods == die.IsMethod()) - dies.push_back(die); + return callback(die); } + + return true; +} + +DWARFIndex::DIERefCallbackImpl::DIERefCallbackImpl( + const DWARFIndex &index, llvm::function_ref<bool(DWARFDIE die)> callback, + llvm::StringRef name) + : m_index(index), + m_dwarf(*llvm::cast<SymbolFileDWARF>(index.m_module.GetSymbolFile())), + m_callback(callback), m_name(name) {} + +bool DWARFIndex::DIERefCallbackImpl::operator()(DIERef ref) const { + if (DWARFDIE die = m_dwarf.GetDIE(ref)) + return m_callback(die); + m_index.ReportInvalidDIERef(ref, m_name); + return true; +} + +void DWARFIndex::ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const { + m_module.ReportErrorIfModifyDetected( + "the DWARF debug information has been modified (accelerator table had " + "bad die 0x%8.8x for '%s')\n", + ref.die_offset(), name.str().c_str()); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h index e3c7c5e63ac8..ecf82a910b66 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_DWARFINDEX_H -#define LLDB_DWARFINDEX_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFINDEX_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFINDEX_H #include "Plugins/SymbolFile/DWARF/DIERef.h" #include "Plugins/SymbolFile/DWARF/DWARFDIE.h" @@ -27,26 +27,38 @@ public: /// Finds global variables with the given base name. Any additional filtering /// (e.g., to only retrieve variables from a given context) should be done by /// the consumer. - virtual void GetGlobalVariables(ConstString basename, DIEArray &offsets) = 0; + virtual void + GetGlobalVariables(ConstString basename, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; - virtual void GetGlobalVariables(const RegularExpression ®ex, - DIEArray &offsets) = 0; - virtual void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) = 0; - virtual void GetObjCMethods(ConstString class_name, DIEArray &offsets) = 0; - virtual void GetCompleteObjCClass(ConstString class_name, - bool must_be_implementation, - DIEArray &offsets) = 0; - virtual void GetTypes(ConstString name, DIEArray &offsets) = 0; - virtual void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) = 0; - virtual void GetNamespaces(ConstString name, DIEArray &offsets) = 0; - virtual void GetFunctions(ConstString name, SymbolFileDWARF &dwarf, - const CompilerDeclContext &parent_decl_ctx, - uint32_t name_type_mask, - std::vector<DWARFDIE> &dies) = 0; - virtual void GetFunctions(const RegularExpression ®ex, - DIEArray &offsets) = 0; + virtual void + GetGlobalVariables(const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; + virtual void + GetGlobalVariables(const DWARFUnit &cu, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; + virtual void + GetObjCMethods(ConstString class_name, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; + virtual void + GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; + virtual void GetTypes(ConstString name, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; + virtual void GetTypes(const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; + virtual void + GetNamespaces(ConstString name, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; + virtual void + GetFunctions(ConstString name, SymbolFileDWARF &dwarf, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; + virtual void + GetFunctions(const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) = 0; - virtual void ReportInvalidDIERef(const DIERef &ref, llvm::StringRef name) = 0; virtual void Dump(Stream &s) = 0; protected: @@ -56,11 +68,33 @@ protected: /// the function given by "ref" matches search criteria given by /// "parent_decl_ctx" and "name_type_mask", it is inserted into the "dies" /// vector. - void ProcessFunctionDIE(llvm::StringRef name, DIERef ref, + bool ProcessFunctionDIE(llvm::StringRef name, DIERef ref, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, - uint32_t name_type_mask, std::vector<DWARFDIE> &dies); + uint32_t name_type_mask, + llvm::function_ref<bool(DWARFDIE die)> callback); + + class DIERefCallbackImpl { + public: + DIERefCallbackImpl(const DWARFIndex &index, + llvm::function_ref<bool(DWARFDIE die)> callback, + llvm::StringRef name); + bool operator()(DIERef ref) const; + + private: + const DWARFIndex &m_index; + SymbolFileDWARF &m_dwarf; + const llvm::function_ref<bool(DWARFDIE die)> m_callback; + const llvm::StringRef m_name; + }; + DIERefCallbackImpl + DIERefCallback(llvm::function_ref<bool(DWARFDIE die)> callback, + llvm::StringRef name = {}) const { + return DIERefCallbackImpl(*this, callback, name); + } + + void ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const; }; } // namespace lldb_private -#endif // LLDB_DWARFINDEX_H +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFINDEX_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp index fcc031bf1ea0..48d578977c57 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp @@ -1,4 +1,4 @@ -//===-- DWARFTypeUnit.cpp ---------------------------------------*- C++ -*-===// +//===-- DWARFTypeUnit.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h index 8967509c081a..5e4d48ab285a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFTypeUnit_h_ -#define SymbolFileDWARF_DWARFTypeUnit_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFTYPEUNIT_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFTYPEUNIT_H #include "DWARFUnit.h" #include "llvm/Support/Error.h" @@ -34,4 +34,4 @@ private: friend class DWARFUnit; }; -#endif // SymbolFileDWARF_DWARFTypeUnit_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFTYPEUNIT_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 22e3e40dac93..dfa40759a7ff 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -1,4 +1,4 @@ -//===-- DWARFUnit.cpp -------------------------------------------*- C++ -*-===// +//===-- DWARFUnit.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -188,7 +188,7 @@ void DWARFUnit::ExtractDIEsRWLocked() { // simultaneously. We also don't need to do that as the dwo file will // contain a superset of information. So, we don't even attempt to parse // any remaining DIEs. - if (m_dwo_symbol_file) { + if (m_dwo) { m_die_array.front().SetHasChildren(false); break; } @@ -249,10 +249,8 @@ void DWARFUnit::ExtractDIEsRWLocked() { m_die_array.shrink_to_fit(); - if (m_dwo_symbol_file) { - DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - dwo_cu->ExtractDIEsIfNeeded(); - } + if (m_dwo) + m_dwo->ExtractDIEsIfNeeded(); } // This is used when a split dwarf is enabled. @@ -261,23 +259,33 @@ void DWARFUnit::ExtractDIEsRWLocked() { // .debug_str_offsets. At the same time, the corresponding split debug unit also // may use DW_FORM_strx* forms pointing to its own .debug_str_offsets.dwo and // for that case, we should find the offset (skip the section header). -static void SetDwoStrOffsetsBase(DWARFUnit *dwo_cu) { +void DWARFUnit::SetDwoStrOffsetsBase() { lldb::offset_t baseOffset = 0; - const DWARFDataExtractor &strOffsets = - dwo_cu->GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData(); - uint64_t length = strOffsets.GetU32(&baseOffset); - if (length == 0xffffffff) - length = strOffsets.GetU64(&baseOffset); + if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) { + if (const auto *contribution = + entry->getContribution(llvm::DW_SECT_STR_OFFSETS)) + baseOffset = contribution->Offset; + else + return; + } - // Check version. - if (strOffsets.GetU16(&baseOffset) < 5) - return; + if (GetVersion() >= 5) { + const DWARFDataExtractor &strOffsets = + GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData(); + uint64_t length = strOffsets.GetU32(&baseOffset); + if (length == 0xffffffff) + length = strOffsets.GetU64(&baseOffset); - // Skip padding. - baseOffset += 2; + // Check version. + if (strOffsets.GetU16(&baseOffset) < 5) + return; + + // Skip padding. + baseOffset += 2; + } - dwo_cu->SetStrOffsetsBase(baseOffset); + SetStrOffsetsBase(baseOffset); } // m_die_array_mutex must be already held as read/write. @@ -336,32 +344,27 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { } } - if (m_is_dwo) + if (m_is_dwo) { + SetDwoStrOffsetsBase(); return; + } - std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = + std::shared_ptr<SymbolFileDWARFDwo> dwo_symbol_file = m_dwarf.GetDwoSymbolFileForCompileUnit(*this, cu_die); if (!dwo_symbol_file) return; - DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); + uint64_t main_dwo_id = + cu_die.GetAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, 0); + DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(main_dwo_id); if (!dwo_cu) return; // Can't fetch the compile unit from the dwo file. + dwo_cu->SetUserData(this); DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); if (!dwo_cu_die.IsValid()) return; // Can't fetch the compile unit DIE from the dwo file. - uint64_t main_dwo_id = - cu_die.GetAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, 0); - uint64_t sub_dwo_id = - dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); - if (main_dwo_id != sub_dwo_id) - return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to - // a differectn compilation. - - m_dwo_symbol_file = std::move(dwo_symbol_file); - // Here for DWO CU we want to use the address base set in the skeleton unit // (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base // otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_* @@ -375,21 +378,18 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { if (GetVersion() <= 4 && gnu_ranges_base) dwo_cu->SetRangesBase(*gnu_ranges_base); - else if (m_dwo_symbol_file->GetDWARFContext() + else if (dwo_symbol_file->GetDWARFContext() .getOrLoadRngListsData() .GetByteSize() > 0) dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); - if (GetVersion() >= 5 && m_dwo_symbol_file->GetDWARFContext() - .getOrLoadLocListsData() - .GetByteSize() > 0) + if (GetVersion() >= 5 && + dwo_symbol_file->GetDWARFContext().getOrLoadLocListsData().GetByteSize() > + 0) dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); dwo_cu->SetBaseAddress(GetBaseAddress()); - for (size_t i = 0; i < m_dwo_symbol_file->DebugInfo()->GetNumUnits(); ++i) { - DWARFUnit *unit = m_dwo_symbol_file->DebugInfo()->GetUnitAtIndex(i); - SetDwoStrOffsetsBase(unit); - } + m_dwo = std::shared_ptr<DWARFUnit>(std::move(dwo_symbol_file), dwo_cu); } DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { @@ -467,18 +467,25 @@ void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) { std::unique_ptr<llvm::DWARFLocationTable> DWARFUnit::GetLocationTable(const DataExtractor &data) const { llvm::DWARFDataExtractor llvm_data( - toStringRef(data.GetData()), - data.GetByteOrder() == lldb::eByteOrderLittle, data.GetAddressByteSize()); + data.GetData(), data.GetByteOrder() == lldb::eByteOrderLittle, + data.GetAddressByteSize()); if (m_is_dwo || GetVersion() >= 5) return std::make_unique<llvm::DWARFDebugLoclists>(llvm_data, GetVersion()); return std::make_unique<llvm::DWARFDebugLoc>(llvm_data); } -const DWARFDataExtractor &DWARFUnit::GetLocationData() const { +DWARFDataExtractor DWARFUnit::GetLocationData() const { DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext(); - return GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() - : Ctx.getOrLoadLocData(); + const DWARFDataExtractor &data = + GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() : Ctx.getOrLoadLocData(); + if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) { + if (const auto *contribution = entry->getContribution(llvm::DW_SECT_EXT_LOC)) + return DWARFDataExtractor(data, contribution->Offset, + contribution->Length); + return DWARFDataExtractor(); + } + return data; } void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) { @@ -506,18 +513,14 @@ void DWARFUnit::ClearDIEsRWLocked() { m_die_array.clear(); m_die_array.shrink_to_fit(); - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->ClearDIEsRWLocked(); + if (m_dwo) + m_dwo->ClearDIEsRWLocked(); } lldb::ByteOrder DWARFUnit::GetByteOrder() const { return m_dwarf.GetObjectFile()->GetByteOrder(); } -llvm::Expected<TypeSystem &> DWARFUnit::GetTypeSystem() { - return m_dwarf.GetTypeSystemForLanguage(GetLanguageType()); -} - void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } // Compare function DWARFDebugAranges::Range structures @@ -534,9 +537,6 @@ static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, DWARFDIE DWARFUnit::GetDIE(dw_offset_t die_offset) { if (die_offset != DW_INVALID_OFFSET) { - if (GetDwoSymbolFile()) - return GetDwoSymbolFile()->GetCompileUnit()->GetDIE(die_offset); - if (ContainsDIEOffset(die_offset)) { ExtractDIEsIfNeeded(); DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); @@ -555,8 +555,9 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) { } DWARFUnit &DWARFUnit::GetNonSkeletonUnit() { - if (SymbolFileDWARFDwo *dwo = GetDwoSymbolFile()) - return *dwo->GetCompileUnit(); + ExtractUnitDIEIfNeeded(); + if (m_dwo) + return *m_dwo; return *this; } @@ -570,11 +571,7 @@ uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; } void *DWARFUnit::GetUserData() const { return m_user_data; } -void DWARFUnit::SetUserData(void *d) { - m_user_data = d; - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); -} +void DWARFUnit::SetUserData(void *d) { m_user_data = d; } bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() { return GetProducer() != eProducerLLVMGCC; @@ -658,28 +655,17 @@ uint32_t DWARFUnit::GetProducerVersionUpdate() { ParseProducerInfo(); return m_producer_version_update; } -LanguageType DWARFUnit::LanguageTypeFromDWARF(uint64_t val) { - // Note: user languages between lo_user and hi_user must be handled - // explicitly here. - switch (val) { - case DW_LANG_Mips_Assembler: - return eLanguageTypeMipsAssembler; - case DW_LANG_GOOGLE_RenderScript: - return eLanguageTypeExtRenderScript; - default: - return static_cast<LanguageType>(val); - } -} -LanguageType DWARFUnit::GetLanguageType() { - if (m_language_type != eLanguageTypeUnknown) - return m_language_type; +uint64_t DWARFUnit::GetDWARFLanguageType() { + if (m_language_type) + return *m_language_type; const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); - if (die) - m_language_type = LanguageTypeFromDWARF( - die->GetAttributeValueAsUnsigned(this, DW_AT_language, 0)); - return m_language_type; + if (!die) + m_language_type = 0; + else + m_language_type = die->GetAttributeValueAsUnsigned(this, DW_AT_language, 0); + return *m_language_type; } bool DWARFUnit::GetIsOptimized() { @@ -738,25 +724,6 @@ removeHostnameFromPathname(llvm::StringRef path_from_dwarf) { return path; } -static FileSpec resolveCompDir(const FileSpec &path) { - bool is_symlink = SymbolFileDWARF::GetSymlinkPaths().FindFileIndex( - 0, path, /*full*/ true) != UINT32_MAX; - - if (!is_symlink) - return path; - - namespace fs = llvm::sys::fs; - if (fs::get_file_type(path.GetPath(), false) != fs::file_type::symlink_file) - return path; - - FileSpec resolved_symlink; - const auto error = FileSystem::Instance().Readlink(path, resolved_symlink); - if (error.Success()) - return resolved_symlink; - - return path; -} - void DWARFUnit::ComputeCompDirAndGuessPathStyle() { m_comp_dir = FileSpec(); const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); @@ -768,7 +735,7 @@ void DWARFUnit::ComputeCompDirAndGuessPathStyle() { if (!comp_dir.empty()) { FileSpec::Style comp_dir_style = FileSpec::GuessPathStyle(comp_dir).getValueOr(FileSpec::Style::native); - m_comp_dir = resolveCompDir(FileSpec(comp_dir, comp_dir_style)); + m_comp_dir = FileSpec(comp_dir, comp_dir_style); } else { // Try to detect the style based on the DW_AT_name attribute, but just store // the detected style in the m_comp_dir field. @@ -795,21 +762,22 @@ void DWARFUnit::ComputeAbsolutePath() { SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() { ExtractUnitDIEIfNeeded(); - return m_dwo_symbol_file.get(); + if (m_dwo) + return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF()); + return nullptr; } const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { if (m_func_aranges_up == nullptr) { - m_func_aranges_up.reset(new DWARFDebugAranges()); + m_func_aranges_up = std::make_unique<DWARFDebugAranges>(); const DWARFDebugInfoEntry *die = DIEPtr(); if (die) die->BuildFunctionAddressRangeTable(this, m_func_aranges_up.get()); - if (m_dwo_symbol_file) { - DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); + if (m_dwo) { + const DWARFDebugInfoEntry *dwo_die = m_dwo->DIEPtr(); if (dwo_die) - dwo_die->BuildFunctionAddressRangeTable(dwo_cu, + dwo_die->BuildFunctionAddressRangeTable(m_dwo.get(), m_func_aranges_up.get()); } @@ -820,10 +788,13 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { } llvm::Expected<DWARFUnitHeader> -DWARFUnitHeader::extract(const DWARFDataExtractor &data, DIERef::Section section, - lldb::offset_t *offset_ptr) { +DWARFUnitHeader::extract(const DWARFDataExtractor &data, + DIERef::Section section, lldb::offset_t *offset_ptr, + const llvm::DWARFUnitIndex *index) { DWARFUnitHeader header; header.m_offset = *offset_ptr; + if (index) + header.m_index_entry = index->getFromOffset(*offset_ptr); header.m_length = data.GetDWARFInitialLength(offset_ptr); header.m_version = data.GetU16(offset_ptr); if (header.m_version == 5) { @@ -839,6 +810,26 @@ DWARFUnitHeader::extract(const DWARFDataExtractor &data, DIERef::Section section section == DIERef::Section::DebugTypes ? DW_UT_type : DW_UT_compile; } + 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->Length != 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->Offset; + } if (header.IsTypeUnit()) { header.m_type_hash = data.GetU64(offset_ptr); header.m_type_offset = data.GetDWARFOffset(offset_ptr); @@ -869,11 +860,12 @@ DWARFUnitHeader::extract(const DWARFDataExtractor &data, DIERef::Section section llvm::Expected<DWARFUnitSP> DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, const DWARFDataExtractor &debug_info, - DIERef::Section section, lldb::offset_t *offset_ptr) { + DIERef::Section section, lldb::offset_t *offset_ptr, + const llvm::DWARFUnitIndex *index) { assert(debug_info.ValidOffset(*offset_ptr)); auto expected_header = - DWARFUnitHeader::extract(debug_info, section, offset_ptr); + DWARFUnitHeader::extract(debug_info, section, offset_ptr, index); if (!expected_header) return expected_header.takeError(); @@ -924,6 +916,12 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { llvm_unreachable("invalid UnitType."); } +llvm::Optional<uint64_t> +DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const { + offset_t offset = GetStrOffsetsBase() + index * 4; + return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset); +} + llvm::Expected<DWARFRangeList> DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { if (GetVersion() <= 4) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 217f9bb89ace..affad286a490 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -6,12 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_DWARFUnit_h_ -#define SymbolFileDWARF_DWARFUnit_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H #include "DWARFDIE.h" #include "DWARFDebugInfoEntry.h" #include "lldb/lldb-enumerations.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/RWMutex.h" #include <atomic> @@ -39,6 +40,9 @@ class DWARFUnitHeader { dw_offset_t m_length = 0; uint16_t m_version = 0; dw_offset_t m_abbr_offset = 0; + + const llvm::DWARFUnitIndex::Entry *m_index_entry = nullptr; + uint8_t m_unit_type = 0; uint8_t m_addr_size = 0; @@ -56,6 +60,9 @@ public: dw_offset_t GetLength() const { return m_length; } dw_offset_t GetAbbrOffset() const { return m_abbr_offset; } uint8_t GetUnitType() const { return m_unit_type; } + const llvm::DWARFUnitIndex::Entry *GetIndexEntry() const { + return m_index_entry; + } uint64_t GetTypeHash() const { return m_type_hash; } dw_offset_t GetTypeOffset() const { return m_type_offset; } bool IsTypeUnit() const { @@ -65,7 +72,7 @@ public: static llvm::Expected<DWARFUnitHeader> extract(const lldb_private::DWARFDataExtractor &data, DIERef::Section section, - lldb::offset_t *offset_ptr); + lldb::offset_t *offset_ptr, const llvm::DWARFUnitIndex *index); }; class DWARFUnit : public lldb_private::UserID { @@ -76,9 +83,12 @@ 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); + DIERef::Section section, lldb::offset_t *offset_ptr, + const llvm::DWARFUnitIndex *index); virtual ~DWARFUnit(); + bool IsDWOUnit() { return m_is_dwo; } + void ExtractUnitDIEIfNeeded(); void ExtractDIEsIfNeeded(); @@ -88,7 +98,8 @@ public: bool m_clear_dies = false; ScopedExtractDIEs(DWARFUnit &cu); ~ScopedExtractDIEs(); - DISALLOW_COPY_AND_ASSIGN(ScopedExtractDIEs); + ScopedExtractDIEs(const ScopedExtractDIEs &) = delete; + const ScopedExtractDIEs &operator=(const ScopedExtractDIEs &) = delete; ScopedExtractDIEs(ScopedExtractDIEs &&rhs); ScopedExtractDIEs &operator=(ScopedExtractDIEs &&rhs); }; @@ -152,8 +163,6 @@ public: lldb::ByteOrder GetByteOrder() const; - llvm::Expected<lldb_private::TypeSystem &> GetTypeSystem(); - const DWARFDebugAranges &GetFunctionAranges(); void SetBaseAddress(dw_addr_t base_addr); @@ -190,9 +199,7 @@ public: uint32_t GetProducerVersionUpdate(); - static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); - - lldb::LanguageType GetLanguageType(); + uint64_t GetDWARFLanguageType(); bool GetIsOptimized(); @@ -213,6 +220,8 @@ public: uint8_t GetUnitType() const { return m_header.GetUnitType(); } bool IsTypeUnit() const { return m_header.IsTypeUnit(); } + llvm::Optional<uint64_t> GetStringOffsetSectionItem(uint32_t index) const; + /// Return a list of address ranges resulting from a (possibly encoded) /// range list starting at a given offset in the appropriate ranges section. llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset); @@ -248,7 +257,7 @@ public: std::unique_ptr<llvm::DWARFLocationTable> GetLocationTable(const lldb_private::DataExtractor &data) const; - const lldb_private::DWARFDataExtractor &GetLocationData() const; + lldb_private::DWARFDataExtractor GetLocationData() const; protected: DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, @@ -279,7 +288,7 @@ protected: } SymbolFileDWARF &m_dwarf; - std::unique_ptr<SymbolFileDWARFDwo> m_dwo_symbol_file; + std::shared_ptr<DWARFUnit> m_dwo; DWARFUnitHeader m_header; const DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; void *m_user_data = nullptr; @@ -304,7 +313,7 @@ protected: uint32_t m_producer_version_major = 0; uint32_t m_producer_version_minor = 0; uint32_t m_producer_version_update = 0; - lldb::LanguageType m_language_type = lldb::eLanguageTypeUnknown; + llvm::Optional<uint64_t> m_language_type; lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; llvm::Optional<lldb_private::FileSpec> m_comp_dir; llvm::Optional<lldb_private::FileSpec> m_file_spec; @@ -329,11 +338,13 @@ private: void ClearDIEsRWLocked(); void AddUnitDIE(const DWARFDebugInfoEntry &cu_die); + void SetDwoStrOffsetsBase(); void ComputeCompDirAndGuessPathStyle(); void ComputeAbsolutePath(); - DISALLOW_COPY_AND_ASSIGN(DWARFUnit); + DWARFUnit(const DWARFUnit &) = delete; + const DWARFUnit &operator=(const DWARFUnit &) = delete; }; -#endif // SymbolFileDWARF_DWARFUnit_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index 007ef2e05e59..cb3e662a6cdf 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -1,4 +1,4 @@ -//===-- DebugNamesDWARFIndex.cpp -------------------------------*- C++ -*-===// +//===-- DebugNamesDWARFIndex.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,6 +10,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" +#include "lldb/Core/Module.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" @@ -19,18 +20,14 @@ using namespace lldb; llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, DWARFDataExtractor debug_str, - DWARFDebugInfo *debug_info) { - if (!debug_info) { - return llvm::make_error<llvm::StringError>("debug info null", - llvm::inconvertibleErrorCode()); - } + SymbolFileDWARF &dwarf) { auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVM(), debug_str.GetAsLLVM()); if (llvm::Error E = index_up->extract()) return std::move(E); return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex( - module, std::move(index_up), debug_names, debug_str, *debug_info)); + module, std::move(index_up), debug_names, debug_str, dwarf)); } llvm::DenseSet<dw_offset_t> @@ -53,12 +50,7 @@ DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) { if (!cu) return llvm::None; - // This initializes the DWO symbol file. It's not possible for - // GetDwoSymbolFile to call this automatically because of mutual recursion - // between this and DWARFDebugInfoEntry::GetAttributeValue. - cu->ExtractUnitDIEIfNeeded(); cu = &cu->GetNonSkeletonUnit(); - if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset()) return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(), DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset); @@ -66,10 +58,18 @@ DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) { return llvm::None; } -void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry, - DIEArray &offsets) { - if (llvm::Optional<DIERef> ref = ToDIERef(entry)) - offsets.push_back(*ref); +bool DebugNamesDWARFIndex::ProcessEntry( + const DebugNames::Entry &entry, + llvm::function_ref<bool(DWARFDIE die)> callback, llvm::StringRef name) { + llvm::Optional<DIERef> ref = ToDIERef(entry); + if (!ref) + return true; + SymbolFileDWARF &dwarf = + *llvm::cast<SymbolFileDWARF>(m_module.GetSymbolFile()); + DWARFDIE die = dwarf.GetDIE(*ref); + if (!die) + return true; + return callback(die); } void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error, @@ -83,23 +83,23 @@ void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error, ni.getUnitOffset(), name); } -void DebugNamesDWARFIndex::GetGlobalVariables(ConstString basename, - DIEArray &offsets) { - m_fallback.GetGlobalVariables(basename, offsets); - +void DebugNamesDWARFIndex::GetGlobalVariables( + ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) { for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(basename.GetStringRef())) { if (entry.tag() != DW_TAG_variable) continue; - Append(entry, offsets); + if (!ProcessEntry(entry, callback, basename.GetStringRef())) + return; } -} -void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, - DIEArray &offsets) { - m_fallback.GetGlobalVariables(regex, offsets); + m_fallback.GetGlobalVariables(basename, callback); +} +void DebugNamesDWARFIndex::GetGlobalVariables( + const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) { for (const DebugNames::NameIndex &ni: *m_debug_names_up) { for (DebugNames::NameTableEntry nte: ni) { if (!regex.Execute(nte.getString())) @@ -111,17 +111,19 @@ void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, if (entry_or->tag() != DW_TAG_variable) continue; - Append(*entry_or, offsets); + if (!ProcessEntry(*entry_or, callback, + llvm::StringRef(nte.getString()))) + return; } MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); } } -} -void DebugNamesDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, - DIEArray &offsets) { - m_fallback.GetGlobalVariables(cu, offsets); + m_fallback.GetGlobalVariables(regex, callback); +} +void DebugNamesDWARFIndex::GetGlobalVariables( + const DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) { uint64_t cu_offset = cu.GetOffset(); for (const DebugNames::NameIndex &ni: *m_debug_names_up) { for (DebugNames::NameTableEntry nte: ni) { @@ -133,18 +135,20 @@ void DebugNamesDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, if (entry_or->getCUOffset() != cu_offset) continue; - Append(*entry_or, offsets); + if (!ProcessEntry(*entry_or, callback, + llvm::StringRef(nte.getString()))) + return; } MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); } } -} -void DebugNamesDWARFIndex::GetCompleteObjCClass(ConstString class_name, - bool must_be_implementation, - DIEArray &offsets) { - m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, offsets); + m_fallback.GetGlobalVariables(cu, callback); +} +void DebugNamesDWARFIndex::GetCompleteObjCClass( + ConstString class_name, bool must_be_implementation, + llvm::function_ref<bool(DWARFDIE die)> callback) { // Keep a list of incomplete types as fallback for when we don't find the // complete type. DIEArray incomplete_types; @@ -165,84 +169,98 @@ void DebugNamesDWARFIndex::GetCompleteObjCClass(ConstString class_name, continue; } - // FIXME: We should return DWARFDIEs so we don't have to resolve it twice. DWARFDIE die = m_debug_info.GetDIE(*ref); - if (!die) + if (!die) { + ReportInvalidDIERef(*ref, class_name.GetStringRef()); continue; + } if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) { // If we find the complete version we're done. - offsets.push_back(*ref); + callback(die); return; - } else { - incomplete_types.push_back(*ref); } + incomplete_types.push_back(*ref); } - offsets.insert(offsets.end(), incomplete_types.begin(), - incomplete_types.end()); -} + auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef()); + for (DIERef ref : incomplete_types) + if (!dierefcallback(ref)) + return; -void DebugNamesDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { - m_fallback.GetTypes(name, offsets); + m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback); +} +void DebugNamesDWARFIndex::GetTypes( + ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name.GetStringRef())) { - if (isType(entry.tag())) - Append(entry, offsets); + if (isType(entry.tag())) { + if (!ProcessEntry(entry, callback, name.GetStringRef())) + return; + } } -} -void DebugNamesDWARFIndex::GetTypes(const DWARFDeclContext &context, - DIEArray &offsets) { - m_fallback.GetTypes(context, offsets); + m_fallback.GetTypes(name, callback); +} - for (const DebugNames::Entry &entry : - m_debug_names_up->equal_range(context[0].name)) { - if (entry.tag() == context[0].tag) - Append(entry, offsets); +void DebugNamesDWARFIndex::GetTypes( + const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) { + auto name = context[0].name; + for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) { + if (entry.tag() == context[0].tag) { + if (!ProcessEntry(entry, callback, name)) + return; + } } -} -void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { - m_fallback.GetNamespaces(name, offsets); + m_fallback.GetTypes(context, callback); +} +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())) { - if (entry.tag() == DW_TAG_namespace) - Append(entry, offsets); + if (entry.tag() == DW_TAG_namespace) { + if (!ProcessEntry(entry, callback, name.GetStringRef())) + return; + } } + + m_fallback.GetNamespaces(name, callback); } void DebugNamesDWARFIndex::GetFunctions( ConstString name, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, - std::vector<DWARFDIE> &dies) { - - std::vector<DWARFDIE> v; - m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask, v); + llvm::function_ref<bool(DWARFDIE die)> callback) { + std::set<DWARFDebugInfoEntry *> seen; for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name.GetStringRef())) { Tag tag = entry.tag(); if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) continue; - if (llvm::Optional<DIERef> ref = ToDIERef(entry)) - ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx, - name_type_mask, v); + if (llvm::Optional<DIERef> ref = ToDIERef(entry)) { + if (!ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx, + name_type_mask, [&](DWARFDIE die) { + if (!seen.insert(die.GetDIE()).second) + return true; + return callback(die); + })) + return; + } } - std::set<DWARFDebugInfoEntry *> seen; - for (DWARFDIE die : v) - if (seen.insert(die.GetDIE()).second) - dies.push_back(die); + m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask, + callback); } -void DebugNamesDWARFIndex::GetFunctions(const RegularExpression ®ex, - DIEArray &offsets) { - m_fallback.GetFunctions(regex, offsets); - +void DebugNamesDWARFIndex::GetFunctions( + const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) { for (const DebugNames::NameIndex &ni: *m_debug_names_up) { for (DebugNames::NameTableEntry nte: ni) { if (!regex.Execute(nte.getString())) @@ -255,11 +273,15 @@ void DebugNamesDWARFIndex::GetFunctions(const RegularExpression ®ex, if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) continue; - Append(*entry_or, offsets); + if (!ProcessEntry(*entry_or, callback, + llvm::StringRef(nte.getString()))) + return; } MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); } } + + m_fallback.GetFunctions(regex, callback); } void DebugNamesDWARFIndex::Dump(Stream &s) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index dca25496373f..5d041c36c8f2 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -6,12 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_DEBUGNAMESDWARFINDEX_H -#define LLDB_DEBUGNAMESDWARFINDEX_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DEBUGNAMESDWARFINDEX_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DEBUGNAMESDWARFINDEX_H #include "Plugins/SymbolFile/DWARF/DWARFIndex.h" #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" #include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "lldb/Utility/ConstString.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" @@ -20,28 +21,38 @@ class DebugNamesDWARFIndex : public DWARFIndex { public: static llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> Create(Module &module, DWARFDataExtractor debug_names, - DWARFDataExtractor debug_str, DWARFDebugInfo *debug_info); + DWARFDataExtractor debug_str, SymbolFileDWARF &dwarf); void Preload() override { m_fallback.Preload(); } - void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; - void GetGlobalVariables(const RegularExpression ®ex, - DIEArray &offsets) override; - void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; - void GetObjCMethods(ConstString class_name, DIEArray &offsets) override {} - void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, - DIEArray &offsets) override; - void GetTypes(ConstString name, DIEArray &offsets) override; - void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; - void GetNamespaces(ConstString name, DIEArray &offsets) override; + void + GetGlobalVariables(ConstString basename, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void + GetGlobalVariables(const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void + GetGlobalVariables(const DWARFUnit &cu, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void + GetObjCMethods(ConstString class_name, + llvm::function_ref<bool(DWARFDIE die)> callback) override {} + void GetCompleteObjCClass( + ConstString class_name, bool must_be_implementation, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetTypes(ConstString name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetTypes(const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetNamespaces(ConstString name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; void GetFunctions(ConstString name, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, - std::vector<DWARFDIE> &dies) override; + llvm::function_ref<bool(DWARFDIE die)> callback) override; void GetFunctions(const RegularExpression ®ex, - DIEArray &offsets) override; + llvm::function_ref<bool(DWARFDIE die)> callback) override; - void ReportInvalidDIERef(const DIERef &ref, llvm::StringRef name) override {} void Dump(Stream &s) override; private: @@ -49,11 +60,11 @@ private: std::unique_ptr<llvm::DWARFDebugNames> debug_names_up, DWARFDataExtractor debug_names_data, DWARFDataExtractor debug_str_data, - DWARFDebugInfo &debug_info) - : DWARFIndex(module), m_debug_info(debug_info), + SymbolFileDWARF &dwarf) + : DWARFIndex(module), m_debug_info(dwarf.DebugInfo()), m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data), m_debug_names_up(std::move(debug_names_up)), - m_fallback(module, &debug_info, GetUnits(*m_debug_names_up)) {} + m_fallback(module, dwarf, GetUnits(*m_debug_names_up)) {} DWARFDebugInfo &m_debug_info; @@ -67,7 +78,9 @@ private: ManualDWARFIndex m_fallback; llvm::Optional<DIERef> ToDIERef(const DebugNames::Entry &entry); - void Append(const DebugNames::Entry &entry, DIEArray &offsets); + bool ProcessEntry(const DebugNames::Entry &entry, + llvm::function_ref<bool(DWARFDIE die)> callback, + llvm::StringRef name); static void MaybeLogLookupError(llvm::Error error, const DebugNames::NameIndex &ni, @@ -78,4 +91,4 @@ private: } // namespace lldb_private -#endif // LLDB_DEBUGNAMESDWARFINDEX_H +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DEBUGNAMESDWARFINDEX_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp index 88a29f4a2672..d36f2a8bccf7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp @@ -1,4 +1,4 @@ -//===-- HashedNameToDIE.cpp -------------------------------------*- C++ -*-===// +//===-- HashedNameToDIE.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,91 +9,99 @@ #include "HashedNameToDIE.h" #include "llvm/ADT/StringRef.h" -void DWARFMappedHash::ExtractDIEArray(const DIEInfoArray &die_info_array, - DIEArray &die_offsets) { +bool DWARFMappedHash::ExtractDIEArray( + const DIEInfoArray &die_info_array, + llvm::function_ref<bool(DIERef ref)> callback) { const size_t count = die_info_array.size(); for (size_t i = 0; i < count; ++i) - die_offsets.emplace_back(die_info_array[i]); + if (!callback(DIERef(die_info_array[i]))) + return false; + return true; } -void DWARFMappedHash::ExtractDIEArray(const DIEInfoArray &die_info_array, - const dw_tag_t tag, - DIEArray &die_offsets) { +void DWARFMappedHash::ExtractDIEArray( + const DIEInfoArray &die_info_array, const dw_tag_t tag, + llvm::function_ref<bool(DIERef ref)> callback) { if (tag == 0) { - ExtractDIEArray(die_info_array, die_offsets); - } else { - const size_t count = die_info_array.size(); - for (size_t i = 0; i < count; ++i) { - const dw_tag_t die_tag = die_info_array[i].tag; - bool tag_matches = die_tag == 0 || tag == die_tag; - if (!tag_matches) { - if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) - tag_matches = - tag == DW_TAG_structure_type || tag == DW_TAG_class_type; - } - if (tag_matches) - die_offsets.emplace_back(die_info_array[i]); + ExtractDIEArray(die_info_array, callback); + return; + } + + const size_t count = die_info_array.size(); + for (size_t i = 0; i < count; ++i) { + const dw_tag_t die_tag = die_info_array[i].tag; + bool tag_matches = die_tag == 0 || tag == die_tag; + if (!tag_matches) { + if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) + tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type; + } + if (tag_matches) { + if (!callback(DIERef(die_info_array[i]))) + return; } } } -void DWARFMappedHash::ExtractDIEArray(const DIEInfoArray &die_info_array, - const dw_tag_t tag, - const uint32_t qualified_name_hash, - DIEArray &die_offsets) { +void DWARFMappedHash::ExtractDIEArray( + const DIEInfoArray &die_info_array, const dw_tag_t tag, + const uint32_t qualified_name_hash, + llvm::function_ref<bool(DIERef ref)> callback) { if (tag == 0) { - ExtractDIEArray(die_info_array, die_offsets); - } else { - const size_t count = die_info_array.size(); - for (size_t i = 0; i < count; ++i) { - if (qualified_name_hash != die_info_array[i].qualified_name_hash) - continue; - const dw_tag_t die_tag = die_info_array[i].tag; - bool tag_matches = die_tag == 0 || tag == die_tag; - if (!tag_matches) { - if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) - tag_matches = - tag == DW_TAG_structure_type || tag == DW_TAG_class_type; - } - if (tag_matches) - die_offsets.emplace_back(die_info_array[i]); + ExtractDIEArray(die_info_array, callback); + return; + } + + const size_t count = die_info_array.size(); + for (size_t i = 0; i < count; ++i) { + if (qualified_name_hash != die_info_array[i].qualified_name_hash) + continue; + const dw_tag_t die_tag = die_info_array[i].tag; + bool tag_matches = die_tag == 0 || tag == die_tag; + if (!tag_matches) { + if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) + tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type; + } + if (tag_matches) { + if (!callback(DIERef(die_info_array[i]))) + return; } } } void DWARFMappedHash::ExtractClassOrStructDIEArray( const DIEInfoArray &die_info_array, - bool return_implementation_only_if_available, DIEArray &die_offsets) { + bool return_implementation_only_if_available, + llvm::function_ref<bool(DIERef ref)> callback) { const size_t count = die_info_array.size(); for (size_t i = 0; i < count; ++i) { const dw_tag_t die_tag = die_info_array[i].tag; - if (die_tag == 0 || die_tag == DW_TAG_class_type || - die_tag == DW_TAG_structure_type) { - if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) { - if (return_implementation_only_if_available) { - // We found the one true definition for this class, so only return - // that - die_offsets.clear(); - die_offsets.emplace_back(die_info_array[i]); - return; - } else { - // Put the one true definition as the first entry so it matches first - die_offsets.emplace(die_offsets.begin(), die_info_array[i]); - } - } else { - die_offsets.emplace_back(die_info_array[i]); - } + if (!(die_tag == 0 || die_tag == DW_TAG_class_type || + die_tag == DW_TAG_structure_type)) + continue; + bool is_implementation = + (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) != 0; + if (is_implementation != return_implementation_only_if_available) + continue; + if (return_implementation_only_if_available) { + // We found the one true definition for this class, so only return + // that + callback(DIERef(die_info_array[i])); + return; } + if (!callback(DIERef(die_info_array[i]))) + return; } } void DWARFMappedHash::ExtractTypesFromDIEArray( const DIEInfoArray &die_info_array, uint32_t type_flag_mask, - uint32_t type_flag_value, DIEArray &die_offsets) { + uint32_t type_flag_value, llvm::function_ref<bool(DIERef ref)> callback) { const size_t count = die_info_array.size(); for (size_t i = 0; i < count; ++i) { - if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) - die_offsets.emplace_back(die_info_array[i]); + if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) { + if (!callback(DIERef(die_info_array[i]))) + return; + } } } @@ -453,7 +461,7 @@ DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression( } } -size_t DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex( +void DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex( const lldb_private::RegularExpression ®ex, DIEInfoArray &die_info_array) const { const uint32_t hash_count = m_header.hashes_count; @@ -482,10 +490,9 @@ size_t DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex( } } die_info_array.swap(pair.value); - return die_info_array.size(); } -size_t DWARFMappedHash::MemoryTable::AppendAllDIEsInRange( +void DWARFMappedHash::MemoryTable::AppendAllDIEsInRange( const uint32_t die_offset_start, const uint32_t die_offset_end, DIEInfoArray &die_info_array) const { const uint32_t hash_count = m_header.hashes_count; @@ -512,73 +519,74 @@ size_t DWARFMappedHash::MemoryTable::AppendAllDIEsInRange( } } } - return die_info_array.size(); } -size_t DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name, - DIEArray &die_offsets) { +bool DWARFMappedHash::MemoryTable::FindByName( + llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback) { if (name.empty()) - return 0; + return true; DIEInfoArray die_info_array; - if (FindByName(name, die_info_array)) - DWARFMappedHash::ExtractDIEArray(die_info_array, die_offsets); - return die_info_array.size(); + FindByName(name, die_info_array); + return DWARFMappedHash::ExtractDIEArray(die_info_array, callback); } -size_t DWARFMappedHash::MemoryTable::FindByNameAndTag(llvm::StringRef name, - const dw_tag_t tag, - DIEArray &die_offsets) { +void DWARFMappedHash::MemoryTable::FindByNameAndTag( + llvm::StringRef name, const dw_tag_t tag, + llvm::function_ref<bool(DIERef ref)> callback) { DIEInfoArray die_info_array; - if (FindByName(name, die_info_array)) - DWARFMappedHash::ExtractDIEArray(die_info_array, tag, die_offsets); - return die_info_array.size(); + FindByName(name, die_info_array); + DWARFMappedHash::ExtractDIEArray(die_info_array, tag, callback); } -size_t DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash( +void DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash( llvm::StringRef name, const dw_tag_t tag, - const uint32_t qualified_name_hash, DIEArray &die_offsets) { + const uint32_t qualified_name_hash, + llvm::function_ref<bool(DIERef ref)> callback) { DIEInfoArray die_info_array; - if (FindByName(name, die_info_array)) - DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash, - die_offsets); - return die_info_array.size(); + FindByName(name, die_info_array); + DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash, + callback); } -size_t DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName( - llvm::StringRef name, DIEArray &die_offsets, bool must_be_implementation) { +void DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName( + llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback, + bool must_be_implementation) { DIEInfoArray die_info_array; - if (FindByName(name, die_info_array)) { - if (must_be_implementation && - GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) { - // If we have two atoms, then we have the DIE offset and the type flags - // so we can find the objective C class efficiently. - DWARFMappedHash::ExtractTypesFromDIEArray(die_info_array, UINT32_MAX, - eTypeFlagClassIsImplementation, - die_offsets); - } else { - // We don't only want the one true definition, so try and see what we can - // find, and only return class or struct DIEs. If we do have the full - // implementation, then return it alone, else return all possible - // matches. - const bool return_implementation_only_if_available = true; - DWARFMappedHash::ExtractClassOrStructDIEArray( - die_info_array, return_implementation_only_if_available, die_offsets); - } + FindByName(name, die_info_array); + if (must_be_implementation && + GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) { + // If we have two atoms, then we have the DIE offset and the type flags + // so we can find the objective C class efficiently. + DWARFMappedHash::ExtractTypesFromDIEArray( + die_info_array, UINT32_MAX, eTypeFlagClassIsImplementation, callback); + return; } - return die_offsets.size(); + // We don't only want the one true definition, so try and see what we can + // find, and only return class or struct DIEs. If we do have the full + // implementation, then return it alone, else return all possible + // matches. + bool found_implementation = false; + DWARFMappedHash::ExtractClassOrStructDIEArray( + die_info_array, true /*return_implementation_only_if_available*/, + [&](DIERef ref) { + found_implementation = true; + // Here the return value does not matter as we are called at most once. + return callback(ref); + }); + if (found_implementation) + return; + DWARFMappedHash::ExtractClassOrStructDIEArray( + die_info_array, false /*return_implementation_only_if_available*/, + callback); } -size_t DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name, - DIEInfoArray &die_info_array) { +void DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name, + DIEInfoArray &die_info_array) { if (name.empty()) - return 0; + return; Pair kv_pair; - size_t old_size = die_info_array.size(); - if (Find(name, kv_pair)) { + if (Find(name, kv_pair)) die_info_array.swap(kv_pair.value); - return die_info_array.size() - old_size; - } - return 0; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h index 56d9bc548877..ad178fc6a987 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_HashedNameToDIE_h_ -#define SymbolFileDWARF_HashedNameToDIE_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_HASHEDNAMETODIE_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_HASHEDNAMETODIE_H #include <vector> @@ -132,33 +132,36 @@ public: bool ReadHashData(uint32_t hash_data_offset, HashData &hash_data) const override; - size_t + void AppendAllDIEsThatMatchingRegex(const lldb_private::RegularExpression ®ex, DIEInfoArray &die_info_array) const; - size_t AppendAllDIEsInRange(const uint32_t die_offset_start, - const uint32_t die_offset_end, - DIEInfoArray &die_info_array) const; + void AppendAllDIEsInRange(const uint32_t die_offset_start, + const uint32_t die_offset_end, + DIEInfoArray &die_info_array) const; - size_t FindByName(llvm::StringRef name, DIEArray &die_offsets); + bool FindByName(llvm::StringRef name, + llvm::function_ref<bool(DIERef ref)> callback); - size_t FindByNameAndTag(llvm::StringRef name, const dw_tag_t tag, - DIEArray &die_offsets); + void FindByNameAndTag(llvm::StringRef name, const dw_tag_t tag, + llvm::function_ref<bool(DIERef ref)> callback); - size_t FindByNameAndTagAndQualifiedNameHash( + void FindByNameAndTagAndQualifiedNameHash( llvm::StringRef name, const dw_tag_t tag, - const uint32_t qualified_name_hash, DIEArray &die_offsets); + const uint32_t qualified_name_hash, + llvm::function_ref<bool(DIERef ref)> callback); - size_t FindCompleteObjCClassByName(llvm::StringRef name, - DIEArray &die_offsets, - bool must_be_implementation); + void + FindCompleteObjCClassByName(llvm::StringRef name, + llvm::function_ref<bool(DIERef ref)> callback, + bool must_be_implementation); protected: Result AppendHashDataForRegularExpression( const lldb_private::RegularExpression ®ex, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const; - size_t FindByName(llvm::StringRef name, DIEInfoArray &die_info_array); + void FindByName(llvm::StringRef name, DIEInfoArray &die_info_array); Result GetHashDataForName(llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr, @@ -169,29 +172,30 @@ public: std::string m_name; }; - static void ExtractDIEArray(const DIEInfoArray &die_info_array, - DIEArray &die_offsets); + static bool ExtractDIEArray(const DIEInfoArray &die_info_array, + llvm::function_ref<bool(DIERef ref)> callback); protected: static void ExtractDIEArray(const DIEInfoArray &die_info_array, - const dw_tag_t tag, DIEArray &die_offsets); + const dw_tag_t tag, + llvm::function_ref<bool(DIERef ref)> callback); static void ExtractDIEArray(const DIEInfoArray &die_info_array, const dw_tag_t tag, const uint32_t qualified_name_hash, - DIEArray &die_offsets); + llvm::function_ref<bool(DIERef ref)> callback); static void ExtractClassOrStructDIEArray(const DIEInfoArray &die_info_array, bool return_implementation_only_if_available, - DIEArray &die_offsets); + llvm::function_ref<bool(DIERef ref)> callback); - static void ExtractTypesFromDIEArray(const DIEInfoArray &die_info_array, - uint32_t type_flag_mask, - uint32_t type_flag_value, - DIEArray &die_offsets); + static void + ExtractTypesFromDIEArray(const DIEInfoArray &die_info_array, + uint32_t type_flag_mask, uint32_t type_flag_value, + llvm::function_ref<bool(DIERef ref)> callback); static const char *GetAtomTypeName(uint16_t atom); }; -#endif // SymbolFileDWARF_HashedNameToDIE_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_HASHEDNAMETODIE_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp index 8495016d4280..3f1d6677bacf 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp @@ -1,4 +1,4 @@ -//===-- LogChannelDWARF.cpp ------------------------------------*- C++ -*-===// +//===-- LogChannelDWARF.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h index a89c686735d2..2fc23563ef93 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_LogChannelDWARF_h_ -#define SymbolFileDWARF_LogChannelDWARF_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_LOGCHANNELDWARF_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_LOGCHANNELDWARF_H #include "lldb/Utility/Log.h" @@ -32,4 +32,4 @@ public: }; } -#endif // SymbolFileDWARF_LogChannelDWARF_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_LOGCHANNELDWARF_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 1e5927bd14f0..7bf4b52bc783 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -1,4 +1,4 @@ -//===-- ManualDWARFIndex.cpp -----------------------------------*- C++ -*-===// +//===-- ManualDWARFIndex.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,31 +13,47 @@ #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" #include "lldb/Core/Module.h" -#include "lldb/Host/TaskPool.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" +#include "llvm/Support/ThreadPool.h" using namespace lldb_private; using namespace lldb; void ManualDWARFIndex::Index() { - if (!m_debug_info) + if (!m_dwarf) return; - DWARFDebugInfo &debug_info = *m_debug_info; - m_debug_info = nullptr; + SymbolFileDWARF &main_dwarf = *m_dwarf; + m_dwarf = nullptr; static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%p", static_cast<void *>(&debug_info)); + Timer scoped_timer(func_cat, "%p", static_cast<void *>(&main_dwarf)); + + DWARFDebugInfo &main_info = main_dwarf.DebugInfo(); + SymbolFileDWARFDwo *dwp_dwarf = main_dwarf.GetDwpSymbolFile().get(); + DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr; std::vector<DWARFUnit *> units_to_index; - units_to_index.reserve(debug_info.GetNumUnits()); - for (size_t U = 0; U < debug_info.GetNumUnits(); ++U) { - DWARFUnit *unit = debug_info.GetUnitAtIndex(U); + units_to_index.reserve(main_info.GetNumUnits() + + (dwp_info ? dwp_info->GetNumUnits() : 0)); + + // Process all units in the main file, as well as any type units in the dwp + // file. Type units in dwo files are handled when we reach the dwo file in + // IndexUnit. + for (size_t U = 0; U < main_info.GetNumUnits(); ++U) { + DWARFUnit *unit = main_info.GetUnitAtIndex(U); if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0) units_to_index.push_back(unit); } + if (dwp_info && dwp_info->ContainsTypeUnits()) { + for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) { + if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) + units_to_index.push_back(tu); + } + } + if (units_to_index.empty()) return; @@ -48,27 +64,34 @@ void ManualDWARFIndex::Index() { std::vector<llvm::Optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies( units_to_index.size()); auto parser_fn = [&](size_t cu_idx) { - IndexUnit(*units_to_index[cu_idx], sets[cu_idx]); + IndexUnit(*units_to_index[cu_idx], dwp_dwarf, sets[cu_idx]); }; auto extract_fn = [&units_to_index, &clear_cu_dies](size_t cu_idx) { clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped(); }; + // Share one thread pool across operations to avoid the overhead of + // recreating the threads. + llvm::ThreadPool pool; + // Create a task runner that extracts dies for each DWARF unit in a - // separate thread + // separate thread. // First figure out which units didn't have their DIEs already // parsed and remember this. If no DIEs were parsed prior to this index // function call, we are going to want to clear the CU dies after we are // done indexing to make sure we don't pull in all DWARF dies, but we need // to wait until all units have been indexed in case a DIE in one // unit refers to another and the indexes accesses those DIEs. - TaskMapOverInt(0, units_to_index.size(), extract_fn); + for (size_t i = 0; i < units_to_index.size(); ++i) + pool.async(extract_fn, i); + pool.wait(); // Now create a task runner that can index each DWARF unit in a // separate thread so we can index quickly. - - TaskMapOverInt(0, units_to_index.size(), parser_fn); + for (size_t i = 0; i < units_to_index.size(); ++i) + pool.async(parser_fn, i); + pool.wait(); auto finalize_fn = [this, &sets](NameToDIE(IndexSet::*index)) { NameToDIE &result = m_set.*index; @@ -77,21 +100,19 @@ void ManualDWARFIndex::Index() { result.Finalize(); }; - TaskPool::RunTasks([&]() { finalize_fn(&IndexSet::function_basenames); }, - [&]() { finalize_fn(&IndexSet::function_fullnames); }, - [&]() { finalize_fn(&IndexSet::function_methods); }, - [&]() { finalize_fn(&IndexSet::function_selectors); }, - [&]() { finalize_fn(&IndexSet::objc_class_selectors); }, - [&]() { finalize_fn(&IndexSet::globals); }, - [&]() { finalize_fn(&IndexSet::types); }, - [&]() { finalize_fn(&IndexSet::namespaces); }); + pool.async(finalize_fn, &IndexSet::function_basenames); + pool.async(finalize_fn, &IndexSet::function_fullnames); + pool.async(finalize_fn, &IndexSet::function_methods); + pool.async(finalize_fn, &IndexSet::function_selectors); + pool.async(finalize_fn, &IndexSet::objc_class_selectors); + pool.async(finalize_fn, &IndexSet::globals); + pool.async(finalize_fn, &IndexSet::types); + pool.async(finalize_fn, &IndexSet::namespaces); + pool.wait(); } -void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, IndexSet &set) { - assert( - !unit.GetSymbolFileDWARF().GetBaseCompileUnit() && - "DWARFUnit associated with .dwo or .dwp should not be indexed directly"); - +void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp, + IndexSet &set) { Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS); if (log) { @@ -100,14 +121,21 @@ void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, IndexSet &set) { unit.GetOffset()); } - const LanguageType cu_language = unit.GetLanguageType(); + const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit); IndexUnitImpl(unit, cu_language, set); if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) { - DWARFDebugInfo &dwo_info = *dwo_symbol_file->DebugInfo(); - for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i) - IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set); + // Type units in a dwp file are indexed separately, so we just need to + // process the split unit here. However, if the split unit is in a dwo file, + // then we need to process type units here. + if (dwo_symbol_file == dwp) { + IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set); + } else { + DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo(); + for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i) + IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set); + } } } @@ -165,12 +193,6 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, is_declaration = form_value.Unsigned() != 0; break; - // case DW_AT_artificial: - // if (attributes.ExtractFormValueAtIndex(i, - // form_value)) - // is_artificial = form_value.Unsigned() != 0; - // break; - case DW_AT_MIPS_linkage_name: case DW_AT_linkage_name: if (attributes.ExtractFormValueAtIndex(i, form_value)) @@ -190,49 +212,8 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, case DW_AT_location: case DW_AT_const_value: has_location_or_const_value = true; - if (tag == DW_TAG_variable) { - const DWARFDebugInfoEntry *parent_die = die.GetParent(); - while (parent_die != nullptr) { - switch (parent_die->Tag()) { - case DW_TAG_subprogram: - case DW_TAG_lexical_block: - case DW_TAG_inlined_subroutine: - // Even if this is a function level static, we don't add it. We - // could theoretically add these if we wanted to by - // introspecting into the DW_AT_location and seeing if the - // location describes a hard coded address, but we don't want - // the performance penalty of that right now. - is_global_or_static_variable = false; - // if (attributes.ExtractFormValueAtIndex(dwarf, i, - // form_value)) { - // // If we have valid block data, then we have location - // // expression bytesthat are fixed (not a location list). - // const uint8_t *block_data = form_value.BlockData(); - // if (block_data) { - // uint32_t block_length = form_value.Unsigned(); - // if (block_length == 1 + - // attributes.UnitAtIndex(i)->GetAddressByteSize()) { - // if (block_data[0] == DW_OP_addr) - // add_die = true; - // } - // } - // } - parent_die = nullptr; // Terminate the while loop. - break; - - case DW_TAG_compile_unit: - case DW_TAG_partial_unit: - is_global_or_static_variable = true; - parent_die = nullptr; // Terminate the while loop. - break; - - default: - parent_die = - parent_die->GetParent(); // Keep going in the while loop. - break; - } - } - } + is_global_or_static_variable = die.IsGlobalOrStaticScopeVariable(); + break; case DW_AT_specification: @@ -347,108 +328,118 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, } } -void ManualDWARFIndex::GetGlobalVariables(ConstString basename, DIEArray &offsets) { +void ManualDWARFIndex::GetGlobalVariables( + ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.globals.Find(basename, offsets); + m_set.globals.Find(basename, + DIERefCallback(callback, basename.GetStringRef())); } -void ManualDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, - DIEArray &offsets) { +void ManualDWARFIndex::GetGlobalVariables( + const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.globals.Find(regex, offsets); + m_set.globals.Find(regex, DIERefCallback(callback, regex.GetText())); } -void ManualDWARFIndex::GetGlobalVariables(const DWARFUnit &unit, - DIEArray &offsets) { +void ManualDWARFIndex::GetGlobalVariables( + const DWARFUnit &unit, llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.globals.FindAllEntriesForUnit(unit, offsets); + m_set.globals.FindAllEntriesForUnit(unit, DIERefCallback(callback)); } -void ManualDWARFIndex::GetObjCMethods(ConstString class_name, - DIEArray &offsets) { +void ManualDWARFIndex::GetObjCMethods( + ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.objc_class_selectors.Find(class_name, offsets); + m_set.objc_class_selectors.Find( + class_name, DIERefCallback(callback, class_name.GetStringRef())); } -void ManualDWARFIndex::GetCompleteObjCClass(ConstString class_name, - bool must_be_implementation, - DIEArray &offsets) { +void ManualDWARFIndex::GetCompleteObjCClass( + ConstString class_name, bool must_be_implementation, + llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.types.Find(class_name, offsets); + m_set.types.Find(class_name, + DIERefCallback(callback, class_name.GetStringRef())); } -void ManualDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { +void ManualDWARFIndex::GetTypes( + ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.types.Find(name, offsets); + m_set.types.Find(name, DIERefCallback(callback, name.GetStringRef())); } -void ManualDWARFIndex::GetTypes(const DWARFDeclContext &context, - DIEArray &offsets) { +void ManualDWARFIndex::GetTypes( + const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.types.Find(ConstString(context[0].name), offsets); + auto name = context[0].name; + m_set.types.Find(ConstString(name), + DIERefCallback(callback, llvm::StringRef(name))); } -void ManualDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { +void ManualDWARFIndex::GetNamespaces( + ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.namespaces.Find(name, offsets); + m_set.namespaces.Find(name, DIERefCallback(callback, name.GetStringRef())); } -void ManualDWARFIndex::GetFunctions(ConstString name, SymbolFileDWARF &dwarf, - const CompilerDeclContext &parent_decl_ctx, - uint32_t name_type_mask, - std::vector<DWARFDIE> &dies) { +void ManualDWARFIndex::GetFunctions( + ConstString name, SymbolFileDWARF &dwarf, + const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, + llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); if (name_type_mask & eFunctionNameTypeFull) { - DIEArray offsets; - m_set.function_fullnames.Find(name, offsets); - for (const DIERef &die_ref: offsets) { - DWARFDIE die = dwarf.GetDIE(die_ref); - if (!die) - continue; - if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) - dies.push_back(die); - } + if (!m_set.function_fullnames.Find( + name, DIERefCallback( + [&](DWARFDIE die) { + if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, + die)) + return true; + return callback(die); + }, + name.GetStringRef()))) + return; } if (name_type_mask & eFunctionNameTypeBase) { - DIEArray offsets; - m_set.function_basenames.Find(name, offsets); - for (const DIERef &die_ref: offsets) { - DWARFDIE die = dwarf.GetDIE(die_ref); - if (!die) - continue; - if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) - dies.push_back(die); - } - offsets.clear(); + if (!m_set.function_basenames.Find( + name, DIERefCallback( + [&](DWARFDIE die) { + if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, + die)) + return true; + return callback(die); + }, + name.GetStringRef()))) + return; } if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) { - DIEArray offsets; - m_set.function_methods.Find(name, offsets); - for (const DIERef &die_ref: offsets) { - if (DWARFDIE die = dwarf.GetDIE(die_ref)) - dies.push_back(die); - } + if (!m_set.function_methods.Find( + name, DIERefCallback(callback, name.GetStringRef()))) + return; } if (name_type_mask & eFunctionNameTypeSelector && !parent_decl_ctx.IsValid()) { - DIEArray offsets; - m_set.function_selectors.Find(name, offsets); - for (const DIERef &die_ref: offsets) { - if (DWARFDIE die = dwarf.GetDIE(die_ref)) - dies.push_back(die); - } + if (!m_set.function_selectors.Find( + name, DIERefCallback(callback, name.GetStringRef()))) + return; } } -void ManualDWARFIndex::GetFunctions(const RegularExpression ®ex, - DIEArray &offsets) { +void ManualDWARFIndex::GetFunctions( + const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) { Index(); - m_set.function_basenames.Find(regex, offsets); - m_set.function_fullnames.Find(regex, offsets); + if (!m_set.function_basenames.Find(regex, + DIERefCallback(callback, regex.GetText()))) + return; + if (!m_set.function_fullnames.Find(regex, + DIERefCallback(callback, regex.GetText()))) + return; } void ManualDWARFIndex::Dump(Stream &s) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h index dd03b103c936..baff989eecca 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -6,42 +6,53 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_MANUALDWARFINDEX_H -#define LLDB_MANUALDWARFINDEX_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H #include "Plugins/SymbolFile/DWARF/DWARFIndex.h" #include "Plugins/SymbolFile/DWARF/NameToDIE.h" #include "llvm/ADT/DenseSet.h" class DWARFDebugInfo; +class SymbolFileDWARFDwo; namespace lldb_private { class ManualDWARFIndex : public DWARFIndex { public: - ManualDWARFIndex(Module &module, DWARFDebugInfo *debug_info, + ManualDWARFIndex(Module &module, SymbolFileDWARF &dwarf, llvm::DenseSet<dw_offset_t> units_to_avoid = {}) - : DWARFIndex(module), m_debug_info(debug_info), + : DWARFIndex(module), m_dwarf(&dwarf), m_units_to_avoid(std::move(units_to_avoid)) {} void Preload() override { Index(); } - void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; - void GetGlobalVariables(const RegularExpression ®ex, - DIEArray &offsets) override; - void GetGlobalVariables(const DWARFUnit &unit, DIEArray &offsets) override; - void GetObjCMethods(ConstString class_name, DIEArray &offsets) override; - void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, - DIEArray &offsets) override; - void GetTypes(ConstString name, DIEArray &offsets) override; - void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; - void GetNamespaces(ConstString name, DIEArray &offsets) override; + void + GetGlobalVariables(ConstString basename, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void + GetGlobalVariables(const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void + GetGlobalVariables(const DWARFUnit &unit, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetObjCMethods(ConstString class_name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetCompleteObjCClass( + ConstString class_name, bool must_be_implementation, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetTypes(ConstString name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetTypes(const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetNamespaces(ConstString name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; void GetFunctions(ConstString name, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, - std::vector<DWARFDIE> &dies) override; - void GetFunctions(const RegularExpression ®ex, DIEArray &offsets) override; + llvm::function_ref<bool(DWARFDIE die)> callback) override; + void GetFunctions(const RegularExpression ®ex, + llvm::function_ref<bool(DWARFDIE die)> callback) override; - void ReportInvalidDIERef(const DIERef &ref, llvm::StringRef name) override {} void Dump(Stream &s) override; private: @@ -56,14 +67,15 @@ private: NameToDIE namespaces; }; void Index(); - void IndexUnit(DWARFUnit &unit, IndexSet &set); + void IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp, IndexSet &set); static void IndexUnitImpl(DWARFUnit &unit, const lldb::LanguageType cu_language, IndexSet &set); - /// Non-null value means we haven't built the index yet. - DWARFDebugInfo *m_debug_info; + /// The DWARF file which we are indexing. Set to nullptr after the index is + /// built. + SymbolFileDWARF *m_dwarf; /// Which dwarf units should we skip while building the index. llvm::DenseSet<dw_offset_t> m_units_to_avoid; @@ -71,4 +83,4 @@ private: }; } // namespace lldb_private -#endif // LLDB_MANUALDWARFINDEX_H +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp index 7d81afb1b226..42e96af84a96 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp @@ -1,4 +1,4 @@ -//===-- NameToDIE.cpp -------------------------------------------*- C++ -*-===// +//===-- NameToDIE.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -26,28 +26,38 @@ void NameToDIE::Insert(ConstString name, const DIERef &die_ref) { m_map.Append(name, die_ref); } -size_t NameToDIE::Find(ConstString name, DIEArray &info_array) const { - return m_map.GetValues(name, info_array); +bool NameToDIE::Find(ConstString name, + llvm::function_ref<bool(DIERef ref)> callback) const { + for (const auto &entry : m_map.equal_range(name)) + if (!callback(entry.value)) + return false; + return true; } -size_t NameToDIE::Find(const RegularExpression ®ex, - DIEArray &info_array) const { - return m_map.GetValues(regex, info_array); +bool NameToDIE::Find(const RegularExpression ®ex, + llvm::function_ref<bool(DIERef ref)> callback) const { + for (const auto &entry : m_map) + if (regex.Execute(entry.cstring.GetCString())) { + if (!callback(entry.value)) + return false; + } + return true; } -size_t NameToDIE::FindAllEntriesForUnit(const DWARFUnit &unit, - DIEArray &info_array) const { - const size_t initial_size = info_array.size(); +void NameToDIE::FindAllEntriesForUnit( + const DWARFUnit &unit, + llvm::function_ref<bool(DIERef ref)> callback) const { const uint32_t size = m_map.GetSize(); for (uint32_t i = 0; i < size; ++i) { const DIERef &die_ref = m_map.GetValueAtIndexUnchecked(i); if (unit.GetSymbolFileDWARF().GetDwoNum() == die_ref.dwo_num() && unit.GetDebugSection() == die_ref.section() && unit.GetOffset() <= die_ref.die_offset() && - die_ref.die_offset() < unit.GetNextUnitOffset()) - info_array.push_back(die_ref); + die_ref.die_offset() < unit.GetNextUnitOffset()) { + if (!callback(die_ref)) + return; + } } - return info_array.size() - initial_size; } void NameToDIE::Dump(Stream *s) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h index b504f45e81b5..5aa841cf3d10 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_NameToDIE_h_ -#define SymbolFileDWARF_NameToDIE_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_NAMETODIE_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_NAMETODIE_H #include <functional> @@ -32,14 +32,15 @@ public: void Finalize(); - size_t Find(lldb_private::ConstString name, - DIEArray &info_array) const; + bool Find(lldb_private::ConstString name, + llvm::function_ref<bool(DIERef ref)> callback) const; - size_t Find(const lldb_private::RegularExpression ®ex, - DIEArray &info_array) const; + bool Find(const lldb_private::RegularExpression ®ex, + llvm::function_ref<bool(DIERef ref)> callback) const; - size_t FindAllEntriesForUnit(const DWARFUnit &unit, - DIEArray &info_array) const; + void + FindAllEntriesForUnit(const DWARFUnit &unit, + llvm::function_ref<bool(DIERef ref)> callback) const; void ForEach(std::function<bool(lldb_private::ConstString name, @@ -50,4 +51,4 @@ protected: lldb_private::UniqueCStringMap<DIERef> m_map; }; -#endif // SymbolFileDWARF_NameToDIE_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_NAMETODIE_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index d45a8b56efe4..9f64e5255fd5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1,4 +1,4 @@ -//===-- SymbolFileDWARF.cpp ------------------------------------*- C++ -*-===// +//===-- SymbolFileDWARF.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -34,9 +34,9 @@ #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" @@ -70,7 +70,6 @@ #include "ManualDWARFIndex.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" -#include "SymbolFileDWARFDwp.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Support/FileSystem.h" @@ -94,6 +93,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(SymbolFileDWARF) + char SymbolFileDWARF::ID; // static inline bool @@ -135,14 +136,6 @@ public: m_collection_sp->Initialize(g_symbolfiledwarf_properties); } - FileSpecList GetSymLinkPaths() { - const OptionValueFileSpecList *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList( - nullptr, true, ePropertySymLinkPaths); - assert(option_value); - return option_value->GetCurrentValue(); - } - bool IgnoreFileIndexes() const { return m_collection_sp->GetPropertyAtIndexAsBoolean( nullptr, ePropertyIgnoreIndexes, false); @@ -169,18 +162,46 @@ ParseLLVMLineTable(lldb_private::DWARFContext &context, llvm::Expected<const llvm::DWARFDebugLine::LineTable *> line_table = line.getOrParseLineTable( data, line_offset, ctx, nullptr, [&](llvm::Error e) { - LLDB_LOG_ERROR(log, std::move(e), - "SymbolFileDWARF::ParseLineTable failed to parse"); + LLDB_LOG_ERROR( + log, std::move(e), + "SymbolFileDWARF::ParseLineTable failed to parse: {0}"); }); if (!line_table) { LLDB_LOG_ERROR(log, line_table.takeError(), - "SymbolFileDWARF::ParseLineTable failed to parse"); + "SymbolFileDWARF::ParseLineTable failed to parse: {0}"); return nullptr; } return *line_table; } +static bool ParseLLVMLineTablePrologue(lldb_private::DWARFContext &context, + llvm::DWARFDebugLine::Prologue &prologue, + dw_offset_t line_offset, + dw_offset_t unit_offset) { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); + bool success = true; + llvm::DWARFDataExtractor data = context.getOrLoadLineData().GetAsLLVM(); + llvm::DWARFContext &ctx = context.GetAsLLVM(); + uint64_t offset = line_offset; + llvm::Error error = prologue.parse( + data, &offset, + [&](llvm::Error e) { + success = false; + LLDB_LOG_ERROR(log, std::move(e), + "SymbolFileDWARF::ParseSupportFiles failed to parse " + "line table prologue: {0}"); + }, + ctx, nullptr); + if (error) { + LLDB_LOG_ERROR(log, std::move(error), + "SymbolFileDWARF::ParseSupportFiles failed to parse line " + "table prologue: {0}"); + return false; + } + return success; +} + static llvm::Optional<std::string> GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx, llvm::StringRef compile_dir, FileSpec::Style style) { @@ -192,7 +213,7 @@ GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx, // Otherwise ask for a relative path. std::string rel_path; - auto relative = llvm::DILineInfoSpecifier::FileLineInfoKind::Default; + auto relative = llvm::DILineInfoSpecifier::FileLineInfoKind::RawValue; if (!prologue.getFileNameByIndex(idx, compile_dir, relative, rel_path, style)) return {}; return std::move(rel_path); @@ -227,15 +248,12 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, return support_files; } -FileSpecList SymbolFileDWARF::GetSymlinkPaths() { - return GetGlobalPluginProperties()->GetSymLinkPaths(); -} - void SymbolFileDWARF::Initialize() { LogChannelDWARF::Initialize(); PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, DebuggerInitialize); + SymbolFileDWARFDebugMap::Initialize(); } void SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) { @@ -250,6 +268,7 @@ void SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) { } void SymbolFileDWARF::Terminate() { + SymbolFileDWARFDebugMap::Terminate(); PluginManager::UnregisterPlugin(CreateInstance); LogChannelDWARF::Terminate(); } @@ -333,10 +352,8 @@ void SymbolFileDWARF::GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset, if (add_type) { const bool assert_not_being_parsed = true; Type *type = ResolveTypeUID(die, assert_not_being_parsed); - if (type) { - if (type_set.find(type) == type_set.end()) - type_set.insert(type); - } + if (type) + type_set.insert(type); } } @@ -366,15 +383,12 @@ void SymbolFileDWARF::GetTypes(SymbolContextScope *sc_scope, GetTypes(dwarf_cu->DIE(), dwarf_cu->GetOffset(), dwarf_cu->GetNextUnitOffset(), type_mask, type_set); } else { - DWARFDebugInfo *info = DebugInfo(); - if (info) { - const size_t num_cus = info->GetNumUnits(); - for (size_t cu_idx = 0; cu_idx < num_cus; ++cu_idx) { - dwarf_cu = info->GetUnitAtIndex(cu_idx); - if (dwarf_cu) { - GetTypes(dwarf_cu->DIE(), 0, UINT32_MAX, type_mask, type_set); - } - } + DWARFDebugInfo &info = DebugInfo(); + const size_t num_cus = info.GetNumUnits(); + for (size_t cu_idx = 0; cu_idx < num_cus; ++cu_idx) { + dwarf_cu = info.GetUnitAtIndex(cu_idx); + if (dwarf_cu) + GetTypes(dwarf_cu->DIE(), 0, UINT32_MAX, type_mask, type_set); } } @@ -418,9 +432,8 @@ SymbolFileDWARF::SymbolFileDWARF(ObjectFileSP objfile_sp, // contain the .o file index/ID m_debug_map_module_wp(), m_debug_map_symfile(nullptr), m_context(m_objfile_sp->GetModule()->GetSectionList(), dwo_section_list), - m_data_debug_loc(), m_abbr(), m_info(), m_fetched_external_modules(false), - m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate), - m_unique_ast_type_map() {} + m_fetched_external_modules(false), + m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate) {} SymbolFileDWARF::~SymbolFileDWARF() {} @@ -471,9 +484,9 @@ void SymbolFileDWARF::InitializeObject() { LoadSectionData(eSectionTypeDWARFDebugNames, debug_names); if (debug_names.GetByteSize() > 0) { llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> index_or = - DebugNamesDWARFIndex::Create( - *GetObjectFile()->GetModule(), debug_names, - m_context.getOrLoadStrData(), DebugInfo()); + DebugNamesDWARFIndex::Create(*GetObjectFile()->GetModule(), + debug_names, + m_context.getOrLoadStrData(), *this); if (index_or) { m_index = std::move(*index_or); return; @@ -483,8 +496,8 @@ void SymbolFileDWARF::InitializeObject() { } } - m_index = std::make_unique<ManualDWARFIndex>(*GetObjectFile()->GetModule(), - DebugInfo()); + m_index = + std::make_unique<ManualDWARFIndex>(*GetObjectFile()->GetModule(), *this); } bool SymbolFileDWARF::SupportedVersion(uint16_t version) { @@ -573,15 +586,6 @@ uint32_t SymbolFileDWARF::CalculateAbilities() { return abilities; } -const DWARFDataExtractor & -SymbolFileDWARF::GetCachedSectionData(lldb::SectionType sect_type, - DWARFDataSegment &data_segment) { - llvm::call_once(data_segment.m_flag, [this, sect_type, &data_segment] { - this->LoadSectionData(sect_type, std::ref(data_segment.m_data)); - }); - return data_segment.m_data; -} - void SymbolFileDWARF::LoadSectionData(lldb::SectionType sect_type, DWARFDataExtractor &data) { ModuleSP module_sp(m_objfile_sp->GetModule()); @@ -618,23 +622,14 @@ DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { return m_abbr.get(); } -const DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() const { - return m_abbr.get(); -} - -DWARFDebugInfo *SymbolFileDWARF::DebugInfo() { - if (m_info == nullptr) { +DWARFDebugInfo &SymbolFileDWARF::DebugInfo() { + llvm::call_once(m_info_once_flag, [&] { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, static_cast<void *>(this)); - if (m_context.getOrLoadDebugInfoData().GetByteSize() > 0) - m_info = std::make_unique<DWARFDebugInfo>(*this, m_context); - } - return m_info.get(); -} - -const DWARFDebugInfo *SymbolFileDWARF::DebugInfo() const { - return m_info.get(); + m_info = std::make_unique<DWARFDebugInfo>(*this, m_context); + }); + return *m_info; } DWARFUnit * @@ -642,15 +637,11 @@ SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { if (!comp_unit) return nullptr; - DWARFDebugInfo *info = DebugInfo(); - if (info) { - // The compile unit ID is the index of the DWARF unit. - DWARFUnit *dwarf_cu = info->GetUnitAtIndex(comp_unit->GetID()); - if (dwarf_cu && dwarf_cu->GetUserData() == nullptr) - dwarf_cu->SetUserData(comp_unit); - return dwarf_cu; - } - return nullptr; + // The compile unit ID is the index of the DWARF unit. + DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(comp_unit->GetID()); + if (dwarf_cu && dwarf_cu->GetUserData() == nullptr) + dwarf_cu->SetUserData(comp_unit); + return dwarf_cu; } DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { @@ -660,7 +651,7 @@ DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { static_cast<void *>(this)); if (m_context.getOrLoadRangesData().GetByteSize() > 0) - m_ranges.reset(new DWARFDebugRanges()); + m_ranges = std::make_unique<DWARFDebugRanges>(); if (m_ranges) m_ranges->Extract(m_context); @@ -668,6 +659,22 @@ DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { return m_ranges.get(); } +/// Make an absolute path out of \p file_spec and remap it using the +/// module's source remapping dictionary. +static void MakeAbsoluteAndRemap(FileSpec &file_spec, DWARFUnit &dwarf_cu, + const ModuleSP &module_sp) { + if (!file_spec) + return; + // If we have a full path to the compile unit, we don't need to + // resolve the file. This can be expensive e.g. when the source + // files are NFS mounted. + file_spec.MakeAbsolute(dwarf_cu.GetCompilationDirectory()); + + std::string remapped_file; + if (module_sp->RemapSourceFile(file_spec.GetPath(), remapped_file)) + file_spec.SetFile(remapped_file, FileSpec::Style::native); +} + lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { CompUnitSP cu_sp; CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); @@ -675,9 +682,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { // We already parsed this compile unit, had out a shared pointer to it cu_sp = comp_unit->shared_from_this(); } else { - if (&dwarf_cu.GetSymbolFileDWARF() != this) { - return dwarf_cu.GetSymbolFileDWARF().ParseCompileUnit(dwarf_cu); - } else if (dwarf_cu.GetOffset() == 0 && GetDebugMapSymfile()) { + if (dwarf_cu.GetOffset() == 0 && GetDebugMapSymfile()) { // Let the debug map create the compile unit cu_sp = m_debug_map_symfile->GetCompileUnit(this); dwarf_cu.SetUserData(cu_sp.get()); @@ -688,19 +693,9 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { dwarf_cu.GetNonSkeletonUnit().GetUnitDIEOnly(); if (cu_die) { FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); - if (cu_file_spec) { - // If we have a full path to the compile unit, we don't need to - // resolve the file. This can be expensive e.g. when the source - // files are NFS mounted. - cu_file_spec.MakeAbsolute(dwarf_cu.GetCompilationDirectory()); - - std::string remapped_file; - if (module_sp->RemapSourceFile(cu_file_spec.GetPath(), - remapped_file)) - cu_file_spec.SetFile(remapped_file, FileSpec::Style::native); - } + MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp); - LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( + LanguageType cu_language = SymbolFileDWARF::LanguageTypeFromDWARF( cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); bool is_optimized = dwarf_cu.GetNonSkeletonUnit().GetIsOptimized(); @@ -724,16 +719,13 @@ void SymbolFileDWARF::BuildCuTranslationTable() { if (!m_lldb_cu_to_dwarf_unit.empty()) return; - DWARFDebugInfo *info = DebugInfo(); - if (!info) - return; - - if (!info->ContainsTypeUnits()) { + DWARFDebugInfo &info = DebugInfo(); + if (!info.ContainsTypeUnits()) { // We can use a 1-to-1 mapping. No need to build a translation table. return; } - for (uint32_t i = 0, num = info->GetNumUnits(); i < num; ++i) { - if (auto *cu = llvm::dyn_cast<DWARFCompileUnit>(info->GetUnitAtIndex(i))) { + for (uint32_t i = 0, num = info.GetNumUnits(); i < num; ++i) { + if (auto *cu = llvm::dyn_cast<DWARFCompileUnit>(info.GetUnitAtIndex(i))) { cu->SetID(m_lldb_cu_to_dwarf_unit.size()); m_lldb_cu_to_dwarf_unit.push_back(i); } @@ -750,23 +742,16 @@ llvm::Optional<uint32_t> SymbolFileDWARF::GetDWARFUnitIndex(uint32_t cu_idx) { } uint32_t SymbolFileDWARF::CalculateNumCompileUnits() { - DWARFDebugInfo *info = DebugInfo(); - if (!info) - return 0; BuildCuTranslationTable(); - return m_lldb_cu_to_dwarf_unit.empty() ? info->GetNumUnits() + return m_lldb_cu_to_dwarf_unit.empty() ? DebugInfo().GetNumUnits() : m_lldb_cu_to_dwarf_unit.size(); } CompUnitSP SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) { ASSERT_MODULE_LOCK(this); - DWARFDebugInfo *info = DebugInfo(); - if (!info) - return {}; - if (llvm::Optional<uint32_t> dwarf_idx = GetDWARFUnitIndex(cu_idx)) { if (auto *dwarf_cu = llvm::cast_or_null<DWARFCompileUnit>( - info->GetUnitAtIndex(*dwarf_idx))) + DebugInfo().GetUnitAtIndex(*dwarf_idx))) return ParseCompileUnit(*dwarf_cu); } return {}; @@ -778,8 +763,7 @@ Function *SymbolFileDWARF::ParseFunction(CompileUnit &comp_unit, if (!die.IsValid()) return nullptr; - auto type_system_or_err = - GetTypeSystemForLanguage(die.GetCU()->GetLanguageType()); + auto type_system_or_err = GetTypeSystemForLanguage(GetLanguage(*die.GetCU())); if (auto err = type_system_or_err.takeError()) { LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS), std::move(err), "Unable to parse function"); @@ -792,6 +776,13 @@ Function *SymbolFileDWARF::ParseFunction(CompileUnit &comp_unit, return dwarf_ast->ParseFunctionFromDWARF(comp_unit, die); } +lldb::addr_t SymbolFileDWARF::FixupAddress(lldb::addr_t file_addr) { + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) + return debug_map_symfile->LinkOSOFileAddress(this, file_addr); + return file_addr; +} + bool SymbolFileDWARF::FixupAddress(Address &addr) { SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); if (debug_map_symfile) { @@ -804,11 +795,39 @@ lldb::LanguageType SymbolFileDWARF::ParseLanguage(CompileUnit &comp_unit) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) - return dwarf_cu->GetLanguageType(); + return GetLanguage(*dwarf_cu); else return eLanguageTypeUnknown; } +XcodeSDK SymbolFileDWARF::ParseXcodeSDK(CompileUnit &comp_unit) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); + if (!dwarf_cu) + return {}; + const DWARFBaseDIE cu_die = dwarf_cu->GetNonSkeletonUnit().GetUnitDIEOnly(); + if (!cu_die) + return {}; + const char *sdk = cu_die.GetAttributeValueAsString(DW_AT_APPLE_sdk, nullptr); + if (!sdk) + return {}; + const char *sysroot = + cu_die.GetAttributeValueAsString(DW_AT_LLVM_sysroot, ""); + // Register the sysroot path remapping with the module belonging to + // the CU as well as the one belonging to the symbol file. The two + // would be different if this is an OSO object and module is the + // corresponding debug map, in which case both should be updated. + ModuleSP module_sp = comp_unit.GetModule(); + if (module_sp) + module_sp->RegisterXcodeSDK(sdk, sysroot); + + ModuleSP local_module_sp = m_objfile_sp->GetModule(); + if (local_module_sp && local_module_sp != module_sp) + local_module_sp->RegisterXcodeSDK(sdk, sysroot); + + return {sdk}; +} + size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "SymbolFileDWARF::ParseFunctions"); @@ -863,8 +882,24 @@ bool SymbolFileDWARF::ForEachExternalModule( bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit, FileSpecList &support_files) { - if (!comp_unit.GetLineTable()) - ParseLineTable(comp_unit); + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); + if (!dwarf_cu) + return false; + + dw_offset_t offset = dwarf_cu->GetLineTableOffset(); + if (offset == DW_INVALID_OFFSET) + return false; + + llvm::DWARFDebugLine::Prologue prologue; + if (!ParseLLVMLineTablePrologue(m_context, prologue, offset, + dwarf_cu->GetOffset())) + return false; + + comp_unit.SetSupportFiles(ParseSupportFilesFromPrologue( + comp_unit.GetModule(), prologue, dwarf_cu->GetPathStyle(), + dwarf_cu->GetCompilationDirectory().GetCString())); + return true; } @@ -898,12 +933,15 @@ SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) { llvm::DWARFDataExtractor data = m_context.getOrLoadLineData().GetAsLLVM(); llvm::DWARFContext &ctx = m_context.GetAsLLVM(); llvm::DWARFDebugLine::Prologue prologue; - llvm::Error error = prologue.parse(data, &line_table_offset, ctx); - if (error) { + auto report = [](llvm::Error error) { Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); LLDB_LOG_ERROR(log, std::move(error), "SymbolFileDWARF::GetTypeUnitSupportFiles failed to parse " "the line table prologue"); + }; + llvm::Error error = prologue.parse(data, &line_table_offset, report, ctx); + if (error) { + report(std::move(error)); } else { list = ParseSupportFilesFromPrologue(GetObjectFile()->GetModule(), prologue, tu.GetPathStyle()); @@ -961,9 +999,12 @@ bool SymbolFileDWARF::ParseImportedModules( } std::reverse(module.path.begin(), module.path.end()); if (const char *include_path = module_die.GetAttributeValueAsString( - DW_AT_LLVM_include_path, nullptr)) - module.search_path = ConstString(include_path); - if (const char *sysroot = module_die.GetAttributeValueAsString( + DW_AT_LLVM_include_path, nullptr)) { + FileSpec include_spec(include_path, dwarf_cu->GetPathStyle()); + MakeAbsoluteAndRemap(include_spec, *dwarf_cu, m_objfile_sp->GetModule()); + module.search_path = ConstString(include_spec.GetPath()); + } + if (const char *sysroot = dwarf_cu->DIE().GetAttributeValueAsString( DW_AT_LLVM_sysroot, nullptr)) module.sysroot = ConstString(sysroot); imported_modules.push_back(module); @@ -981,18 +1022,13 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) { if (!dwarf_cu) return false; - const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly(); - if (!dwarf_cu_die) - return false; - - const dw_offset_t cu_line_offset = dwarf_cu_die.GetAttributeValueAsUnsigned( - DW_AT_stmt_list, DW_INVALID_OFFSET); - if (cu_line_offset == DW_INVALID_OFFSET) + dw_offset_t offset = dwarf_cu->GetLineTableOffset(); + if (offset == DW_INVALID_OFFSET) return false; llvm::DWARFDebugLine line; - const llvm::DWARFDebugLine::LineTable *line_table = ParseLLVMLineTable( - m_context, line, cu_line_offset, dwarf_cu->GetOffset()); + const llvm::DWARFDebugLine::LineTable *line_table = + ParseLLVMLineTable(m_context, line, offset, dwarf_cu->GetOffset()); if (!line_table) return false; @@ -1000,20 +1036,23 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) { // FIXME: Rather than parsing the whole line table and then copying it over // into LLDB, we should explore using a callback to populate the line table // while we parse to reduce memory usage. - std::unique_ptr<LineTable> line_table_up = - std::make_unique<LineTable>(&comp_unit); - LineSequence *sequence = line_table_up->CreateLineSequenceContainer(); + std::unique_ptr<LineSequence> sequence = + LineTable::CreateLineSequenceContainer(); + std::vector<std::unique_ptr<LineSequence>> sequences; for (auto &row : line_table->Rows) { - line_table_up->AppendLineEntryToSequence( - sequence, row.Address.Address, row.Line, row.Column, row.File, + LineTable::AppendLineEntryToSequence( + sequence.get(), row.Address.Address, row.Line, row.Column, row.File, row.IsStmt, row.BasicBlock, row.PrologueEnd, row.EpilogueBegin, row.EndSequence); if (row.EndSequence) { - line_table_up->InsertSequence(sequence); - sequence = line_table_up->CreateLineSequenceContainer(); + sequences.push_back(std::move(sequence)); + sequence = LineTable::CreateLineSequenceContainer(); } } + std::unique_ptr<LineTable> line_table_up = + std::make_unique<LineTable>(&comp_unit, std::move(sequences)); + if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile()) { // We have an object file that has a line table with addresses that are not // linked. We need to link the line table and convert the addresses that @@ -1024,10 +1063,6 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) { comp_unit.SetLineTable(line_table_up.release()); } - comp_unit.SetSupportFiles(ParseSupportFilesFromPrologue( - comp_unit.GetModule(), line_table->Prologue, dwarf_cu->GetPathStyle(), - dwarf_cu->GetCompilationDirectory().GetCString())); - return true; } @@ -1157,15 +1192,15 @@ size_t SymbolFileDWARF::ParseBlocksRecursive( (name != nullptr || mangled_name != nullptr)) { std::unique_ptr<Declaration> decl_up; if (decl_file != 0 || decl_line != 0 || decl_column != 0) - decl_up.reset(new Declaration( + decl_up = std::make_unique<Declaration>( comp_unit.GetSupportFiles().GetFileSpecAtIndex(decl_file), - decl_line, decl_column)); + decl_line, decl_column); std::unique_ptr<Declaration> call_up; if (call_file != 0 || call_line != 0 || call_column != 0) - call_up.reset(new Declaration( + call_up = std::make_unique<Declaration>( comp_unit.GetSupportFiles().GetFileSpecAtIndex(call_file), - call_line, call_column)); + call_line, call_column); block->SetInlinedFunctionInfo(name, mangled_name, decl_up.get(), call_up.get()); @@ -1289,7 +1324,7 @@ CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) { // SymbolFileDWARF::GetDIE(). See comments inside the // SymbolFileDWARF::GetDIE() for details. if (DWARFDIE die = GetDIE(type_uid)) - return die.GetDecl(); + return GetDecl(die); return CompilerDecl(); } @@ -1302,7 +1337,7 @@ SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) { // SymbolFileDWARF::GetDIE(). See comments inside the // SymbolFileDWARF::GetDIE() for details. if (DWARFDIE die = GetDIE(type_uid)) - return die.GetDeclContext(); + return GetDeclContext(die); return CompilerDeclContext(); } @@ -1313,7 +1348,7 @@ SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) { // SymbolFileDWARF::GetDIE(). See comments inside the // SymbolFileDWARF::GetDIE() for details. if (DWARFDIE die = GetDIE(type_uid)) - return die.GetContainingDeclContext(); + return GetContainingDeclContext(die); return CompilerDeclContext(); } @@ -1394,8 +1429,8 @@ bool SymbolFileDWARF::HasForwardDeclForClangType( } TypeSystem *type_system = compiler_type.GetTypeSystem(); - ClangASTContext *clang_type_system = - llvm::dyn_cast_or_null<ClangASTContext>(type_system); + TypeSystemClang *clang_type_system = + llvm::dyn_cast_or_null<TypeSystemClang>(type_system); if (!clang_type_system) return false; DWARFASTParserClang *ast_parser = @@ -1406,8 +1441,8 @@ bool SymbolFileDWARF::HasForwardDeclForClangType( bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - ClangASTContext *clang_type_system = - llvm::dyn_cast_or_null<ClangASTContext>(compiler_type.GetTypeSystem()); + TypeSystemClang *clang_type_system = + llvm::dyn_cast_or_null<TypeSystemClang>(compiler_type.GetTypeSystem()); if (clang_type_system) { DWARFASTParserClang *ast_parser = static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser()); @@ -1444,8 +1479,7 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { dwarf_die.GetID(), dwarf_die.GetTagAsCString(), type->GetName().AsCString()); assert(compiler_type); - DWARFASTParser *dwarf_ast = dwarf_die.GetDWARFParser(); - if (dwarf_ast) + if (DWARFASTParser *dwarf_ast = GetDWARFParser(*dwarf_die.GetCU())) return dwarf_ast->CompleteTypeFromDWARF(dwarf_die, type, compiler_type); } return false; @@ -1473,20 +1507,25 @@ Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die, CompileUnit * SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit &dwarf_cu) { + if (dwarf_cu.IsDWOUnit()) { + DWARFCompileUnit *non_dwo_cu = + static_cast<DWARFCompileUnit *>(dwarf_cu.GetUserData()); + assert(non_dwo_cu); + return non_dwo_cu->GetSymbolFileDWARF().GetCompUnitForDWARFCompUnit( + *non_dwo_cu); + } // Check if the symbol vendor already knows about this compile unit? if (dwarf_cu.GetUserData() == nullptr) { // The symbol vendor doesn't know about this compile unit, we need to parse // and add it to the symbol vendor object. return ParseCompileUnit(dwarf_cu).get(); } - return (CompileUnit *)dwarf_cu.GetUserData(); + return static_cast<CompileUnit *>(dwarf_cu.GetUserData()); } -size_t SymbolFileDWARF::GetObjCMethodDIEOffsets(ConstString class_name, - DIEArray &method_die_offsets) { - method_die_offsets.clear(); - m_index->GetObjCMethods(class_name, method_die_offsets); - return method_die_offsets.size(); +void SymbolFileDWARF::GetObjCMethods( + ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) { + m_index->GetObjCMethods(class_name, callback); } bool SymbolFileDWARF::GetFunction(const DWARFDIE &die, SymbolContext &sc) { @@ -1522,17 +1561,15 @@ lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) { DWARFDIE SymbolFileDWARF::GetDIE(const DIERef &die_ref) { if (die_ref.dwo_num()) { - return DebugInfo() - ->GetUnitAtIndex(*die_ref.dwo_num()) - ->GetDwoSymbolFile() - ->GetDIE(die_ref); + SymbolFileDWARF *dwarf = *die_ref.dwo_num() == 0x3fffffff + ? m_dwp_symfile.get() + : this->DebugInfo() + .GetUnitAtIndex(*die_ref.dwo_num()) + ->GetDwoSymbolFile(); + return dwarf->DebugInfo().GetDIE(die_ref); } - DWARFDebugInfo *debug_info = DebugInfo(); - if (debug_info) - return debug_info->GetDIE(die_ref); - else - return DWARFDIE(); + return DebugInfo().GetDIE(die_ref); } /// Return the DW_AT_(GNU_)dwo_name. @@ -1569,7 +1606,7 @@ llvm::Optional<uint64_t> SymbolFileDWARF::GetDWOId() { return {}; } -std::unique_ptr<SymbolFileDWARFDwo> +std::shared_ptr<SymbolFileDWARFDwo> SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( DWARFUnit &unit, const DWARFDebugInfoEntry &cu_die) { // If this is a Darwin-style debug map (non-.dSYM) symbol file, @@ -1589,14 +1626,8 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( if (!dwo_name) return nullptr; - SymbolFileDWARFDwp *dwp_symfile = GetDwpSymbolFile(); - if (dwp_symfile) { - uint64_t dwo_id = ::GetDWOId(*dwarf_cu, cu_die); - std::unique_ptr<SymbolFileDWARFDwo> dwo_symfile = - dwp_symfile->GetSymbolFileForDwoId(*dwarf_cu, dwo_id); - if (dwo_symfile) - return dwo_symfile; - } + if (std::shared_ptr<SymbolFileDWARFDwo> dwp_sp = GetDwpSymbolFile()) + return dwp_sp; FileSpec dwo_file(dwo_name); FileSystem::Instance().Resolve(dwo_file); @@ -1624,20 +1655,21 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( if (dwo_obj_file == nullptr) return nullptr; - return std::make_unique<SymbolFileDWARFDwo>(dwo_obj_file, *dwarf_cu); + return std::make_shared<SymbolFileDWARFDwo>(*this, dwo_obj_file, + dwarf_cu->GetID()); } void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { if (m_fetched_external_modules) return; m_fetched_external_modules = true; - DWARFDebugInfo *debug_info = DebugInfo(); + DWARFDebugInfo &debug_info = DebugInfo(); // Follow DWO skeleton unit breadcrumbs. const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { auto *dwarf_cu = - llvm::dyn_cast<DWARFCompileUnit>(debug_info->GetUnitAtIndex(cu_idx)); + llvm::dyn_cast<DWARFCompileUnit>(debug_info.GetUnitAtIndex(cu_idx)); if (!dwarf_cu) continue; @@ -1731,7 +1763,7 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() { if (!m_global_aranges_up) { - m_global_aranges_up.reset(new GlobalVariableMap()); + m_global_aranges_up = std::make_unique<GlobalVariableMap>(); ModuleSP module_sp = GetObjectFile()->GetModule(); if (module_sp) { @@ -1773,6 +1805,32 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() { return *m_global_aranges_up; } +void SymbolFileDWARF::ResolveFunctionAndBlock(lldb::addr_t file_vm_addr, + bool lookup_block, + SymbolContext &sc) { + assert(sc.comp_unit); + DWARFUnit &cu = GetDWARFCompileUnit(sc.comp_unit)->GetNonSkeletonUnit(); + DWARFDIE function_die = cu.LookupAddress(file_vm_addr); + DWARFDIE block_die; + if (function_die) { + sc.function = sc.comp_unit->FindFunctionByUID(function_die.GetID()).get(); + if (sc.function == nullptr) + sc.function = ParseFunction(*sc.comp_unit, function_die); + + if (sc.function && lookup_block) + block_die = function_die.LookupDeepestBlock(file_vm_addr); + } + + if (!sc.function || ! lookup_block) + return; + + Block &block = sc.function->GetBlock(true); + if (block_die) + sc.block = block.FindBlockByID(block_die.GetID()); + else + sc.block = block.FindBlockByID(function_die.GetID()); +} + uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, SymbolContextItem resolve_scope, SymbolContext &sc) { @@ -1791,123 +1849,99 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, eSymbolContextLineEntry | eSymbolContextVariable)) { lldb::addr_t file_vm_addr = so_addr.GetFileAddress(); - DWARFDebugInfo *debug_info = DebugInfo(); - if (debug_info) { - llvm::Expected<DWARFDebugAranges &> aranges = - debug_info->GetCompileUnitAranges(); - if (!aranges) { - Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); - LLDB_LOG_ERROR(log, aranges.takeError(), - "SymbolFileDWARF::ResolveSymbolContext failed to get cu " - "aranges. {0}"); - return 0; - } + DWARFDebugInfo &debug_info = DebugInfo(); + llvm::Expected<DWARFDebugAranges &> aranges = + debug_info.GetCompileUnitAranges(); + if (!aranges) { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); + LLDB_LOG_ERROR(log, aranges.takeError(), + "SymbolFileDWARF::ResolveSymbolContext failed to get cu " + "aranges. {0}"); + return 0; + } - const dw_offset_t cu_offset = aranges->FindAddress(file_vm_addr); - if (cu_offset == DW_INVALID_OFFSET) { - // Global variables are not in the compile unit address ranges. The - // only way to currently find global variables is to iterate over the - // .debug_pubnames or the __apple_names table and find all items in - // there that point to DW_TAG_variable DIEs and then find the address - // that matches. - if (resolve_scope & eSymbolContextVariable) { - GlobalVariableMap &map = GetGlobalAranges(); - const GlobalVariableMap::Entry *entry = - map.FindEntryThatContains(file_vm_addr); - if (entry && entry->data) { - Variable *variable = entry->data; - SymbolContextScope *scc = variable->GetSymbolContextScope(); - if (scc) { - scc->CalculateSymbolContext(&sc); - sc.variable = variable; - } - return sc.GetResolvedMask(); + const dw_offset_t cu_offset = aranges->FindAddress(file_vm_addr); + if (cu_offset == DW_INVALID_OFFSET) { + // Global variables are not in the compile unit address ranges. The only + // way to currently find global variables is to iterate over the + // .debug_pubnames or the __apple_names table and find all items in there + // that point to DW_TAG_variable DIEs and then find the address that + // matches. + if (resolve_scope & eSymbolContextVariable) { + GlobalVariableMap &map = GetGlobalAranges(); + const GlobalVariableMap::Entry *entry = + map.FindEntryThatContains(file_vm_addr); + if (entry && entry->data) { + Variable *variable = entry->data; + SymbolContextScope *scc = variable->GetSymbolContextScope(); + if (scc) { + scc->CalculateSymbolContext(&sc); + sc.variable = variable; } + return sc.GetResolvedMask(); } - } else { - uint32_t cu_idx = DW_INVALID_INDEX; - if (auto *dwarf_cu = llvm::dyn_cast_or_null<DWARFCompileUnit>( - debug_info->GetUnitAtOffset(DIERef::Section::DebugInfo, - cu_offset, &cu_idx))) { - sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu); - if (sc.comp_unit) { - resolved |= eSymbolContextCompUnit; - - bool force_check_line_table = false; - if (resolve_scope & - (eSymbolContextFunction | eSymbolContextBlock)) { - DWARFDIE function_die = dwarf_cu->LookupAddress(file_vm_addr); - DWARFDIE block_die; - if (function_die) { - sc.function = - sc.comp_unit->FindFunctionByUID(function_die.GetID()).get(); - if (sc.function == nullptr) - sc.function = ParseFunction(*sc.comp_unit, function_die); - - if (sc.function && (resolve_scope & eSymbolContextBlock)) - block_die = function_die.LookupDeepestBlock(file_vm_addr); - } else { - // We might have had a compile unit that had discontiguous - // address ranges where the gaps are symbols that don't have - // any debug info. Discontiguous compile unit address ranges - // should only happen when there aren't other functions from - // other compile units in these gaps. This helps keep the size - // of the aranges down. - force_check_line_table = true; - } - - if (sc.function != nullptr) { - resolved |= eSymbolContextFunction; - - if (resolve_scope & eSymbolContextBlock) { - Block &block = sc.function->GetBlock(true); - - if (block_die) - sc.block = block.FindBlockByID(block_die.GetID()); - else - sc.block = block.FindBlockByID(function_die.GetID()); - if (sc.block) - resolved |= eSymbolContextBlock; - } - } + } + } else { + uint32_t cu_idx = DW_INVALID_INDEX; + if (auto *dwarf_cu = llvm::dyn_cast_or_null<DWARFCompileUnit>( + debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, cu_offset, + &cu_idx))) { + sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu); + if (sc.comp_unit) { + resolved |= eSymbolContextCompUnit; + + bool force_check_line_table = false; + if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) { + ResolveFunctionAndBlock(file_vm_addr, + resolve_scope & eSymbolContextBlock, sc); + if (sc.function) + resolved |= eSymbolContextFunction; + else { + // We might have had a compile unit that had discontiguous address + // ranges where the gaps are symbols that don't have any debug + // info. Discontiguous compile unit address ranges should only + // happen when there aren't other functions from other compile + // units in these gaps. This helps keep the size of the aranges + // down. + force_check_line_table = true; } + if (sc.block) + resolved |= eSymbolContextBlock; + } - if ((resolve_scope & eSymbolContextLineEntry) || - force_check_line_table) { - LineTable *line_table = sc.comp_unit->GetLineTable(); - if (line_table != nullptr) { - // And address that makes it into this function should be in - // terms of this debug file if there is no debug map, or it - // will be an address in the .o file which needs to be fixed up - // to be in terms of the debug map executable. Either way, - // calling FixupAddress() will work for us. - Address exe_so_addr(so_addr); - if (FixupAddress(exe_so_addr)) { - if (line_table->FindLineEntryByAddress(exe_so_addr, - sc.line_entry)) { - resolved |= eSymbolContextLineEntry; - } + if ((resolve_scope & eSymbolContextLineEntry) || + force_check_line_table) { + LineTable *line_table = sc.comp_unit->GetLineTable(); + if (line_table != nullptr) { + // And address that makes it into this function should be in terms + // of this debug file if there is no debug map, or it will be an + // address in the .o file which needs to be fixed up to be in + // terms of the debug map executable. Either way, calling + // FixupAddress() will work for us. + Address exe_so_addr(so_addr); + if (FixupAddress(exe_so_addr)) { + if (line_table->FindLineEntryByAddress(exe_so_addr, + sc.line_entry)) { + resolved |= eSymbolContextLineEntry; } } } + } - if (force_check_line_table && - !(resolved & eSymbolContextLineEntry)) { - // We might have had a compile unit that had discontiguous - // address ranges where the gaps are symbols that don't have any - // debug info. Discontiguous compile unit address ranges should - // only happen when there aren't other functions from other - // compile units in these gaps. This helps keep the size of the - // aranges down. - sc.comp_unit = nullptr; - resolved &= ~eSymbolContextCompUnit; - } - } else { - GetObjectFile()->GetModule()->ReportWarning( - "0x%8.8x: compile unit %u failed to create a valid " - "lldb_private::CompileUnit class.", - cu_offset, cu_idx); + if (force_check_line_table && !(resolved & eSymbolContextLineEntry)) { + // We might have had a compile unit that had discontiguous address + // ranges where the gaps are symbols that don't have any debug info. + // Discontiguous compile unit address ranges should only happen when + // there aren't other functions from other compile units in these + // gaps. This helps keep the size of the aranges down. + sc.comp_unit = nullptr; + resolved &= ~eSymbolContextCompUnit; } + } else { + GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8x: compile unit %u failed to create a valid " + "lldb_private::CompileUnit class.", + cu_offset, cu_idx); } } } @@ -1969,30 +2003,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, const lldb::addr_t file_vm_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress(); if (file_vm_addr != LLDB_INVALID_ADDRESS) { - DWARFDIE function_die = - GetDWARFCompileUnit(dc_cu)->LookupAddress(file_vm_addr); - DWARFDIE block_die; - if (function_die) { - sc.function = - sc.comp_unit->FindFunctionByUID(function_die.GetID()) - .get(); - if (sc.function == nullptr) - sc.function = - ParseFunction(*sc.comp_unit, function_die); - - if (sc.function && (resolve_scope & eSymbolContextBlock)) - block_die = - function_die.LookupDeepestBlock(file_vm_addr); - } - - if (sc.function != nullptr) { - Block &block = sc.function->GetBlock(true); - - if (block_die) - sc.block = block.FindBlockByID(block_die.GetID()); - else if (function_die) - sc.block = block.FindBlockByID(function_die.GetID()); - } + ResolveFunctionAndBlock( + file_vm_addr, resolve_scope & eSymbolContextBlock, sc); } } @@ -2035,15 +2047,15 @@ std::recursive_mutex &SymbolFileDWARF::GetModuleMutex() const { } bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile( - const lldb_private::CompilerDeclContext *decl_ctx) { - if (decl_ctx == nullptr || !decl_ctx->IsValid()) { + const lldb_private::CompilerDeclContext &decl_ctx) { + if (!decl_ctx.IsValid()) { // Invalid namespace decl which means we aren't matching only things in // this symbol file, so return true to indicate it matches this symbol // file. return true; } - TypeSystem *decl_ctx_type_system = decl_ctx->GetTypeSystem(); + TypeSystem *decl_ctx_type_system = decl_ctx.GetTypeSystem(); auto type_system_or_err = GetTypeSystemForLanguage( decl_ctx_type_system->GetMinimumLanguage(nullptr)); if (auto err = type_system_or_err.takeError()) { @@ -2067,7 +2079,7 @@ bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile( } void SymbolFileDWARF::FindGlobalVariables( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, VariableList &variables) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); @@ -2077,16 +2089,12 @@ void SymbolFileDWARF::FindGlobalVariables( log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " "parent_decl_ctx=%p, max_matches=%u, variables)", - name.GetCString(), static_cast<const void *>(parent_decl_ctx), + name.GetCString(), static_cast<const void *>(&parent_decl_ctx), max_matches); if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) return; - DWARFDebugInfo *info = DebugInfo(); - if (!info) - return; - // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); @@ -2098,69 +2106,46 @@ void SymbolFileDWARF::FindGlobalVariables( context, basename)) basename = name.GetStringRef(); - DIEArray die_offsets; - m_index->GetGlobalVariables(ConstString(basename), die_offsets); - const size_t num_die_matches = die_offsets.size(); - if (num_die_matches) { - SymbolContext sc; - sc.module_sp = m_objfile_sp->GetModule(); - assert(sc.module_sp); - - // Loop invariant: Variables up to this index have been checked for context - // matches. - uint32_t pruned_idx = original_size; + // Loop invariant: Variables up to this index have been checked for context + // matches. + uint32_t pruned_idx = original_size; - bool done = false; - for (size_t i = 0; i < num_die_matches && !done; ++i) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = GetDIE(die_ref); - - if (die) { - switch (die.Tag()) { - default: - case DW_TAG_subprogram: - case DW_TAG_inlined_subroutine: - case DW_TAG_try_block: - case DW_TAG_catch_block: - break; + SymbolContext sc; + m_index->GetGlobalVariables(ConstString(basename), [&](DWARFDIE die) { + if (!sc.module_sp) + sc.module_sp = m_objfile_sp->GetModule(); + assert(sc.module_sp); - case DW_TAG_variable: { - auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU()); - if (!dwarf_cu) - continue; - sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu); - - if (parent_decl_ctx) { - DWARFASTParser *dwarf_ast = die.GetDWARFParser(); - if (dwarf_ast) { - CompilerDeclContext actual_parent_decl_ctx = - dwarf_ast->GetDeclContextContainingUIDFromDWARF(die); - if (!actual_parent_decl_ctx || - actual_parent_decl_ctx != *parent_decl_ctx) - continue; - } - } + if (die.Tag() != DW_TAG_variable) + return true; - ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, - &variables); - while (pruned_idx < variables.GetSize()) { - VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx); - if (name_is_mangled || - var_sp->GetName().GetStringRef().contains(name.GetStringRef())) - ++pruned_idx; - else - variables.RemoveVariableAtIndex(pruned_idx); - } + auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU()); + if (!dwarf_cu) + return true; + sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu); - if (variables.GetSize() - original_size >= max_matches) - done = true; - } break; - } - } else { - m_index->ReportInvalidDIERef(die_ref, name.GetStringRef()); + if (parent_decl_ctx) { + if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) { + CompilerDeclContext actual_parent_decl_ctx = + dwarf_ast->GetDeclContextContainingUIDFromDWARF(die); + if (!actual_parent_decl_ctx || + actual_parent_decl_ctx != parent_decl_ctx) + return true; } } - } + + ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables); + while (pruned_idx < variables.GetSize()) { + VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx); + if (name_is_mangled || + var_sp->GetName().GetStringRef().contains(name.GetStringRef())) + ++pruned_idx; + else + variables.RemoveVariableAtIndex(pruned_idx); + } + + return variables.GetSize() - original_size < max_matches; + }); // Return the number of variable that were appended to the list const uint32_t num_matches = variables.GetSize() - original_size; @@ -2169,7 +2154,7 @@ void SymbolFileDWARF::FindGlobalVariables( log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " "parent_decl_ctx=%p, max_matches=%u, variables) => %u", - name.GetCString(), static_cast<const void *>(parent_decl_ctx), + name.GetCString(), static_cast<const void *>(&parent_decl_ctx), max_matches, num_matches); } } @@ -2188,41 +2173,24 @@ void SymbolFileDWARF::FindGlobalVariables(const RegularExpression ®ex, regex.GetText().str().c_str(), max_matches); } - DWARFDebugInfo *info = DebugInfo(); - if (!info) - return; - // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); - DIEArray die_offsets; - m_index->GetGlobalVariables(regex, die_offsets); - SymbolContext sc; - sc.module_sp = m_objfile_sp->GetModule(); - assert(sc.module_sp); - - const size_t num_matches = die_offsets.size(); - if (num_matches) { - for (size_t i = 0; i < num_matches; ++i) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = GetDIE(die_ref); + m_index->GetGlobalVariables(regex, [&](DWARFDIE die) { + if (!sc.module_sp) + sc.module_sp = m_objfile_sp->GetModule(); + assert(sc.module_sp); - if (die) { - DWARFCompileUnit *dwarf_cu = - llvm::dyn_cast<DWARFCompileUnit>(die.GetCU()); - if (!dwarf_cu) - continue; - sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu); + DWARFCompileUnit *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU()); + if (!dwarf_cu) + return true; + sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu); - ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables); + ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables); - if (variables.GetSize() - original_size >= max_matches) - break; - } else - m_index->ReportInvalidDIERef(die_ref, regex.GetText()); - } - } + return variables.GetSize() - original_size < max_matches; + }); } bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, @@ -2281,28 +2249,26 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } -bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext *decl_ctx, +bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx, const DWARFDIE &die) { // If we have no parent decl context to match this DIE matches, and if the // parent decl context isn't valid, we aren't trying to look for any // particular decl context so any die matches. - if (decl_ctx == nullptr || !decl_ctx->IsValid()) + if (!decl_ctx.IsValid()) return true; if (die) { - DWARFASTParser *dwarf_ast = die.GetDWARFParser(); - if (dwarf_ast) { - CompilerDeclContext actual_decl_ctx = - dwarf_ast->GetDeclContextContainingUIDFromDWARF(die); - if (actual_decl_ctx) - return decl_ctx->IsContainedInLookup(actual_decl_ctx); + if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) { + if (CompilerDeclContext actual_decl_ctx = + dwarf_ast->GetDeclContextContainingUIDFromDWARF(die)) + return decl_ctx.IsContainedInLookup(actual_decl_ctx); } } return false; } void SymbolFileDWARF::FindFunctions(ConstString name, - const CompilerDeclContext *parent_decl_ctx, + const CompilerDeclContext &parent_decl_ctx, FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) { @@ -2337,17 +2303,13 @@ void SymbolFileDWARF::FindFunctions(ConstString name, const uint32_t original_size = sc_list.GetSize(); llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies; - DIEArray offsets; - CompilerDeclContext empty_decl_ctx; - if (!parent_decl_ctx) - parent_decl_ctx = &empty_decl_ctx; - - std::vector<DWARFDIE> dies; - m_index->GetFunctions(name, *this, *parent_decl_ctx, name_type_mask, dies); - for (const DWARFDIE &die : dies) { - if (resolved_dies.insert(die.GetDIE()).second) - ResolveFunction(die, include_inlines, sc_list); - } + + m_index->GetFunctions(name, *this, parent_decl_ctx, name_type_mask, + [&](DWARFDIE die) { + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); + return true; + }); // Return the number of variable that were appended to the list const uint32_t num_matches = sc_list.GetSize() - original_size; @@ -2378,35 +2340,21 @@ void SymbolFileDWARF::FindFunctions(const RegularExpression ®ex, regex.GetText().str().c_str()); } - DWARFDebugInfo *info = DebugInfo(); - if (!info) - return; - - DIEArray offsets; - m_index->GetFunctions(regex, offsets); - llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies; - for (DIERef ref : offsets) { - DWARFDIE die = info->GetDIE(ref); - if (!die) { - m_index->ReportInvalidDIERef(ref, regex.GetText()); - continue; - } + m_index->GetFunctions(regex, [&](DWARFDIE die) { if (resolved_dies.insert(die.GetDIE()).second) ResolveFunction(die, include_inlines, sc_list); - } + return true; + }); } void SymbolFileDWARF::GetMangledNamesForFunction( const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names) { - DWARFDebugInfo *info = DebugInfo(); - uint32_t num_comp_units = 0; - if (info) - num_comp_units = info->GetNumUnits(); - + DWARFDebugInfo &info = DebugInfo(); + uint32_t num_comp_units = info.GetNumUnits(); for (uint32_t i = 0; i < num_comp_units; i++) { - DWARFUnit *cu = info->GetUnitAtIndex(i); + DWARFUnit *cu = info.GetUnitAtIndex(i); if (cu == nullptr) continue; @@ -2415,15 +2363,15 @@ void SymbolFileDWARF::GetMangledNamesForFunction( dwo->GetMangledNamesForFunction(scope_qualified_name, mangled_names); } - for (lldb::user_id_t uid : + for (DIERef die_ref : m_function_scope_qualified_name_map.lookup(scope_qualified_name)) { - DWARFDIE die = GetDIE(uid); + DWARFDIE die = GetDIE(die_ref); mangled_names.push_back(ConstString(die.GetMangledName())); } } void SymbolFileDWARF::FindTypes( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { @@ -2432,10 +2380,6 @@ void SymbolFileDWARF::FindTypes( if (!searched_symbol_files.insert(this).second) return; - DWARFDebugInfo *info = DebugInfo(); - if (!info) - return; - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) { @@ -2444,8 +2388,8 @@ void SymbolFileDWARF::FindTypes( log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx = " "%p (\"%s\"), max_matches=%u, type_list)", - name.GetCString(), static_cast<const void *>(parent_decl_ctx), - parent_decl_ctx->GetName().AsCString("<NULL>"), max_matches); + name.GetCString(), static_cast<const void *>(&parent_decl_ctx), + parent_decl_ctx.GetName().AsCString("<NULL>"), max_matches); else GetObjectFile()->GetModule()->LogMessage( log, @@ -2457,38 +2401,28 @@ void SymbolFileDWARF::FindTypes( if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) return; - DIEArray die_offsets; - m_index->GetTypes(name, die_offsets); - const size_t num_die_matches = die_offsets.size(); + m_index->GetTypes(name, [&](DWARFDIE die) { + if (!DIEInDeclContext(parent_decl_ctx, die)) + return true; // The containing decl contexts don't match - for (size_t i = 0; i < num_die_matches; ++i) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = GetDIE(die_ref); - if (die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - Type *matching_type = ResolveType(die, true, true); - if (matching_type) { - // We found a type pointer, now find the shared pointer form our type - // list - types.InsertUnique(matching_type->shared_from_this()); - if (types.GetSize() >= max_matches) - break; - } - } else { - m_index->ReportInvalidDIERef(die_ref, name.GetStringRef()); - } - } + Type *matching_type = ResolveType(die, true, true); + if (!matching_type) + return true; + + // 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; + }); // Next search through the reachable Clang modules. This only applies for // DWARF objects compiled with -gmodules that haven't been processed by // dsymutil. - if (num_die_matches < max_matches) { + if (types.GetSize() < max_matches) { UpdateExternalModuleListIfNeeded(); for (const auto &pair : m_external_type_modules) - if (ModuleSP external_module_sp = pair.second) + 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); @@ -2500,8 +2434,8 @@ void SymbolFileDWARF::FindTypes( log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx " "= %p (\"%s\"), max_matches=%u, type_list) => %u", - name.GetCString(), static_cast<const void *>(parent_decl_ctx), - parent_decl_ctx->GetName().AsCString("<NULL>"), max_matches, + name.GetCString(), static_cast<const void *>(&parent_decl_ctx), + parent_decl_ctx.GetName().AsCString("<NULL>"), max_matches, types.GetSize()); } else { GetObjectFile()->GetModule()->LogMessage( @@ -2529,32 +2463,22 @@ void SymbolFileDWARF::FindTypes( if (!name) return; - DIEArray die_offsets; - m_index->GetTypes(name, die_offsets); - const size_t num_die_matches = die_offsets.size(); - - for (size_t i = 0; i < num_die_matches; ++i) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = GetDIE(die_ref); - - if (!die) { - m_index->ReportInvalidDIERef(die_ref, name.GetStringRef()); - continue; - } - if (!languages[die.GetCU()->GetLanguageType()]) - continue; + m_index->GetTypes(name, [&](DWARFDIE die) { + if (!languages[GetLanguage(*die.GetCU())]) + return true; llvm::SmallVector<CompilerContext, 4> die_context; die.GetDeclContext(die_context); if (!contextMatches(die_context, pattern)) - continue; + 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 @@ -2569,7 +2493,7 @@ void SymbolFileDWARF::FindTypes( CompilerDeclContext SymbolFileDWARF::FindNamespace(ConstString name, - const CompilerDeclContext *parent_decl_ctx) { + const CompilerDeclContext &parent_decl_ctx) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); @@ -2584,32 +2508,18 @@ SymbolFileDWARF::FindNamespace(ConstString name, if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) return namespace_decl_ctx; - DWARFDebugInfo *info = DebugInfo(); - if (info) { - DIEArray die_offsets; - m_index->GetNamespaces(name, die_offsets); - const size_t num_matches = die_offsets.size(); - if (num_matches) { - for (size_t i = 0; i < num_matches; ++i) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = GetDIE(die_ref); - - if (die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - DWARFASTParser *dwarf_ast = die.GetDWARFParser(); - if (dwarf_ast) { - namespace_decl_ctx = dwarf_ast->GetDeclContextForUIDFromDWARF(die); - if (namespace_decl_ctx) - break; - } - } else { - m_index->ReportInvalidDIERef(die_ref, name.GetStringRef()); - } - } - } - } + m_index->GetNamespaces(name, [&](DWARFDIE die) { + if (!DIEInDeclContext(parent_decl_ctx, die)) + return true; // The containing decl contexts don't match + + DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU()); + if (!dwarf_ast) + return true; + + namespace_decl_ctx = dwarf_ast->GetDeclContextForUIDFromDWARF(die); + return !namespace_decl_ctx.IsValid(); + }); + if (log && namespace_decl_ctx) { GetObjectFile()->GetModule()->LogMessage( log, @@ -2735,10 +2645,10 @@ bool SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type(DWARFUnit *cu) { if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type()) m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; else { - DWARFDebugInfo *debug_info = DebugInfo(); + DWARFDebugInfo &debug_info = DebugInfo(); const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFUnit *dwarf_cu = debug_info->GetUnitAtIndex(cu_idx); + DWARFUnit *dwarf_cu = debug_info.GetUnitAtIndex(cu_idx); if (dwarf_cu != cu && dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type()) { m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; @@ -2763,17 +2673,8 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( if (!type_name || (must_be_implementation && !GetObjCClassSymbol(type_name))) return type_sp; - DIEArray die_offsets; - m_index->GetCompleteObjCClass(type_name, must_be_implementation, die_offsets); - - const size_t num_matches = die_offsets.size(); - - if (num_matches) { - for (size_t i = 0; i < num_matches; ++i) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE type_die = GetDIE(die_ref); - - if (type_die) { + 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 @@ -2788,35 +2689,32 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( break; } } + if (!try_resolving_type) + return true; - if (try_resolving_type) { - if (must_be_implementation && - type_die.Supports_DW_AT_APPLE_objc_complete_type()) - try_resolving_type = type_die.GetAttributeValueAsUnsigned( - DW_AT_APPLE_objc_complete_type, 0); - - if (try_resolving_type) { - Type *resolved_type = ResolveType(type_die, false, true); - if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) { - DEBUG_PRINTF("resolved 0x%8.8" PRIx64 " from %s to 0x%8.8" PRIx64 - " (cu 0x%8.8" PRIx64 ")\n", - die.GetID(), - m_objfile_sp->GetFileSpec().GetFilename().AsCString( - "<Unknown>"), - type_die.GetID(), type_cu->GetID()); - - if (die) - GetDIEToType()[die.GetDIE()] = resolved_type; - type_sp = resolved_type->shared_from_this(); - break; - } - } - } - } else { - m_index->ReportInvalidDIERef(die_ref, type_name.GetStringRef()); - } - } - } + if (must_be_implementation && + type_die.Supports_DW_AT_APPLE_objc_complete_type()) + try_resolving_type = type_die.GetAttributeValueAsUnsigned( + DW_AT_APPLE_objc_complete_type, 0); + if (!try_resolving_type) + return true; + + Type *resolved_type = ResolveType(type_die, false, true); + if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED) + return true; + + DEBUG_PRINTF( + "resolved 0x%8.8" PRIx64 " from %s to 0x%8.8" PRIx64 + " (cu 0x%8.8" PRIx64 ")\n", + die.GetID(), + m_objfile_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"), + type_die.GetID(), type_cu->GetID()); + + if (die) + GetDIEToType()[die.GetDIE()] = resolved_type; + type_sp = resolved_type->shared_from_this(); + return false; + }); return type_sp; } @@ -2930,10 +2828,6 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( dwarf_decl_ctx.GetQualifiedName()); } - DIEArray die_offsets; - m_index->GetTypes(dwarf_decl_ctx, die_offsets); - const size_t num_matches = die_offsets.size(); - // Get the type system that we are looking to find a type for. We will // use this to ensure any matches we find are in a language that this // type system supports @@ -2950,91 +2844,85 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( type_system = &type_system_or_err.get(); } } - if (num_matches) { - for (size_t i = 0; i < num_matches; ++i) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE type_die = GetDIE(die_ref); - - if (type_die) { - // Make sure type_die's langauge 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(type_die.GetLanguage())) - continue; - 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; - } - } - if (try_resolving_type) { - DWARFDeclContext type_dwarf_decl_ctx; - type_die.GetDWARFDeclContext(type_dwarf_decl_ctx); - - if (log) { - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::" - "FindDefinitionTypeForDWARFDeclContext(tag=%s, " - "qualified-name='%s') trying die=0x%8.8x (%s)", - DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), - dwarf_decl_ctx.GetQualifiedName(), type_die.GetOffset(), - type_dwarf_decl_ctx.GetQualifiedName()); - } + m_index->GetTypes(dwarf_decl_ctx, [&](DWARFDIE type_die) { + // Make sure type_die's langauge 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; - // Make sure the decl contexts match all the way up - if (dwarf_decl_ctx == type_dwarf_decl_ctx) { - Type *resolved_type = ResolveType(type_die, false); - if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) { - type_sp = resolved_type->shared_from_this(); - break; - } - } - } else { - if (log) { - std::string qualified_name; - type_die.GetQualifiedName(qualified_name); - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::" - "FindDefinitionTypeForDWARFDeclContext(tag=%s, " - "qualified-name='%s') ignoring die=0x%8.8x (%s)", - DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), - dwarf_decl_ctx.GetQualifiedName(), type_die.GetOffset(), - qualified_name.c_str()); - } - } - } else { - m_index->ReportInvalidDIERef(die_ref, type_name.GetStringRef()); + // 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; } } - } + + if (!try_resolving_type) { + if (log) { + std::string qualified_name; + type_die.GetQualifiedName(qualified_name); + GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::" + "FindDefinitionTypeForDWARFDeclContext(tag=%s, " + "qualified-name='%s') ignoring die=0x%8.8x (%s)", + DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), + dwarf_decl_ctx.GetQualifiedName(), type_die.GetOffset(), + qualified_name.c_str()); + } + return true; + } + + DWARFDeclContext type_dwarf_decl_ctx = GetDWARFDeclContext(type_die); + + if (log) { + GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::" + "FindDefinitionTypeForDWARFDeclContext(tag=%s, " + "qualified-name='%s') trying die=0x%8.8x (%s)", + DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), + dwarf_decl_ctx.GetQualifiedName(), type_die.GetOffset(), + type_dwarf_decl_ctx.GetQualifiedName()); + } + + // Make sure the decl contexts match all the way up + if (dwarf_decl_ctx != type_dwarf_decl_ctx) + return true; + + Type *resolved_type = ResolveType(type_die, false); + if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED) + return true; + + type_sp = resolved_type->shared_from_this(); + return false; + }); } } return type_sp; @@ -3045,8 +2933,7 @@ TypeSP SymbolFileDWARF::ParseType(const SymbolContext &sc, const DWARFDIE &die, if (!die) return {}; - auto type_system_or_err = - GetTypeSystemForLanguage(die.GetCU()->GetLanguageType()); + auto type_system_or_err = GetTypeSystemForLanguage(GetLanguage(*die.GetCU())); if (auto err = type_system_or_err.takeError()) { LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS), std::move(err), "Unable to parse type"); @@ -3067,7 +2954,7 @@ TypeSP SymbolFileDWARF::ParseType(const SymbolContext &sc, const DWARFDIE &die, .AsCString("")); if (scope_qualified_name.size()) { m_function_scope_qualified_name_map[scope_qualified_name].insert( - die.GetID()); + *die.GetDIERef()); } } } @@ -3124,7 +3011,8 @@ size_t SymbolFileDWARF::ParseBlocksRecursive(Function &func) { size_t functions_added = 0; const dw_offset_t function_die_offset = func.GetID(); - DWARFDIE function_die = dwarf_cu->GetDIE(function_die_offset); + DWARFDIE function_die = + dwarf_cu->GetNonSkeletonUnit().GetDIE(function_die_offset); if (function_die) { ParseBlocksRecursive(*comp_unit, &func.GetBlock(false), function_die, LLDB_INVALID_ADDRESS, 0); @@ -3152,10 +3040,6 @@ size_t SymbolFileDWARF::ParseTypes(CompileUnit &comp_unit) { size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); if (sc.comp_unit != nullptr) { - DWARFDebugInfo *info = DebugInfo(); - if (info == nullptr) - return 0; - if (sc.function) { DWARFDIE function_die = GetDIE(sc.function->GetID()); @@ -3170,7 +3054,7 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { return num_variables; } } else if (sc.comp_unit) { - DWARFUnit *dwarf_cu = info->GetUnitAtIndex(sc.comp_unit->GetID()); + DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(sc.comp_unit->GetID()); if (dwarf_cu == nullptr) return 0; @@ -3182,25 +3066,16 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { variables = std::make_shared<VariableList>(); sc.comp_unit->SetVariableList(variables); - DIEArray die_offsets; - m_index->GetGlobalVariables(dwarf_cu->GetNonSkeletonUnit(), - die_offsets); - const size_t num_matches = die_offsets.size(); - if (num_matches) { - for (size_t i = 0; i < num_matches; ++i) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = GetDIE(die_ref); - if (die) { + m_index->GetGlobalVariables( + dwarf_cu->GetNonSkeletonUnit(), [&](DWARFDIE die) { VariableSP var_sp( ParseVariableDIE(sc, die, LLDB_INVALID_ADDRESS)); if (var_sp) { variables->AddVariableIfUnique(var_sp); ++vars_added; } - } else - m_index->ReportInvalidDIERef(die_ref, ""); - } - } + return true; + }); } return vars_added; } @@ -3412,12 +3287,10 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, // declaration context. if ((parent_tag == DW_TAG_compile_unit || parent_tag == DW_TAG_partial_unit) && - Language::LanguageIsCPlusPlus(die.GetLanguage())) { - DWARFDeclContext decl_ctx; - - die.GetDWARFDeclContext(decl_ctx); - mangled = decl_ctx.GetQualifiedNameAsConstString().GetCString(); - } + Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU()))) + mangled = GetDWARFDeclContext(die) + .GetQualifiedNameAsConstString() + .GetCString(); } if (tag == DW_TAG_formal_parameter) @@ -3524,7 +3397,8 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, } } } else { - if (location_is_const_value_data) + if (location_is_const_value_data && + die.GetDIE()->IsGlobalOrStaticScopeVariable()) scope = eValueTypeVariableStatic; else { scope = eValueTypeVariableLocal; @@ -3603,7 +3477,7 @@ SymbolFileDWARF::FindBlockContainingSpecification( // Give the concrete function die specified by "func_die_offset", find the // concrete block whose DW_AT_specification or DW_AT_abstract_origin points // to "spec_block_die_offset" - return FindBlockContainingSpecification(DebugInfo()->GetDIE(func_die_ref), + return FindBlockContainingSpecification(DebugInfo().GetDIE(func_die_ref), spec_block_die_offset); } @@ -3762,7 +3636,8 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { CallSiteParameterArray parameters; for (DWARFDIE child = call_site_die.GetFirstChild(); child.IsValid(); child = child.GetSibling()) { - if (child.Tag() != DW_TAG_call_site_parameter) + if (child.Tag() != DW_TAG_call_site_parameter && + child.Tag() != DW_TAG_GNU_call_site_parameter) continue; llvm::Optional<DWARFExpression> LocationInCallee; @@ -3792,7 +3667,7 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { dw_attr_t attr = attributes.AttributeAtIndex(i); if (attr == DW_AT_location) LocationInCallee = parse_simple_location(i); - if (attr == DW_AT_call_value) + if (attr == DW_AT_call_value || attr == DW_AT_GNU_call_site_value) LocationInCaller = parse_simple_location(i); } @@ -3805,12 +3680,13 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { } /// Collect call graph edges present in a function DIE. -static std::vector<std::unique_ptr<lldb_private::CallEdge>> -CollectCallEdges(ModuleSP module, DWARFDIE function_die) { +std::vector<std::unique_ptr<lldb_private::CallEdge>> +SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // Check if the function has a supported call site-related attribute. // TODO: In the future it may be worthwhile to support call_all_source_calls. - uint64_t has_call_edges = - function_die.GetAttributeValueAsUnsigned(DW_AT_call_all_calls, 0); + bool has_call_edges = + function_die.GetAttributeValueAsUnsigned(DW_AT_call_all_calls, 0) || + function_die.GetAttributeValueAsUnsigned(DW_AT_GNU_all_call_sites, 0); if (!has_call_edges) return {}; @@ -3826,15 +3702,22 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { std::vector<std::unique_ptr<CallEdge>> call_edges; for (DWARFDIE child = function_die.GetFirstChild(); child.IsValid(); child = child.GetSibling()) { - if (child.Tag() != DW_TAG_call_site) + if (child.Tag() != DW_TAG_call_site && child.Tag() != DW_TAG_GNU_call_site) continue; llvm::Optional<DWARFDIE> call_origin; llvm::Optional<DWARFExpression> call_target; addr_t return_pc = LLDB_INVALID_ADDRESS; + addr_t call_inst_pc = LLDB_INVALID_ADDRESS; + addr_t low_pc = LLDB_INVALID_ADDRESS; + bool tail_call = false; + // Second DW_AT_low_pc may come from DW_TAG_subprogram referenced by + // DW_TAG_GNU_call_site's DW_AT_abstract_origin overwriting our 'low_pc'. + // So do not inherit attributes from DW_AT_abstract_origin. DWARFAttributes attributes; - const size_t num_attributes = child.GetAttributes(attributes); + const size_t num_attributes = + child.GetAttributes(attributes, DWARFDIE::Recurse::no); for (size_t i = 0; i < num_attributes; ++i) { DWARFFormValue form_value; if (!attributes.ExtractFormValueAtIndex(i, form_value)) { @@ -3844,8 +3727,11 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { dw_attr_t attr = attributes.AttributeAtIndex(i); + if (attr == DW_AT_call_tail_call || attr == DW_AT_GNU_tail_call) + tail_call = form_value.Boolean(); + // Extract DW_AT_call_origin (the call target's DIE). - if (attr == DW_AT_call_origin) { + if (attr == DW_AT_call_origin || attr == DW_AT_abstract_origin) { call_origin = form_value.Reference(); if (!call_origin->IsValid()) { LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", @@ -3854,15 +3740,24 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { } } + if (attr == DW_AT_low_pc) + low_pc = form_value.Address(); + // Extract DW_AT_call_return_pc (the PC the call returns to) if it's // available. It should only ever be unavailable for tail call edges, in // which case use LLDB_INVALID_ADDRESS. if (attr == DW_AT_call_return_pc) return_pc = form_value.Address(); + // Extract DW_AT_call_pc (the PC at the call/branch instruction). It + // should only ever be unavailable for non-tail calls, in which case use + // LLDB_INVALID_ADDRESS. + if (attr == DW_AT_call_pc) + call_inst_pc = form_value.Address(); + // Extract DW_AT_call_target (the location of the address of the indirect // call). - if (attr == DW_AT_call_target) { + if (attr == DW_AT_call_target || attr == DW_AT_GNU_call_site_target) { if (!DWARFFormValue::IsBlockForm(form_value.Form())) { LLDB_LOG(log, "CollectCallEdges: AT_call_target does not have block form"); @@ -3882,16 +3777,39 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { continue; } + addr_t caller_address; + CallEdge::AddrType caller_address_type; + if (return_pc != LLDB_INVALID_ADDRESS) { + caller_address = return_pc; + caller_address_type = CallEdge::AddrType::AfterCall; + } else if (low_pc != LLDB_INVALID_ADDRESS) { + caller_address = low_pc; + caller_address_type = CallEdge::AddrType::AfterCall; + } else if (call_inst_pc != LLDB_INVALID_ADDRESS) { + caller_address = call_inst_pc; + caller_address_type = CallEdge::AddrType::Call; + } else { + LLDB_LOG(log, "CollectCallEdges: No caller address"); + continue; + } + // Adjust any PC forms. It needs to be fixed up if the main executable + // contains a debug map (i.e. pointers to object files), because we need a + // file address relative to the executable's text section. + caller_address = FixupAddress(caller_address); + // Extract call site parameters. CallSiteParameterArray parameters = CollectCallSiteParameters(module, child); std::unique_ptr<CallEdge> edge; if (call_origin) { - LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", - call_origin->GetPubname(), return_pc); - edge = std::make_unique<DirectCallEdge>(call_origin->GetMangledName(), - return_pc, std::move(parameters)); + LLDB_LOG(log, + "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x}) " + "(call-PC: {2:x})", + call_origin->GetPubname(), return_pc, call_inst_pc); + edge = std::make_unique<DirectCallEdge>( + call_origin->GetMangledName(), caller_address_type, caller_address, + tail_call, std::move(parameters)); } else { if (log) { StreamString call_target_desc; @@ -3900,8 +3818,9 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}", call_target_desc.GetString()); } - edge = std::make_unique<IndirectCallEdge>(*call_target, return_pc, - std::move(parameters)); + edge = std::make_unique<IndirectCallEdge>( + *call_target, caller_address_type, caller_address, tail_call, + std::move(parameters)); } if (log && parameters.size()) { @@ -3925,6 +3844,11 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { std::vector<std::unique_ptr<lldb_private::CallEdge>> SymbolFileDWARF::ParseCallEdgesInFunction(UserID func_id) { + // ParseCallEdgesInFunction must be called at the behest of an exclusively + // locked lldb::Function instance. Storage for parsed call edges is owned by + // the lldb::Function instance: locking at the SymbolFile level would be too + // late, because the act of storing results from ParseCallEdgesInFunction + // would be racy. DWARFDIE func_die = GetDIE(func_id.GetID()); if (func_die.IsValid()) return CollectCallEdges(GetObjectFile()->GetModule(), func_die); @@ -3945,8 +3869,8 @@ void SymbolFileDWARF::DumpClangAST(Stream &s) { auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus); if (!ts_or_err) return; - ClangASTContext *clang = - llvm::dyn_cast_or_null<ClangASTContext>(&ts_or_err.get()); + TypeSystemClang *clang = + llvm::dyn_cast_or_null<TypeSystemClang>(&ts_or_err.get()); if (!clang) return; clang->Dump(s); @@ -3957,26 +3881,93 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { lldb::ModuleSP module_sp(m_debug_map_module_wp.lock()); if (module_sp) { m_debug_map_symfile = - (SymbolFileDWARFDebugMap *)module_sp->GetSymbolFile(); + static_cast<SymbolFileDWARFDebugMap *>(module_sp->GetSymbolFile()); } } return m_debug_map_symfile; } -SymbolFileDWARFDwp *SymbolFileDWARF::GetDwpSymbolFile() { +const std::shared_ptr<SymbolFileDWARFDwo> &SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { ModuleSpec module_spec; module_spec.GetFileSpec() = m_objfile_sp->GetFileSpec(); module_spec.GetSymbolFileSpec() = - FileSpec(m_objfile_sp->GetFileSpec().GetPath() + ".dwp"); + FileSpec(m_objfile_sp->GetModule()->GetFileSpec().GetPath() + ".dwp"); FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); FileSpec dwp_filespec = Symbols::LocateExecutableSymbolFile(module_spec, search_paths); if (FileSystem::Instance().Exists(dwp_filespec)) { - m_dwp_symfile = SymbolFileDWARFDwp::Create(GetObjectFile()->GetModule(), - dwp_filespec); + DataBufferSP dwp_file_data_sp; + lldb::offset_t dwp_file_data_offset = 0; + ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin( + GetObjectFile()->GetModule(), &dwp_filespec, 0, + FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp, + dwp_file_data_offset); + if (!dwp_obj_file) + return; + m_dwp_symfile = + std::make_shared<SymbolFileDWARFDwo>(*this, dwp_obj_file, 0x3fffffff); } }); - return m_dwp_symfile.get(); + return m_dwp_symfile; +} + +llvm::Expected<TypeSystem &> SymbolFileDWARF::GetTypeSystem(DWARFUnit &unit) { + return unit.GetSymbolFileDWARF().GetTypeSystemForLanguage(GetLanguage(unit)); +} + +DWARFASTParser *SymbolFileDWARF::GetDWARFParser(DWARFUnit &unit) { + auto type_system_or_err = GetTypeSystem(unit); + if (auto err = type_system_or_err.takeError()) { + LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS), + std::move(err), "Unable to get DWARFASTParser"); + return nullptr; + } + return type_system_or_err->GetDWARFParser(); +} + +CompilerDecl SymbolFileDWARF::GetDecl(const DWARFDIE &die) { + if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) + return dwarf_ast->GetDeclForUIDFromDWARF(die); + return CompilerDecl(); +} + +CompilerDeclContext SymbolFileDWARF::GetDeclContext(const DWARFDIE &die) { + if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) + return dwarf_ast->GetDeclContextForUIDFromDWARF(die); + return CompilerDeclContext(); +} + +CompilerDeclContext +SymbolFileDWARF::GetContainingDeclContext(const DWARFDIE &die) { + if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) + return dwarf_ast->GetDeclContextContainingUIDFromDWARF(die); + return CompilerDeclContext(); +} + +DWARFDeclContext SymbolFileDWARF::GetDWARFDeclContext(const DWARFDIE &die) { + if (!die.IsValid()) + return {}; + DWARFDeclContext dwarf_decl_ctx = + die.GetDIE()->GetDWARFDeclContext(die.GetCU()); + dwarf_decl_ctx.SetLanguage(GetLanguage(*die.GetCU())); + return dwarf_decl_ctx; +} + +LanguageType SymbolFileDWARF::LanguageTypeFromDWARF(uint64_t val) { + // Note: user languages between lo_user and hi_user must be handled + // explicitly here. + switch (val) { + case DW_LANG_Mips_Assembler: + return eLanguageTypeMipsAssembler; + case DW_LANG_GOOGLE_RenderScript: + return eLanguageTypeExtRenderScript; + default: + return static_cast<LanguageType>(val); + } +} + +LanguageType SymbolFileDWARF::GetLanguage(DWARFUnit &unit) { + return LanguageTypeFromDWARF(unit.GetDWARFLanguageType()); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 23e26732453f..76ceb279c718 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -6,17 +6,17 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_SymbolFileDWARF_h_ -#define SymbolFileDWARF_SymbolFileDWARF_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARF_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARF_H #include <list> #include <map> #include <mutex> -#include <set> #include <unordered_map> #include <vector> #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Support/Threading.h" #include "lldb/Core/UniqueCStringMap.h" @@ -90,8 +90,6 @@ public: static lldb_private::SymbolFile * CreateInstance(lldb::ObjectFileSP objfile_sp); - static lldb_private::FileSpecList GetSymlinkPaths(); - // Constructors and Destructors SymbolFileDWARF(lldb::ObjectFileSP objfile_sp, @@ -108,6 +106,9 @@ public: lldb::LanguageType ParseLanguage(lldb_private::CompileUnit &comp_unit) override; + lldb_private::XcodeSDK + ParseXcodeSDK(lldb_private::CompileUnit &comp_unit) override; + size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override; bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override; @@ -168,7 +169,7 @@ public: void FindGlobalVariables(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, lldb_private::VariableList &variables) override; @@ -177,7 +178,7 @@ public: lldb_private::VariableList &variables) override; void FindFunctions(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, lldb::FunctionNameType name_type_mask, bool include_inlines, lldb_private::SymbolContextList &sc_list) override; @@ -192,7 +193,7 @@ public: void FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; @@ -211,7 +212,7 @@ public: lldb_private::CompilerDeclContext FindNamespace( lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx) override; + const lldb_private::CompilerDeclContext &parent_decl_ctx) override; void PreloadSymbols() override; @@ -224,11 +225,7 @@ public: DWARFDebugAbbrev *DebugAbbrev(); - const DWARFDebugAbbrev *DebugAbbrev() const; - - DWARFDebugInfo *DebugInfo(); - - const DWARFDebugInfo *DebugInfo() const; + DWARFDebugInfo &DebugInfo(); DWARFDebugRanges *GetDebugRanges(); @@ -243,8 +240,8 @@ public: lldb_private::CompileUnit * GetCompUnitForDWARFCompUnit(DWARFCompileUnit &dwarf_cu); - virtual size_t GetObjCMethodDIEOffsets(lldb_private::ConstString class_name, - DIEArray &method_die_offsets); + virtual void GetObjCMethods(lldb_private::ConstString class_name, + llvm::function_ref<bool(DWARFDIE die)> callback); bool Supports_DW_AT_APPLE_objc_complete_type(DWARFUnit *cu); @@ -252,8 +249,6 @@ public: static DWARFDIE GetParentSymbolContextDIE(const DWARFDIE &die); - virtual lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu); - lldb::ModuleSP GetExternalModule(lldb_private::ConstString name); typedef std::map<lldb_private::ConstString, lldb::ModuleSP> @@ -278,22 +273,17 @@ public: lldb::user_id_t GetUID(DIERef ref); - std::unique_ptr<SymbolFileDWARFDwo> + std::shared_ptr<SymbolFileDWARFDwo> GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die); - // For regular SymbolFileDWARF instances the method returns nullptr, - // for the instances of the subclass SymbolFileDWARFDwo - // the method returns a pointer to the base compile unit. - virtual DWARFCompileUnit *GetBaseCompileUnit() { return nullptr; } - virtual llvm::Optional<uint32_t> GetDwoNum() { return llvm::None; } /// If this is a DWARF object with a single CU, return its DW_AT_dwo_id. llvm::Optional<uint64_t> GetDWOId(); static bool - DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, + DIEInDeclContext(const lldb_private::CompilerDeclContext &parent_decl_ctx, const DWARFDIE &die); std::vector<std::unique_ptr<lldb_private::CallEdge>> @@ -305,8 +295,30 @@ public: lldb_private::DWARFContext &GetDWARFContext() { return m_context; } + const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile(); + lldb_private::FileSpec GetFile(DWARFUnit &unit, size_t file_idx); + static llvm::Expected<lldb_private::TypeSystem &> + GetTypeSystem(DWARFUnit &unit); + + static DWARFASTParser *GetDWARFParser(DWARFUnit &unit); + + // CompilerDecl related functions + + static lldb_private::CompilerDecl GetDecl(const DWARFDIE &die); + + static lldb_private::CompilerDeclContext GetDeclContext(const DWARFDIE &die); + + static lldb_private::CompilerDeclContext + GetContainingDeclContext(const DWARFDIE &die); + + static DWARFDeclContext GetDWARFDeclContext(const DWARFDIE &die); + + static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); + + static lldb::LanguageType GetLanguage(DWARFUnit &unit); + protected: typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> DIEToTypePtr; @@ -315,25 +327,16 @@ protected: typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::opaque_compiler_type_t> DIEToClangType; - typedef llvm::DenseMap<lldb::opaque_compiler_type_t, lldb::user_id_t> - ClangTypeToDIE; + typedef llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> ClangTypeToDIE; - struct DWARFDataSegment { - llvm::once_flag m_flag; - lldb_private::DWARFDataExtractor m_data; - }; - - DISALLOW_COPY_AND_ASSIGN(SymbolFileDWARF); - - const lldb_private::DWARFDataExtractor & - GetCachedSectionData(lldb::SectionType sect_type, - DWARFDataSegment &data_segment); + SymbolFileDWARF(const SymbolFileDWARF &) = delete; + const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete; virtual void LoadSectionData(lldb::SectionType sect_type, lldb_private::DWARFDataExtractor &data); bool DeclContextMatchesThisSymbolFile( - const lldb_private::CompilerDeclContext *decl_ctx); + const lldb_private::CompilerDeclContext &decl_ctx); uint32_t CalculateNumCompileUnits() override; @@ -341,6 +344,8 @@ protected: lldb_private::TypeList &GetTypeList() override; + lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu); + virtual DWARFUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit); @@ -383,6 +388,13 @@ protected: bool ResolveFunction(const DWARFDIE &die, bool include_inlines, lldb_private::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); + virtual lldb::TypeSP FindDefinitionTypeForDWARFDeclContext(const DWARFDeclContext &die_decl_ctx); @@ -417,9 +429,21 @@ protected: bool ClassContainsSelector(const DWARFDIE &class_die, lldb_private::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>> + CollectCallEdges(lldb::ModuleSP module, DWARFDIE function_die); + + /// If this symbol file is linked to by a debug map (see + /// SymbolFileDWARFDebugMap), and \p file_addr is a file address relative to + /// an object file, adjust \p file_addr so that it is relative to the main + /// binary. Returns the adjusted address, or \p file_addr if no adjustment is + /// needed, on success and LLDB_INVALID_ADDRESS otherwise. + lldb::addr_t FixupAddress(lldb::addr_t file_addr); + bool FixupAddress(lldb_private::Address &addr); - typedef std::set<lldb_private::Type *> TypeSet; + typedef llvm::SetVector<lldb_private::Type *> TypeSet; void GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset, dw_offset_t max_die_offset, uint32_t type_mask, @@ -454,7 +478,7 @@ protected: }; llvm::Optional<DecodedUID> DecodeUID(lldb::user_id_t uid); - SymbolFileDWARFDwp *GetDwpSymbolFile(); + void FindDwpSymbolFile(); const lldb_private::FileSpecList &GetTypeUnitSupportFiles(DWARFTypeUnit &tu); @@ -462,17 +486,14 @@ protected: SymbolFileDWARFDebugMap *m_debug_map_symfile; llvm::once_flag m_dwp_symfile_once_flag; - std::unique_ptr<SymbolFileDWARFDwp> m_dwp_symfile; + std::shared_ptr<SymbolFileDWARFDwo> m_dwp_symfile; lldb_private::DWARFContext m_context; - DWARFDataSegment m_data_debug_loc; - DWARFDataSegment m_data_debug_loclists; + llvm::once_flag m_info_once_flag; + std::unique_ptr<DWARFDebugInfo> m_info; - // The unique pointer items below are generated on demand if and when someone - // accesses them through a non const version of this class. std::unique_ptr<DWARFDebugAbbrev> m_abbr; - std::unique_ptr<DWARFDebugInfo> m_info; std::unique_ptr<GlobalVariableMap> m_global_aranges_up; typedef std::unordered_map<lldb::offset_t, lldb_private::DebugMacrosSP> @@ -484,7 +505,7 @@ protected: bool m_fetched_external_modules : 1; lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; - typedef std::set<lldb::user_id_t> DIERefSet; + typedef std::set<DIERef> DIERefSet; typedef llvm::StringMap<DIERefSet> NameToOffsetMap; NameToOffsetMap m_function_scope_qualified_name_map; std::unique_ptr<DWARFDebugRanges> m_ranges; @@ -498,4 +519,4 @@ protected: std::vector<uint32_t> m_lldb_cu_to_dwarf_unit; }; -#endif // SymbolFileDWARF_SymbolFileDWARF_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARF_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index cce666a222d0..6515d78b8f23 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -1,4 +1,4 @@ -//===-- SymbolFileDWARFDebugMap.cpp -----------------------------*- C++ -*-===// +//===-- SymbolFileDWARFDebugMap.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -108,8 +108,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( // First we find the original symbol in the .o file's symbol table Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType( - exe_symbol->GetMangled().GetName(lldb::eLanguageTypeUnknown, - Mangled::ePreferMangled), + exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), eSymbolTypeCode, Symtab::eDebugNo, Symtab::eVisibilityAny); if (oso_fun_symbol) { // Add the inverse OSO file address to debug map entry mapping @@ -139,8 +138,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( // in the .o file Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType( - exe_symbol->GetMangled().GetName(lldb::eLanguageTypeUnknown, - Mangled::ePreferMangled), + exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), eSymbolTypeData, Symtab::eDebugNo, Symtab::eVisibilityAny); if (exe_symbol && oso_gsym_symbol && exe_symbol->ValueIsAddress() && oso_gsym_symbol->ValueIsAddress()) { @@ -416,6 +414,7 @@ Module *SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo( FileSpec oso_file(oso_path); ConstString oso_object; if (FileSystem::Instance().Exists(oso_file)) { + FileSystem::Instance().Collect(oso_file); // The modification time returned by the FS can have a higher precision // than the one from the CU. auto oso_mod_time = std::chrono::time_point_cast<std::chrono::seconds>( @@ -531,7 +530,7 @@ SymbolFileDWARF * SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF(SymbolFile *sym_file) { if (sym_file && sym_file->GetPluginName() == SymbolFileDWARF::GetPluginNameStatic()) - return (SymbolFileDWARF *)sym_file; + return static_cast<SymbolFileDWARF *>(sym_file); return nullptr; } @@ -630,6 +629,14 @@ SymbolFileDWARFDebugMap::ParseLanguage(CompileUnit &comp_unit) { return eLanguageTypeUnknown; } +XcodeSDK SymbolFileDWARFDebugMap::ParseXcodeSDK(CompileUnit &comp_unit) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); + if (oso_dwarf) + return oso_dwarf->ParseXcodeSDK(comp_unit); + return {}; +} + size_t SymbolFileDWARFDebugMap::ParseFunctions(CompileUnit &comp_unit) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); @@ -826,7 +833,7 @@ uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( } void SymbolFileDWARFDebugMap::PrivateFindGlobalVariables( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, const std::vector<uint32_t> &indexes, // Indexes into the symbol table that match "name" uint32_t max_matches, VariableList &variables) { @@ -848,7 +855,7 @@ void SymbolFileDWARFDebugMap::PrivateFindGlobalVariables( } void SymbolFileDWARFDebugMap::FindGlobalVariables( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, VariableList &variables) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); uint32_t total_matches = 0; @@ -1002,7 +1009,7 @@ static void RemoveFunctionsWithModuleNotEqualTo(const ModuleSP &module_sp, } void SymbolFileDWARFDebugMap::FindFunctions( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); @@ -1172,7 +1179,7 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( } void SymbolFileDWARFDebugMap::FindTypes( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { @@ -1209,7 +1216,7 @@ void SymbolFileDWARFDebugMap::FindTypes( CompilerDeclContext SymbolFileDWARFDebugMap::FindNamespace( lldb_private::ConstString name, - const CompilerDeclContext *parent_decl_ctx) { + const CompilerDeclContext &parent_decl_ctx) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); CompilerDeclContext matching_namespace; @@ -1225,6 +1232,9 @@ CompilerDeclContext SymbolFileDWARFDebugMap::FindNamespace( void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s) { ForEachSymbolFile([&s](SymbolFileDWARF *oso_dwarf) -> bool { oso_dwarf->DumpClangAST(s); + // The underlying assumption is that DumpClangAST(...) will obtain the + // AST from the underlying TypeSystem and therefore we only need to do + // this once and can stop after the first iteration hence we return true. return true; }); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 035a902498be..06f0d48c04ca 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARF_SymbolFileDWARFDebugMap_h_ -#define SymbolFileDWARF_SymbolFileDWARFDebugMap_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H #include "lldb/Symbol/SymbolFile.h" #include "lldb/Utility/RangeMap.h" @@ -57,11 +57,10 @@ public: // Compile Unit function calls lldb::LanguageType ParseLanguage(lldb_private::CompileUnit &comp_unit) override; - + lldb_private::XcodeSDK + ParseXcodeSDK(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( @@ -105,14 +104,14 @@ public: lldb_private::SymbolContextList &sc_list) override; void FindGlobalVariables(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, lldb_private::VariableList &variables) override; void FindGlobalVariables(const lldb_private::RegularExpression ®ex, uint32_t max_matches, lldb_private::VariableList &variables) override; void FindFunctions(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, lldb::FunctionNameType name_type_mask, bool include_inlines, lldb_private::SymbolContextList &sc_list) override; @@ -121,7 +120,7 @@ public: lldb_private::SymbolContextList &sc_list) override; void FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; @@ -132,7 +131,7 @@ public: lldb_private::TypeMap &types) override; lldb_private::CompilerDeclContext FindNamespace( lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx) override; + const lldb_private::CompilerDeclContext &parent_decl_ctx) override; void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override; @@ -254,7 +253,7 @@ protected: void PrivateFindGlobalVariables( lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, const std::vector<uint32_t> &name_symbol_indexes, uint32_t max_matches, lldb_private::VariableList &variables); @@ -379,4 +378,4 @@ protected: DWARFDebugAranges *debug_aranges); }; -#endif // #ifndef SymbolFileDWARF_SymbolFileDWARFDebugMap_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index f75f06f31e2d..3aaa7d330b84 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -1,4 +1,4 @@ -//===-- SymbolFileDWARFDwo.cpp ----------------------------------*- C++ -*-===// +//===-- SymbolFileDWARFDwo.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -23,62 +23,52 @@ using namespace lldb_private; char SymbolFileDWARFDwo::ID; -SymbolFileDWARFDwo::SymbolFileDWARFDwo(ObjectFileSP objfile, - DWARFCompileUnit &dwarf_cu) +SymbolFileDWARFDwo::SymbolFileDWARFDwo(SymbolFileDWARF &base_symbol_file, + ObjectFileSP objfile, uint32_t id) : SymbolFileDWARF(objfile, objfile->GetSectionList( /*update_module_section_list*/ false)), - m_base_dwarf_cu(dwarf_cu) { - SetID(((lldb::user_id_t)dwarf_cu.GetID()) << 32); -} - -void SymbolFileDWARFDwo::LoadSectionData(lldb::SectionType sect_type, - DWARFDataExtractor &data) { - const SectionList *section_list = - m_objfile_sp->GetSectionList(false /* update_module_section_list */); - if (section_list) { - SectionSP section_sp(section_list->FindSectionByType(sect_type, true)); - if (section_sp) { + m_base_symbol_file(base_symbol_file) { + SetID(user_id_t(id) << 32); - if (m_objfile_sp->ReadSectionData(section_sp.get(), data) != 0) - return; + // Parsing of the dwarf unit index is not thread-safe, so we need to prime it + // to enable subsequent concurrent lookups. + m_context.GetAsLLVM().getCUIndex(); +} - data.Clear(); +DWARFCompileUnit *SymbolFileDWARFDwo::GetDWOCompileUnitForHash(uint64_t hash) { + if (const llvm::DWARFUnitIndex &index = m_context.GetAsLLVM().getCUIndex()) { + if (const llvm::DWARFUnitIndex::Entry *entry = index.getFromHash(hash)) { + if (auto *unit_contrib = entry->getContribution()) + return llvm::dyn_cast_or_null<DWARFCompileUnit>( + DebugInfo().GetUnitAtOffset(DIERef::Section::DebugInfo, + unit_contrib->Offset)); } + return nullptr; } - SymbolFileDWARF::LoadSectionData(sect_type, data); -} - -lldb::CompUnitSP -SymbolFileDWARFDwo::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { - assert(GetCompileUnit() == &dwarf_cu && - "SymbolFileDWARFDwo::ParseCompileUnit called with incompatible " - "compile unit"); - return GetBaseSymbolFile().ParseCompileUnit(m_base_dwarf_cu); -} - -DWARFCompileUnit *SymbolFileDWARFDwo::GetCompileUnit() { - if (!m_cu) - m_cu = ComputeCompileUnit(); - return m_cu; + DWARFCompileUnit *cu = FindSingleCompileUnit(); + if (!cu) + return nullptr; + if (hash != + cu->GetUnitDIEOnly().GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0)) + return nullptr; + return cu; } -DWARFCompileUnit *SymbolFileDWARFDwo::ComputeCompileUnit() { - DWARFDebugInfo *debug_info = DebugInfo(); - if (!debug_info) - return nullptr; +DWARFCompileUnit *SymbolFileDWARFDwo::FindSingleCompileUnit() { + DWARFDebugInfo &debug_info = DebugInfo(); // Right now we only support dwo files with one compile unit. If we don't have // type units, we can just check for the unit count. - if (!debug_info->ContainsTypeUnits() && debug_info->GetNumUnits() == 1) - return llvm::cast<DWARFCompileUnit>(debug_info->GetUnitAtIndex(0)); + if (!debug_info.ContainsTypeUnits() && debug_info.GetNumUnits() == 1) + return llvm::cast<DWARFCompileUnit>(debug_info.GetUnitAtIndex(0)); // Otherwise, we have to run through all units, and find the compile unit that // way. DWARFCompileUnit *cu = nullptr; - for (size_t i = 0; i < debug_info->GetNumUnits(); ++i) { + for (size_t i = 0; i < debug_info.GetNumUnits(); ++i) { if (auto *candidate = - llvm::dyn_cast<DWARFCompileUnit>(debug_info->GetUnitAtIndex(i))) { + llvm::dyn_cast<DWARFCompileUnit>(debug_info.GetUnitAtIndex(i))) { if (cu) return nullptr; // More that one CU found. cu = candidate; @@ -87,11 +77,6 @@ DWARFCompileUnit *SymbolFileDWARFDwo::ComputeCompileUnit() { return cu; } -DWARFUnit * -SymbolFileDWARFDwo::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { - return GetCompileUnit(); -} - SymbolFileDWARF::DIEToTypePtr &SymbolFileDWARFDwo::GetDIEToType() { return GetBaseSymbolFile().GetDIEToType(); } @@ -110,10 +95,10 @@ SymbolFileDWARFDwo::GetForwardDeclClangTypeToDie() { return GetBaseSymbolFile().GetForwardDeclClangTypeToDie(); } -size_t SymbolFileDWARFDwo::GetObjCMethodDIEOffsets( - lldb_private::ConstString class_name, DIEArray &method_die_offsets) { - return GetBaseSymbolFile().GetObjCMethodDIEOffsets(class_name, - method_die_offsets); +void SymbolFileDWARFDwo::GetObjCMethods( + lldb_private::ConstString class_name, + llvm::function_ref<bool(DWARFDIE die)> callback) { + GetBaseSymbolFile().GetObjCMethods(class_name, callback); } UniqueDWARFASTTypeMap &SymbolFileDWARFDwo::GetUniqueDWARFASTTypeMap() { @@ -133,10 +118,6 @@ lldb::TypeSP SymbolFileDWARFDwo::FindCompleteObjCDefinitionTypeForDIE( die, type_name, must_be_implementation); } -SymbolFileDWARF &SymbolFileDWARFDwo::GetBaseSymbolFile() { - return m_base_dwarf_cu.GetSymbolFileDWARF(); -} - llvm::Expected<TypeSystem &> SymbolFileDWARFDwo::GetTypeSystemForLanguage(LanguageType language) { return GetBaseSymbolFile().GetTypeSystemForLanguage(language); @@ -144,7 +125,7 @@ SymbolFileDWARFDwo::GetTypeSystemForLanguage(LanguageType language) { DWARFDIE SymbolFileDWARFDwo::GetDIE(const DIERef &die_ref) { - if (*die_ref.dwo_num() == GetDwoNum()) - return DebugInfo()->GetDIE(die_ref); + if (die_ref.dwo_num() == GetDwoNum()) + return DebugInfo().GetDIE(die_ref); return GetBaseSymbolFile().GetDIE(die_ref); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index 0855dba044e4..93538aac3c54 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef SymbolFileDWARFDwo_SymbolFileDWARFDwo_h_ -#define SymbolFileDWARFDwo_SymbolFileDWARFDwo_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H #include "SymbolFileDWARF.h" @@ -24,19 +24,15 @@ public: static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } /// \} - SymbolFileDWARFDwo(lldb::ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu); + SymbolFileDWARFDwo(SymbolFileDWARF &m_base_symbol_file, + lldb::ObjectFileSP objfile, uint32_t id); ~SymbolFileDWARFDwo() override = default; - lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu) override; + DWARFCompileUnit *GetDWOCompileUnitForHash(uint64_t hash); - DWARFCompileUnit *GetCompileUnit(); - - DWARFUnit * - GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) override; - - size_t GetObjCMethodDIEOffsets(lldb_private::ConstString class_name, - DIEArray &method_die_offsets) override; + void GetObjCMethods(lldb_private::ConstString class_name, + llvm::function_ref<bool(DWARFDIE die)> callback) override; llvm::Expected<lldb_private::TypeSystem &> GetTypeSystemForLanguage(lldb::LanguageType language) override; @@ -44,14 +40,9 @@ public: DWARFDIE GetDIE(const DIERef &die_ref) override; - DWARFCompileUnit *GetBaseCompileUnit() override { return &m_base_dwarf_cu; } - llvm::Optional<uint32_t> GetDwoNum() override { return GetID() >> 32; } protected: - void LoadSectionData(lldb::SectionType sect_type, - lldb_private::DWARFDataExtractor &data) override; - DIEToTypePtr &GetDIEToType() override; DIEToVariableSP &GetDIEToVariable() override; @@ -69,12 +60,13 @@ protected: const DWARFDIE &die, lldb_private::ConstString type_name, bool must_be_implementation) override; - SymbolFileDWARF &GetBaseSymbolFile(); + SymbolFileDWARF &GetBaseSymbolFile() { return m_base_symbol_file; } - DWARFCompileUnit *ComputeCompileUnit(); + /// If this file contains exactly one compile unit, this function will return + /// it. Otherwise it returns nullptr. + DWARFCompileUnit *FindSingleCompileUnit(); - DWARFCompileUnit &m_base_dwarf_cu; - DWARFCompileUnit *m_cu = nullptr; + SymbolFileDWARF &m_base_symbol_file; }; -#endif // SymbolFileDWARFDwo_SymbolFileDWARFDwo_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp deleted file mode 100644 index 4288dcb5c9bd..000000000000 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//===-- SymbolFileDWARFDwoDwp.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 "SymbolFileDWARFDwoDwp.h" - -#include "lldb/Core/Section.h" -#include "lldb/Expression/DWARFExpression.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Utility/LLDBAssert.h" - -#include "DWARFUnit.h" -#include "DWARFDebugInfo.h" - -using namespace lldb; -using namespace lldb_private; - -char SymbolFileDWARFDwoDwp::ID; - -SymbolFileDWARFDwoDwp::SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, - ObjectFileSP objfile, - DWARFCompileUnit &dwarf_cu, - uint64_t dwo_id) - : SymbolFileDWARFDwo(objfile, dwarf_cu), m_dwp_symfile(dwp_symfile), - m_dwo_id(dwo_id) {} - -void SymbolFileDWARFDwoDwp::LoadSectionData(lldb::SectionType sect_type, - DWARFDataExtractor &data) { - if (m_dwp_symfile->LoadSectionData(m_dwo_id, sect_type, data)) - return; - - SymbolFileDWARF::LoadSectionData(sect_type, data); -} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h deleted file mode 100644 index a55795ba5950..000000000000 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h +++ /dev/null @@ -1,39 +0,0 @@ -//===-- SymbolFileDWARFDwoDwp.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 SymbolFileDWARFDwoDwp_SymbolFileDWARFDwoDwp_h_ -#define SymbolFileDWARFDwoDwp_SymbolFileDWARFDwoDwp_h_ - -#include "SymbolFileDWARFDwo.h" -#include "SymbolFileDWARFDwp.h" - -class SymbolFileDWARFDwoDwp : public SymbolFileDWARFDwo { - /// LLVM RTTI support. - static char ID; - -public: - /// LLVM RTTI support. - /// \{ - bool isA(const void *ClassID) const override { - return ClassID == &ID || SymbolFileDWARFDwo::isA(ClassID); - } - static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } - /// \} - SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, - lldb::ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu, - uint64_t dwo_id); - -protected: - void LoadSectionData(lldb::SectionType sect_type, - lldb_private::DWARFDataExtractor &data) override; - - SymbolFileDWARFDwp *m_dwp_symfile; - uint64_t m_dwo_id; -}; - -#endif // SymbolFileDWARFDwoDwp_SymbolFileDWARFDwoDwp_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp deleted file mode 100644 index 08e6e1c8c2f3..000000000000 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp +++ /dev/null @@ -1,138 +0,0 @@ -//===-- SymbolFileDWARFDwp.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 "SymbolFileDWARFDwp.h" - -#include "lldb/Core/Section.h" -#include "lldb/Symbol/ObjectFile.h" - -#include "SymbolFileDWARFDwoDwp.h" - -static llvm::DWARFSectionKind -lldbSectTypeToLlvmSectionKind(lldb::SectionType type) { - switch (type) { - case lldb::eSectionTypeDWARFDebugInfo: - return llvm::DW_SECT_INFO; - // case lldb::eSectionTypeDWARFDebugTypes: - // return llvm::DW_SECT_TYPES; - case lldb::eSectionTypeDWARFDebugAbbrev: - return llvm::DW_SECT_ABBREV; - case lldb::eSectionTypeDWARFDebugLine: - return llvm::DW_SECT_LINE; - case lldb::eSectionTypeDWARFDebugLoc: - return llvm::DW_SECT_LOC; - case lldb::eSectionTypeDWARFDebugStrOffsets: - return llvm::DW_SECT_STR_OFFSETS; - // case lldb::eSectionTypeDWARFDebugMacinfo: - // return llvm::DW_SECT_MACINFO; - case lldb::eSectionTypeDWARFDebugMacro: - return llvm::DW_SECT_MACRO; - default: - // Note: 0 is an invalid dwarf section kind. - return llvm::DWARFSectionKind(0); - } -} - -std::unique_ptr<SymbolFileDWARFDwp> -SymbolFileDWARFDwp::Create(lldb::ModuleSP module_sp, - const lldb_private::FileSpec &file_spec) { - const lldb::offset_t file_offset = 0; - lldb::DataBufferSP file_data_sp; - lldb::offset_t file_data_offset = 0; - lldb::ObjectFileSP obj_file = lldb_private::ObjectFile::FindPlugin( - module_sp, &file_spec, file_offset, - lldb_private::FileSystem::Instance().GetByteSize(file_spec), file_data_sp, - file_data_offset); - if (obj_file == nullptr) - return nullptr; - - std::unique_ptr<SymbolFileDWARFDwp> dwp_symfile( - new SymbolFileDWARFDwp(module_sp, obj_file)); - - lldb_private::DWARFDataExtractor debug_cu_index; - if (!dwp_symfile->LoadRawSectionData(lldb::eSectionTypeDWARFDebugCuIndex, - debug_cu_index)) - return nullptr; - - llvm::DataExtractor llvm_debug_cu_index( - llvm::StringRef(debug_cu_index.PeekCStr(0), debug_cu_index.GetByteSize()), - debug_cu_index.GetByteOrder() == lldb::eByteOrderLittle, - debug_cu_index.GetAddressByteSize()); - if (!dwp_symfile->m_debug_cu_index.parse(llvm_debug_cu_index)) - return nullptr; - dwp_symfile->InitDebugCUIndexMap(); - return dwp_symfile; -} - -void SymbolFileDWARFDwp::InitDebugCUIndexMap() { - m_debug_cu_index_map.clear(); - for (const auto &entry : m_debug_cu_index.getRows()) - m_debug_cu_index_map.emplace(entry.getSignature(), &entry); -} - -SymbolFileDWARFDwp::SymbolFileDWARFDwp(lldb::ModuleSP module_sp, - lldb::ObjectFileSP obj_file) - : m_obj_file(std::move(obj_file)), m_debug_cu_index(llvm::DW_SECT_INFO) -{} - -std::unique_ptr<SymbolFileDWARFDwo> -SymbolFileDWARFDwp::GetSymbolFileForDwoId(DWARFCompileUnit &dwarf_cu, - uint64_t dwo_id) { - return std::unique_ptr<SymbolFileDWARFDwo>( - new SymbolFileDWARFDwoDwp(this, m_obj_file, dwarf_cu, dwo_id)); -} - -bool SymbolFileDWARFDwp::LoadSectionData( - uint64_t dwo_id, lldb::SectionType sect_type, - lldb_private::DWARFDataExtractor &data) { - lldb_private::DWARFDataExtractor section_data; - if (!LoadRawSectionData(sect_type, section_data)) - return false; - - auto it = m_debug_cu_index_map.find(dwo_id); - if (it == m_debug_cu_index_map.end()) - return false; - - auto *offsets = - it->second->getOffset(lldbSectTypeToLlvmSectionKind(sect_type)); - if (offsets) { - data.SetData(section_data, offsets->Offset, offsets->Length); - } else { - data.SetData(section_data, 0, section_data.GetByteSize()); - } - return true; -} - -bool SymbolFileDWARFDwp::LoadRawSectionData( - lldb::SectionType sect_type, lldb_private::DWARFDataExtractor &data) { - std::lock_guard<std::mutex> lock(m_sections_mutex); - - auto it = m_sections.find(sect_type); - if (it != m_sections.end()) { - if (it->second.GetByteSize() == 0) - return false; - - data = it->second; - return true; - } - - const lldb_private::SectionList *section_list = - m_obj_file->GetSectionList(false /* update_module_section_list */); - if (section_list) { - lldb::SectionSP section_sp( - section_list->FindSectionByType(sect_type, true)); - if (section_sp) { - if (m_obj_file->ReadSectionData(section_sp.get(), data) != 0) { - m_sections[sect_type] = data; - return true; - } - } - } - m_sections[sect_type].Clear(); - return false; -} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h deleted file mode 100644 index ef06b9dca8bb..000000000000 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h +++ /dev/null @@ -1,50 +0,0 @@ -//===-- SymbolFileDWARFDwp.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 SymbolFileDWARFDwp_SymbolFileDWARFDwp_h_ -#define SymbolFileDWARFDwp_SymbolFileDWARFDwp_h_ - -#include <memory> - -#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" - -#include "lldb/Core/Module.h" - -#include "DWARFDataExtractor.h" -#include "SymbolFileDWARFDwo.h" - -class SymbolFileDWARFDwp { -public: - static std::unique_ptr<SymbolFileDWARFDwp> - Create(lldb::ModuleSP module_sp, const lldb_private::FileSpec &file_spec); - - std::unique_ptr<SymbolFileDWARFDwo> - GetSymbolFileForDwoId(DWARFCompileUnit &dwarf_cu, uint64_t dwo_id); - - bool LoadSectionData(uint64_t dwo_id, lldb::SectionType sect_type, - lldb_private::DWARFDataExtractor &data); - -private: - explicit SymbolFileDWARFDwp(lldb::ModuleSP module_sp, - lldb::ObjectFileSP obj_file); - - bool LoadRawSectionData(lldb::SectionType sect_type, - lldb_private::DWARFDataExtractor &data); - - void InitDebugCUIndexMap(); - - lldb::ObjectFileSP m_obj_file; - - std::mutex m_sections_mutex; - std::map<lldb::SectionType, lldb_private::DWARFDataExtractor> m_sections; - - llvm::DWARFUnitIndex m_debug_cu_index; - std::map<uint64_t, const llvm::DWARFUnitIndex::Entry *> m_debug_cu_index_map; -}; - -#endif // SymbolFileDWARFDwp_SymbolFileDWARFDwp_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFProperties.td b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFProperties.td index ef6ae3498588..2f1ce88808b7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFProperties.td +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFProperties.td @@ -1,10 +1,6 @@ include "../../../../include/lldb/Core/PropertiesBase.td" let Definition = "symbolfiledwarf" in { - def SymLinkPaths: Property<"comp-dir-symlink-paths", "FileSpecList">, - Global, - DefaultStringValue<"">, - Desc<"If the DW_AT_comp_dir matches any of these paths the symbolic links will be resolved at DWARF parse time.">; def IgnoreIndexes: Property<"ignore-file-indexes", "Boolean">, Global, DefaultFalse, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp index 4862fea8d079..2181989cd37a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp @@ -1,4 +1,4 @@ -//===-- UniqueDWARFASTType.cpp ----------------------------------*- C++ -*-===// +//===-- UniqueDWARFASTType.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h index 1269dbac7126..a1b1a3009787 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_UniqueDWARFASTType_h_ -#define lldb_UniqueDWARFASTType_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_UNIQUEDWARFASTTYPE_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_UNIQUEDWARFASTTYPE_H #include <vector> @@ -100,4 +100,4 @@ protected: collection m_collection; }; -#endif // lldb_UniqueDWARFASTType_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_UNIQUEDWARFASTTYPE_H diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp index 3834165c71c0..ca9ddcec287f 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp @@ -1,4 +1,4 @@ -//===-- CodeViewRegisterMapping.cpp -----------------------------*- C++ -*-===// +//===-- CodeViewRegisterMapping.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h b/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h index b1c31e0c1785..02c7495565b8 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Plugins_SymbolFile_PDB_CodeViewRegisterMapping_h_ -#define lldb_Plugins_SymbolFile_PDB_CodeViewRegisterMapping_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_CODEVIEWREGISTERMAPPING_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_CODEVIEWREGISTERMAPPING_H #include "llvm/ADT/Triple.h" #include "llvm/DebugInfo/CodeView/CodeView.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp index 830d78f81679..f25dc84fb342 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp @@ -1,4 +1,4 @@ -//===-- CompileUnitIndex.cpp ------------------------------------*- C++ -*-===// +//===-- CompileUnitIndex.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -154,7 +154,7 @@ CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) { // name until we find it, and we can cache that one since the memory is backed // by a contiguous chunk inside the mapped PDB. llvm::SmallString<64> main_file = GetMainSourceFile(*cci); - std::string s = main_file.str(); + std::string s = std::string(main_file.str()); llvm::sys::path::native(main_file); uint32_t file_count = modules.getSourceFileCount(modi); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h index 44a1c8cdd9c2..088de970cbf3 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_COMPILEUNITINDEX_H -#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_COMPILEUNITINDEX_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp index 6aaff06cc134..d0672352a58f 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp @@ -1,4 +1,4 @@ -//===-- DWARFLocationExpression.cpp -----------------------------*- C++ -*-===// +//===-- DWARFLocationExpression.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h index c37d715babdc..99da09b70fe1 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h @@ -6,14 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H -#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H #include "lldb/lldb-forward.h" #include "llvm/DebugInfo/CodeView/CodeView.h" namespace llvm { class APSInt; +class StringRef; namespace codeview { class TypeIndex; } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 4588c80aa1b1..0acc77d7c67f 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -14,11 +14,11 @@ #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Demangle/MicrosoftDemangle.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" @@ -178,7 +178,7 @@ GetNestedTagDefinition(const NestedTypeRecord &Record, // single component of a mangled name. So we can inject it into the parent's // mangled name to see if it matches. CVTagRecord child = CVTagRecord::create(cvt); - std::string qname = parent.asTag().getUniqueName(); + std::string qname = std::string(parent.asTag().getUniqueName()); if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4) return llvm::None; @@ -202,7 +202,7 @@ static bool IsAnonymousNamespaceName(llvm::StringRef name) { return name == "`anonymous namespace'" || name == "`anonymous-namespace'"; } -PdbAstBuilder::PdbAstBuilder(ObjectFile &obj, PdbIndex &index, ClangASTContext &clang) +PdbAstBuilder::PdbAstBuilder(ObjectFile &obj, PdbIndex &index, TypeSystemClang &clang) : m_index(index), m_clang(clang) { BuildParentMap(); } @@ -221,7 +221,7 @@ PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { StringView sv(record.UniqueName.begin(), record.UniqueName.size()); llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv); if (demangler.Error) - return {m_clang.GetTranslationUnitDecl(), record.UniqueName}; + return {m_clang.GetTranslationUnitDecl(), std::string(record.UniqueName)}; llvm::ms_demangle::IdentifierNode *idn = ttn->QualifiedName->getUnqualifiedIdentifier(); @@ -248,7 +248,7 @@ PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { // a NamespaceDecl and a CXXRecordDecl, so instead we create a class at // global scope with the fully qualified name. if (AnyScopesHaveTemplateParams(scopes)) - return {context, record.Name}; + return {context, std::string(record.Name)}; for (llvm::ms_demangle::Node *scope : scopes) { auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope); @@ -507,7 +507,7 @@ PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) { llvm::StringRef uname = specs.back().GetBaseName(); specs = specs.drop_back(); if (specs.empty()) - return {context, name}; + return {context, std::string(name)}; llvm::StringRef scope_name = specs.back().GetFullName(); @@ -517,7 +517,7 @@ PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) { clang::QualType qt = GetOrCreateType(types.back()); clang::TagDecl *tag = qt->getAsTagDecl(); if (tag) - return {clang::TagDecl::castToDeclContext(tag), uname}; + return {clang::TagDecl::castToDeclContext(tag), std::string(uname)}; types.pop_back(); } @@ -526,7 +526,7 @@ PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) { std::string ns_name = spec.GetBaseName().str(); context = GetOrCreateNamespaceDecl(ns_name.c_str(), *context); } - return {context, uname}; + return {context, std::string(uname)}; } clang::DeclContext * @@ -656,7 +656,7 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { lldbassert(IsTagRecord(type_id, m_index.tpi())); clang::QualType tag_qt = m_clang.getASTContext().getTypeDeclType(&tag); - ClangASTContext::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false); + TypeSystemClang::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false); TypeIndex tag_ti = type_id.index; CVType cvt = m_index.tpi().getType(tag_ti); @@ -681,7 +681,7 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { // Visit all members of this class, then perform any finalization necessary // to complete the class. CompilerType ct = ToCompilerType(tag_qt); - UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index.tpi()); + UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index); auto error = llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer); completer.complete(); @@ -776,12 +776,13 @@ clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, metadata.SetUserID(toOpaqueUid(id)); metadata.SetIsDynamicCXXType(false); - CompilerType ct = m_clang.CreateRecordType( - context, access, uname, ttk, lldb::eLanguageTypeC_plus_plus, &metadata); + CompilerType ct = + m_clang.CreateRecordType(context, OptionalClangModuleID(), access, uname, + ttk, lldb::eLanguageTypeC_plus_plus, &metadata); lldbassert(ct.IsValid()); - ClangASTContext::StartTagDeclarationDefinition(ct); + TypeSystemClang::StartTagDeclarationDefinition(ct); // Even if it's possible, don't complete it at this point. Just mark it // forward resolved, and if/when LLDB needs the full definition, it can @@ -789,7 +790,7 @@ clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, clang::QualType result = clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); - ClangASTContext::SetHasExternalStorage(result.getAsOpaquePtr(), true); + TypeSystemClang::SetHasExternalStorage(result.getAsOpaquePtr(), true); return result; } @@ -804,7 +805,8 @@ clang::NamespaceDecl * PdbAstBuilder::GetOrCreateNamespaceDecl(const char *name, clang::DeclContext &context) { return m_clang.GetUniqueNamespaceDeclaration( - IsAnonymousNamespaceName(name) ? nullptr : name, &context); + IsAnonymousNamespaceName(name) ? nullptr : name, &context, + OptionalClangModuleID()); } clang::BlockDecl * @@ -814,7 +816,8 @@ PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) { clang::DeclContext *scope = GetParentDeclContext(block_id); - clang::BlockDecl *block_decl = m_clang.CreateBlockDeclaration(scope); + clang::BlockDecl *block_decl = + m_clang.CreateBlockDeclaration(scope, OptionalClangModuleID()); m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl}); DeclStatus status; @@ -831,7 +834,7 @@ clang::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym, clang::QualType qt = GetOrCreateType(var_info.type); clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration( - &scope, var_info.name.str().c_str(), qt); + &scope, OptionalClangModuleID(), var_info.name.str().c_str(), qt); m_uid_to_decl[toOpaqueUid(uid)] = var_decl; DeclStatus status; @@ -876,10 +879,10 @@ PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) { PdbTypeSymId real_type_id{udt.Type, false}; clang::QualType qt = GetOrCreateType(real_type_id); - std::string uname = DropNameScope(udt.Name); + std::string uname = std::string(DropNameScope(udt.Name)); CompilerType ct = m_clang.CreateTypedefType(ToCompilerType(qt), uname.c_str(), - ToCompilerDeclContext(*scope)); + ToCompilerDeclContext(*scope), 0); clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct); DeclStatus status; status.resolved = true; @@ -1012,7 +1015,8 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { proc_name.consume_front("::"); clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( - parent, proc_name.str().c_str(), func_ct, storage, false); + parent, OptionalClangModuleID(), proc_name.str().c_str(), func_ct, + storage, false); lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; @@ -1080,8 +1084,8 @@ void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, CompilerType param_type_ct = m_clang.GetType(qt); clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( - &function_decl, param_name.str().c_str(), param_type_ct, - clang::SC_None, true); + &function_decl, OptionalClangModuleID(), param_name.str().c_str(), + param_type_ct, clang::SC_None, true); lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0); m_uid_to_decl[toOpaqueUid(param_uid)] = param; @@ -1102,11 +1106,11 @@ clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id, Declaration declaration; CompilerType enum_ct = m_clang.CreateEnumerationType( - uname.c_str(), decl_context, declaration, ToCompilerType(underlying_type), - er.isScoped()); + uname.c_str(), decl_context, OptionalClangModuleID(), declaration, + ToCompilerType(underlying_type), er.isScoped()); - ClangASTContext::StartTagDeclarationDefinition(enum_ct); - ClangASTContext::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true); + TypeSystemClang::StartTagDeclarationDefinition(enum_ct); + TypeSystemClang::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true); return clang::QualType::getFromOpaquePtr(enum_ct.GetOpaqueQualType()); } @@ -1334,7 +1338,7 @@ void PdbAstBuilder::ParseDeclsForContext(clang::DeclContext &context) { } CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) { - return {&m_clang, &decl}; + return m_clang.GetCompilerDecl(&decl); } CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) { @@ -1347,7 +1351,7 @@ PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) { } clang::Decl * PdbAstBuilder::FromCompilerDecl(CompilerDecl decl) { - return static_cast<clang::Decl *>(decl.GetOpaqueDecl()); + return ClangUtil::GetDecl(decl); } clang::DeclContext * diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h index a4242e90810d..7bb2584d19a3 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H -#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "PdbIndex.h" #include "PdbSymUid.h" @@ -51,7 +51,7 @@ struct DeclStatus { class PdbAstBuilder { public: // Constructors and Destructors - PdbAstBuilder(ObjectFile &obj, PdbIndex &index, ClangASTContext &clang); + PdbAstBuilder(ObjectFile &obj, PdbIndex &index, TypeSystemClang &clang); lldb_private::CompilerDeclContext GetTranslationUnitDecl(); @@ -80,7 +80,7 @@ public: clang::Decl *FromCompilerDecl(CompilerDecl decl); clang::DeclContext *FromCompilerDeclContext(CompilerDeclContext context); - ClangASTContext &clang() { return m_clang; } + TypeSystemClang &clang() { return m_clang; } ClangASTImporter &importer() { return m_importer; } void Dump(Stream &stream); @@ -129,7 +129,7 @@ private: clang::QualType CreateSimpleType(TypeIndex ti); PdbIndex &m_index; - ClangASTContext &m_clang; + TypeSystemClang &m_clang; ClangASTImporter m_importer; @@ -142,4 +142,4 @@ private: } // namespace npdb } // namespace lldb_private -#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp index a7bc23519710..ecae767e4469 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp @@ -1,4 +1,4 @@ -//===-- PdbFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===// +//===-- PdbFPOProgramToDWARFExpression.cpp --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h index 107e26fb04cb..fb979b877143 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Plugins_SymbolFile_PDB_PDBFPOProgramToDWARFExpression_h_ -#define lldb_Plugins_SymbolFile_PDB_PDBFPOProgramToDWARFExpression_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBFPOPROGRAMTODWARFEXPRESSION_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBFPOPROGRAMTODWARFEXPRESSION_H #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp index ba9a95b16e18..6ac6cc2da29b 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp @@ -1,4 +1,4 @@ -//===-- PdbIndex.cpp --------------------------------------------*- C++ -*-===// +//===-- PdbIndex.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h index b30e7870bbdb..ccc3cc2f4538 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H -#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBINDEX_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBINDEX_H #include "lldb/lldb-types.h" #include "llvm/ADT/IntervalMap.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp index e5ad23f813eb..67397d707110 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp @@ -1,4 +1,4 @@ -//===-- PdbSymUid.cpp -------------------------------------------*- C++ -*-===// +//===-- PdbSymUid.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h index 7252d63c1ab4..3accd38d710e 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h @@ -14,8 +14,8 @@ // access to the compile unit's information. //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H -#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBSYMUID_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBSYMUID_H #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp index fc047e25a2f4..b5a16447d9cf 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -1,4 +1,4 @@ -//===-- PdbUtil.cpp ---------------------------------------------*- C++ -*-===// +//===-- PdbUtil.cpp -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h index 6f675b56dca4..c309c5c8ea1c 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H -#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBUTIL_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBUTIL_H #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/Variable.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index 370c339fb74b..cce06473d92f 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -1,4 +1,4 @@ -//===-- SymbolFileNativePDB.cpp ---------------------------------*- C++ -*-===// +//===-- SymbolFileNativePDB.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -14,13 +14,13 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#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/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" @@ -129,17 +129,18 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { // If it doesn't have a debug directory, fail. llvm::StringRef pdb_file; - auto ec = obj->getDebugPDBInfo(pdb_info, pdb_file); - if (ec) + if (llvm::Error e = obj->getDebugPDBInfo(pdb_info, pdb_file)) { + consumeError(std::move(e)); return nullptr; + } // if the file doesn't exist, is not a pdb, or doesn't have a matching guid, // fail. llvm::file_magic magic; - ec = llvm::identify_magic(pdb_file, magic); + auto ec = llvm::identify_magic(pdb_file, magic); if (ec || magic != llvm::file_magic::pdb) return nullptr; - std::unique_ptr<PDBFile> pdb = loadPDBFile(pdb_file, allocator); + std::unique_ptr<PDBFile> pdb = loadPDBFile(std::string(pdb_file), allocator); if (!pdb) return nullptr; @@ -331,7 +332,7 @@ void SymbolFileNativePDB::InitializeObject() { std::move(err), "Failed to initialize"); } else { ts_or_err->SetSymbolFile(this); - auto *clang = llvm::cast_or_null<ClangASTContext>(&ts_or_err.get()); + auto *clang = llvm::cast_or_null<TypeSystemClang>(&ts_or_err.get()); lldbassert(clang); m_ast = std::make_unique<PdbAstBuilder>(*m_objfile_sp, *m_index, *clang); } @@ -452,7 +453,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id, std::string name; if (mr.ModifiedType.isSimple()) - name = GetSimpleTypeName(mr.ModifiedType.getSimpleKind()); + name = std::string(GetSimpleTypeName(mr.ModifiedType.getSimpleKind())); else name = computeTypeName(stream.typeCollection(), mr.ModifiedType); Declaration decl; @@ -532,14 +533,14 @@ static std::string GetUnqualifiedTypeName(const TagRecord &record) { MSVCUndecoratedNameParser parser(record.Name); llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers(); - return specs.back().GetBaseName(); + return std::string(specs.back().GetBaseName()); } llvm::ms_demangle::Demangler demangler; StringView sv(record.UniqueName.begin(), record.UniqueName.size()); llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv); if (demangler.Error) - return record.Name; + return std::string(record.Name); llvm::ms_demangle::IdentifierNode *idn = ttn->QualifiedName->getUnqualifiedIdentifier(); @@ -1171,7 +1172,7 @@ size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) { void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); } void SymbolFileNativePDB::FindGlobalVariables( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, VariableList &variables) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>; @@ -1198,7 +1199,7 @@ void SymbolFileNativePDB::FindGlobalVariables( } void SymbolFileNativePDB::FindFunctions( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + ConstString name, const CompilerDeclContext &parent_decl_ctx, FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); @@ -1236,7 +1237,7 @@ void SymbolFileNativePDB::FindFunctions(const RegularExpression ®ex, SymbolContextList &sc_list) {} void SymbolFileNativePDB::FindTypes( - ConstString name, const CompilerDeclContext *parent_decl_ctx, + 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()); @@ -1563,7 +1564,7 @@ void SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, CompilerDeclContext SymbolFileNativePDB::FindNamespace(ConstString name, - const CompilerDeclContext *parent_decl_ctx) { + const CompilerDeclContext &parent_decl_ctx) { return {}; } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h index a37de0f58ef3..bf5718e11a19 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H -#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H #include "lldb/Symbol/SymbolFile.h" @@ -100,7 +100,7 @@ public: size_t ParseBlocksRecursive(Function &func) override; void FindGlobalVariables(ConstString name, - const CompilerDeclContext *parent_decl_ctx, + const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, VariableList &variables) override; @@ -129,14 +129,14 @@ public: TypeList &type_list) override; void FindFunctions(ConstString name, - const CompilerDeclContext *parent_decl_ctx, + const CompilerDeclContext &parent_decl_ctx, lldb::FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) override; void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) override; - void FindTypes(ConstString name, const CompilerDeclContext *parent_decl_ctx, + void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) override; @@ -150,7 +150,7 @@ public: CompilerDeclContext FindNamespace(ConstString name, - const CompilerDeclContext *parent_decl_ctx) override; + const CompilerDeclContext &parent_decl_ctx) override; ConstString GetPluginName() override; @@ -246,4 +246,4 @@ private: } // namespace npdb } // namespace lldb_private -#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index 7221144407c1..c8fb46c75034 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -5,15 +5,18 @@ #include "PdbSymUid.h" #include "PdbUtil.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Type.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" @@ -29,10 +32,10 @@ UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder, - TpiStream &tpi) + PdbIndex &index) : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl), - m_ast_builder(ast_builder), m_tpi(tpi) { - CVType cvt = m_tpi.getType(m_id.index); + m_ast_builder(ast_builder), m_index(index) { + CVType cvt = m_index.tpi().getType(m_id.index); switch (cvt.kind()) { case LF_ENUM: llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er)); @@ -55,7 +58,7 @@ clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex( PdbTypeSymId type_id(ti); clang::QualType qt = m_ast_builder.GetOrCreateType(type_id); - CVType udt_cvt = m_tpi.getType(ti); + CVType udt_cvt = m_index.tpi().getType(ti); std::unique_ptr<clang::CXXBaseSpecifier> base_spec = m_ast_builder.clang().CreateBaseClassSpecifier( @@ -128,9 +131,70 @@ Error UdtRecordCompleter::visitKnownMember( lldb::AccessType access = TranslateMemberAccess(static_data_member.getAccess()); - ClangASTContext::AddVariableToRecordType( + auto decl = TypeSystemClang::AddVariableToRecordType( m_derived_ct, static_data_member.Name, member_ct, access); + // Static constant members may be a const[expr] declaration. + // Query the symbol's value as the variable initializer if valid. + if (member_ct.IsConst()) { + std::string qual_name = decl->getQualifiedNameAsString(); + + auto results = + m_index.globals().findRecordsByName(qual_name, m_index.symrecords()); + + for (const auto &result : results) { + if (result.second.kind() == SymbolKind::S_CONSTANT) { + ConstantSym constant(SymbolRecordKind::ConstantSym); + cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(result.second, + constant)); + + clang::QualType qual_type = decl->getType(); + unsigned type_width = decl->getASTContext().getIntWidth(qual_type); + unsigned constant_width = constant.Value.getBitWidth(); + + if (qual_type->isIntegralOrEnumerationType()) { + if (type_width >= constant_width) { + TypeSystemClang::SetIntegerInitializerForVariable( + decl, constant.Value.extOrTrunc(type_width)); + } else { + LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST), + "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) " + "which resolves to a wider constant value ({4} bits). " + "Ignoring constant.", + m_derived_ct.GetTypeName(), static_data_member.Name, + member_ct.GetTypeName(), type_width, constant_width); + } + } else { + lldb::BasicType basic_type_enum = member_ct.GetBasicTypeEnumeration(); + switch (basic_type_enum) { + case lldb::eBasicTypeFloat: + case lldb::eBasicTypeDouble: + case lldb::eBasicTypeLongDouble: + if (type_width == constant_width) { + TypeSystemClang::SetFloatingInitializerForVariable( + decl, basic_type_enum == lldb::eBasicTypeFloat + ? llvm::APFloat(constant.Value.bitsToFloat()) + : llvm::APFloat(constant.Value.bitsToDouble())); + decl->setConstexpr(true); + } else { + LLDB_LOG( + GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST), + "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) " + "which resolves to a constant value of mismatched width " + "({4} bits). Ignoring constant.", + m_derived_ct.GetTypeName(), static_data_member.Name, + member_ct.GetTypeName(), type_width, constant_width); + } + break; + default: + break; + } + } + break; + } + } + } + // FIXME: Add a PdbSymUid namespace for field list members and update // the m_uid_to_decl map with this decl. return Error::success(); @@ -149,7 +213,7 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, TypeIndex ti(data_member.Type); if (!ti.isSimple()) { - CVType cvt = m_tpi.getType(ti); + CVType cvt = m_index.tpi().getType(ti); if (cvt.kind() == LF_BITFIELD) { BitFieldRecord bfr; llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr)); @@ -164,7 +228,7 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, lldb::AccessType access = TranslateMemberAccess(data_member.getAccess()); - clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType( + clang::FieldDecl *decl = TypeSystemClang::AddFieldToRecordType( m_derived_ct, data_member.Name, m_ast_builder.ToCompilerType(member_qt), access, bitfield_width); // FIXME: Add a PdbSymUid namespace for field list members and update @@ -187,7 +251,7 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, OverloadedMethodRecord &overloaded) { TypeIndex method_list_idx = overloaded.MethodList; - CVType method_list_type = m_tpi.getType(method_list_idx); + CVType method_list_type = m_index.tpi().getType(method_list_idx); assert(method_list_type.kind() == LF_METHODLIST); MethodOverloadListRecord method_list; @@ -223,12 +287,12 @@ void UdtRecordCompleter::complete() { for (auto &ib : m_bases) bases.push_back(std::move(ib.second)); - ClangASTContext &clang = m_ast_builder.clang(); + TypeSystemClang &clang = m_ast_builder.clang(); clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), std::move(bases)); clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType()); - ClangASTContext::BuildIndirectFields(m_derived_ct); - ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct); + TypeSystemClang::BuildIndirectFields(m_derived_ct); + TypeSystemClang::CompleteTagDeclarationDefinition(m_derived_ct); if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) { m_ast_builder.importer().SetRecordLayout(record_decl, m_layout); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h index 55397582209b..ae7e47c82fe5 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h @@ -6,10 +6,10 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H -#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -25,6 +25,7 @@ class TagDecl; namespace llvm { namespace pdb { class TpiStream; +class GlobalsStream; } } // namespace llvm @@ -33,6 +34,7 @@ class Type; class CompilerType; namespace npdb { class PdbAstBuilder; +class PdbIndex; class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks { using IndexedBase = @@ -49,14 +51,14 @@ class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks { CompilerType &m_derived_ct; clang::TagDecl &m_tag_decl; PdbAstBuilder &m_ast_builder; - llvm::pdb::TpiStream &m_tpi; + PdbIndex &m_index; std::vector<IndexedBase> m_bases; ClangASTImporter::LayoutInfo m_layout; public: UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder, - llvm::pdb::TpiStream &tpi); + PdbIndex &index); #define MEMBER_RECORD(EnumName, EnumVal, Name) \ llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \ @@ -79,4 +81,4 @@ private: } // namespace npdb } // namespace lldb_private -#endif // LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 6b2dbd9e1e5a..d87926a6588f 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -1,4 +1,4 @@ -//===-- PDBASTParser.cpp ----------------------------------------*- C++ -*-===// +//===-- PDBASTParser.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -14,10 +14,10 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeMap.h" @@ -100,7 +100,7 @@ static lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) { } static CompilerType -GetBuiltinTypeForPDBEncodingAndBitSize(ClangASTContext &clang_ast, +GetBuiltinTypeForPDBEncodingAndBitSize(TypeSystemClang &clang_ast, const PDBSymbolTypeBuiltin &pdb_type, Encoding encoding, uint32_t width) { clang::ASTContext &ast = clang_ast.getASTContext(); @@ -353,7 +353,7 @@ static clang::CallingConv TranslateCallingConvention(PDB_CallingConv pdb_cc) { } } -PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {} +PDBASTParser::PDBASTParser(lldb_private::TypeSystemClang &ast) : m_ast(ast) {} PDBASTParser::~PDBASTParser() {} @@ -386,7 +386,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { return nullptr; // Ignore unnamed-tag UDTs. - std::string name = MSVCUndecoratedNameParser::DropScope(udt->getName()); + std::string name = + std::string(MSVCUndecoratedNameParser::DropScope(udt->getName())); if (name.empty()) return nullptr; @@ -408,9 +409,9 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { metadata.SetUserID(type.getSymIndexId()); metadata.SetIsDynamicCXXType(false); - clang_type = - m_ast.CreateRecordType(decl_context, access, name, tag_type_kind, - lldb::eLanguageTypeC_plus_plus, &metadata); + clang_type = m_ast.CreateRecordType( + decl_context, OptionalClangModuleID(), access, name, tag_type_kind, + lldb::eLanguageTypeC_plus_plus, &metadata); assert(clang_type.IsValid()); auto record_decl = @@ -422,15 +423,15 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { m_ast.getASTContext(), GetMSInheritance(*udt)); record_decl->addAttr(inheritance_attr); - ClangASTContext::StartTagDeclarationDefinition(clang_type); + TypeSystemClang::StartTagDeclarationDefinition(clang_type); auto children = udt->findAllChildren(); if (!children || children->getChildCount() == 0) { // PDB does not have symbol of forwarder. We assume we get an udt w/o // any fields. Just complete it at this point. - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); - ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(), + TypeSystemClang::SetHasExternalStorage(clang_type.GetOpaqueQualType(), false); type_resolve_state = Type::ResolveState::Full; @@ -439,7 +440,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { // an endless recursion in CompleteTypeFromUdt function. m_forward_decl_to_uid[record_decl] = type.getSymIndexId(); - ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(), + TypeSystemClang::SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); type_resolve_state = Type::ResolveState::Forward; @@ -465,7 +466,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { assert(enum_type); std::string name = - MSVCUndecoratedNameParser::DropScope(enum_type->getName()); + std::string(MSVCUndecoratedNameParser::DropScope(enum_type->getName())); auto decl_context = GetDeclContextContainingSymbol(type); uint64_t bytes = enum_type->getLength(); @@ -496,10 +497,11 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { // Class). Set it false for now. bool isScoped = false; - ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, decl, + ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, + OptionalClangModuleID(), decl, builtin_type, isScoped); - auto enum_decl = ClangASTContext::GetAsEnumDecl(ast_enum); + auto enum_decl = TypeSystemClang::GetAsEnumDecl(ast_enum); assert(enum_decl); m_uid_to_decl[type.getSymIndexId()] = enum_decl; @@ -512,8 +514,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { } } - if (ClangASTContext::StartTagDeclarationDefinition(ast_enum)) - ClangASTContext::CompleteTagDeclarationDefinition(ast_enum); + if (TypeSystemClang::StartTagDeclarationDefinition(ast_enum)) + TypeSystemClang::CompleteTagDeclarationDefinition(ast_enum); } if (enum_type->isConstType()) @@ -538,7 +540,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { return nullptr; std::string name = - MSVCUndecoratedNameParser::DropScope(type_def->getName()); + std::string(MSVCUndecoratedNameParser::DropScope(type_def->getName())); auto decl_ctx = GetDeclContextContainingSymbol(type); // Check if such a typedef already exists in the current context @@ -549,11 +551,11 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { CompilerType target_ast_type = target_type->GetFullCompilerType(); ast_typedef = m_ast.CreateTypedefType( - target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx)); + target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0); if (!ast_typedef) return nullptr; - auto typedef_decl = ClangASTContext::GetAsTypedefDecl(ast_typedef); + auto typedef_decl = TypeSystemClang::GetAsTypedefDecl(ast_typedef); assert(typedef_decl); m_uid_to_decl[type.getSymIndexId()] = typedef_decl; } @@ -587,7 +589,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { return nullptr; func_sig = sig.release(); // Function type is named. - name = MSVCUndecoratedNameParser::DropScope(pdb_func->getName()); + name = std::string( + MSVCUndecoratedNameParser::DropScope(pdb_func->getName())); } else if (auto pdb_func_sig = llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) { func_sig = const_cast<PDBSymbolTypeFunctionSig *>(pdb_func_sig); @@ -660,10 +663,10 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { CompilerType element_ast_type = element_type->GetForwardCompilerType(); // If element type is UDT, it needs to be complete. - if (ClangASTContext::IsCXXClassType(element_ast_type) && + if (TypeSystemClang::IsCXXClassType(element_ast_type) && !element_ast_type.GetCompleteType()) { - if (ClangASTContext::StartTagDeclarationDefinition(element_ast_type)) { - ClangASTContext::CompleteTagDeclarationDefinition(element_ast_type); + if (TypeSystemClang::StartTagDeclarationDefinition(element_ast_type)) { + TypeSystemClang::CompleteTagDeclarationDefinition(element_ast_type); } else { // We are not able to start defintion. return nullptr; @@ -721,7 +724,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { assert(class_parent_type); CompilerType pointer_ast_type; - pointer_ast_type = ClangASTContext::CreateMemberPointerType( + pointer_ast_type = TypeSystemClang::CreateMemberPointerType( class_parent_type->GetLayoutCompilerType(), pointee_type->GetForwardCompilerType()); assert(pointer_ast_type); @@ -787,7 +790,7 @@ bool PDBASTParser::CompleteTypeFromPDB( m_forward_decl_to_uid.erase(uid_it); - ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), + TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), false); switch (symbol->getSymTag()) { @@ -887,7 +890,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { if (auto parent_decl = llvm::dyn_cast_or_null<clang::TagDecl>(decl_context)) m_ast.GetCompleteDecl(parent_decl); - std::string name = MSVCUndecoratedNameParser::DropScope(data->getName()); + std::string name = + std::string(MSVCUndecoratedNameParser::DropScope(data->getName())); // Check if the current context already contains the symbol with the name. clang::Decl *decl = @@ -898,7 +902,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { return nullptr; decl = m_ast.CreateVariableDeclaration( - decl_context, name.c_str(), + decl_context, OptionalClangModuleID(), name.c_str(), ClangUtil::GetQualType(type->GetLayoutCompilerType())); } @@ -913,7 +917,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { auto decl_context = GetDeclContextContainingSymbol(symbol); assert(decl_context); - std::string name = MSVCUndecoratedNameParser::DropScope(func->getName()); + std::string name = + std::string(MSVCUndecoratedNameParser::DropScope(func->getName())); Type *type = symbol_file->ResolveTypeUID(sym_id); if (!type) @@ -923,8 +928,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { : clang::StorageClass::SC_None; auto decl = m_ast.CreateFunctionDeclaration( - decl_context, name.c_str(), type->GetForwardCompilerType(), storage, - func->hasInlineAttribute()); + decl_context, OptionalClangModuleID(), name.c_str(), + type->GetForwardCompilerType(), storage, func->hasInlineAttribute()); std::vector<clang::ParmVarDecl *> params; if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) { @@ -937,8 +942,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { continue; clang::ParmVarDecl *param = m_ast.CreateParameterDeclaration( - decl, nullptr, arg_type->GetForwardCompilerType(), - clang::SC_None, true); + decl, OptionalClangModuleID(), nullptr, + arg_type->GetForwardCompilerType(), clang::SC_None, true); if (param) params.push_back(param); } @@ -1047,13 +1052,13 @@ clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol( // or a type. We check it to avoid fake namespaces such as `__l2': // `N0::N1::CClass::PrivateFunc::__l2::InnerFuncStruct' if (!has_type_or_function_parent) { - std::string namespace_name = specs[i].GetBaseName(); + std::string namespace_name = std::string(specs[i].GetBaseName()); const char *namespace_name_c_str = IsAnonymousNamespaceName(namespace_name) ? nullptr : namespace_name.data(); clang::NamespaceDecl *namespace_decl = - m_ast.GetUniqueNamespaceDeclaration(namespace_name_c_str, - curr_context); + m_ast.GetUniqueNamespaceDeclaration( + namespace_name_c_str, curr_context, OptionalClangModuleID()); m_parent_to_namespaces[curr_context].insert(namespace_decl); m_namespaces.insert(namespace_decl); @@ -1119,7 +1124,8 @@ bool PDBASTParser::AddEnumValue(CompilerType enum_type, const PDBSymbolData &enum_value) { Declaration decl; Variant v = enum_value.getValue(); - std::string name = MSVCUndecoratedNameParser::DropScope(enum_value.getName()); + std::string name = + std::string(MSVCUndecoratedNameParser::DropScope(enum_value.getName())); int64_t raw_value; switch (v.Type) { case PDB_VariantType::Int8: @@ -1149,8 +1155,7 @@ bool PDBASTParser::AddEnumValue(CompilerType enum_type, default: return false; } - CompilerType underlying_type = - m_ast.GetEnumerationIntegerType(enum_type.GetOpaqueQualType()); + CompilerType underlying_type = m_ast.GetEnumerationIntegerType(enum_type); uint32_t byte_size = m_ast.getASTContext().getTypeSize( ClangUtil::GetQualType(underlying_type)); auto enum_constant_decl = m_ast.AddEnumerationValueToEnumerationType( @@ -1190,8 +1195,8 @@ bool PDBASTParser::CompleteTypeFromUDT( AddRecordMethods(symbol_file, compiler_type, *methods_enum); m_ast.AddMethodOverridesForCXXRecordType(compiler_type.GetOpaqueQualType()); - ClangASTContext::BuildIndirectFields(compiler_type); - ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); + TypeSystemClang::BuildIndirectFields(compiler_type); + TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type); clang::CXXRecordDecl *record_decl = m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType()); @@ -1225,8 +1230,8 @@ void PDBASTParser::AddRecordMembers( "which does not have a complete definition.", record_type.GetTypeName().GetCString(), member_name.c_str(), member_comp_type.GetTypeName().GetCString()); - if (ClangASTContext::StartTagDeclarationDefinition(member_comp_type)) - ClangASTContext::CompleteTagDeclarationDefinition(member_comp_type); + if (TypeSystemClang::StartTagDeclarationDefinition(member_comp_type)) + TypeSystemClang::CompleteTagDeclarationDefinition(member_comp_type); } auto access = TranslateMemberAccess(member->getAccess()); @@ -1239,7 +1244,7 @@ void PDBASTParser::AddRecordMembers( if (location_type == PDB_LocType::ThisRel) bit_size *= 8; - auto decl = ClangASTContext::AddFieldToRecordType( + auto decl = TypeSystemClang::AddFieldToRecordType( record_type, member_name.c_str(), member_comp_type, access, bit_size); if (!decl) continue; @@ -1255,11 +1260,57 @@ void PDBASTParser::AddRecordMembers( break; } case PDB_DataKind::StaticMember: { - auto decl = ClangASTContext::AddVariableToRecordType( + auto decl = TypeSystemClang::AddVariableToRecordType( record_type, member_name.c_str(), member_comp_type, access); if (!decl) continue; + // Static constant members may be a const[expr] declaration. + // Query the symbol's value as the variable initializer if valid. + if (member_comp_type.IsConst()) { + auto value = member->getValue(); + clang::QualType qual_type = decl->getType(); + unsigned type_width = m_ast.getASTContext().getIntWidth(qual_type); + unsigned constant_width = value.getBitWidth(); + + if (qual_type->isIntegralOrEnumerationType()) { + if (type_width >= constant_width) { + TypeSystemClang::SetIntegerInitializerForVariable( + decl, value.toAPSInt().extOrTrunc(type_width)); + } else { + LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST), + "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) " + "which resolves to a wider constant value ({4} bits). " + "Ignoring constant.", + record_type.GetTypeName(), member_name, + member_comp_type.GetTypeName(), type_width, + constant_width); + } + } else { + switch (member_comp_type.GetBasicTypeEnumeration()) { + case lldb::eBasicTypeFloat: + case lldb::eBasicTypeDouble: + case lldb::eBasicTypeLongDouble: + if (type_width == constant_width) { + TypeSystemClang::SetFloatingInitializerForVariable( + decl, value.toAPFloat()); + decl->setConstexpr(true); + } else { + LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST), + "Class '{0}' has a member '{1}' of type '{2}' ({3} " + "bits) which resolves to a constant value of mismatched " + "width ({4} bits). Ignoring constant.", + record_type.GetTypeName(), member_name, + member_comp_type.GetTypeName(), type_width, + constant_width); + } + break; + default: + break; + } + } + } + m_uid_to_decl[member->getSymIndexId()] = decl; break; @@ -1289,8 +1340,8 @@ void PDBASTParser::AddRecordBases( "which does not have a complete definition.", record_type.GetTypeName().GetCString(), base_comp_type.GetTypeName().GetCString()); - if (ClangASTContext::StartTagDeclarationDefinition(base_comp_type)) - ClangASTContext::CompleteTagDeclarationDefinition(base_comp_type); + if (TypeSystemClang::StartTagDeclarationDefinition(base_comp_type)) + TypeSystemClang::CompleteTagDeclarationDefinition(base_comp_type); } auto access = TranslateMemberAccess(base->getAccess()); @@ -1333,7 +1384,8 @@ clang::CXXMethodDecl * PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file, lldb_private::CompilerType &record_type, const llvm::pdb::PDBSymbolFunc &method) const { - std::string name = MSVCUndecoratedNameParser::DropScope(method.getName()); + std::string name = + std::string(MSVCUndecoratedNameParser::DropScope(method.getName())); Type *method_type = symbol_file.ResolveTypeUID(method.getSymIndexId()); // MSVC specific __vecDelDtor. @@ -1346,8 +1398,8 @@ PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file, ":: Class '%s' has a method '%s' whose type cannot be completed.", record_type.GetTypeName().GetCString(), method_comp_type.GetTypeName().GetCString()); - if (ClangASTContext::StartTagDeclarationDefinition(method_comp_type)) - ClangASTContext::CompleteTagDeclarationDefinition(method_comp_type); + if (TypeSystemClang::StartTagDeclarationDefinition(method_comp_type)) + TypeSystemClang::CompleteTagDeclarationDefinition(method_comp_type); } AccessType access = TranslateMemberAccess(method.getAccess()); diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h index 9221d42b2020..06f317f4c4d9 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H -#define LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H #include "lldb/lldb-forward.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" class SymbolFilePDB; @@ -23,7 +23,7 @@ class RecordDecl; } // namespace clang namespace lldb_private { -class ClangASTContext; +class TypeSystemClang; class CompilerType; } // namespace lldb_private @@ -42,7 +42,7 @@ class PDBSymbolTypeUDT; class PDBASTParser { public: - PDBASTParser(lldb_private::ClangASTContext &ast); + PDBASTParser(lldb_private::TypeSystemClang &ast); ~PDBASTParser(); lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type); @@ -103,7 +103,7 @@ private: lldb_private::CompilerType &record_type, const llvm::pdb::PDBSymbolFunc &method) const; - lldb_private::ClangASTContext &m_ast; + lldb_private::TypeSystemClang &m_ast; lldb_private::ClangASTImporter m_ast_importer; CXXRecordDeclToUidMap m_forward_decl_to_uid; @@ -113,4 +113,4 @@ private: DeclContextToUidMap m_decl_context_to_uid; }; -#endif // LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp index 42bf1b34c956..330188e29f00 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp @@ -1,4 +1,4 @@ -//===-- PDBLocationToDWARFExpression.cpp ------------------------*- C++ -*-===// +//===-- PDBLocationToDWARFExpression.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h b/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h index 2e9d1386d537..fd0fef03e2c8 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Plugins_SymbolFile_PDB_PDBLocationToDWARFExpression_h_ -#define lldb_Plugins_SymbolFile_PDB_PDBLocationToDWARFExpression_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_PDBLOCATIONTODWARFEXPRESSION_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_PDBLOCATIONTODWARFEXPRESSION_H #include "lldb/Core/Module.h" #include "lldb/Symbol/Variable.h" diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index 917ab68af418..1001514edede 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -1,4 +1,4 @@ -//===-- SymbolFilePDB.cpp ---------------------------------------*- C++ -*-===// +//===-- SymbolFilePDB.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,9 +13,9 @@ #include "clang/Lex/Lexer.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" @@ -58,6 +58,8 @@ using namespace lldb; using namespace lldb_private; using namespace llvm::pdb; +LLDB_PLUGIN_DEFINE(SymbolFilePDB) + char SymbolFilePDB::ID; namespace { @@ -310,8 +312,8 @@ SymbolFilePDB::ParseCompileUnitFunctionForPDBFunc(const PDBSymbolFunc &pdb_func, return nullptr; } - ClangASTContext *clang_type_system = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + TypeSystemClang *clang_type_system = + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_type_system) return nullptr; clang_type_system->GetPDBParser()->GetDeclForSymbol(pdb_func); @@ -560,8 +562,8 @@ lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { return nullptr; } - ClangASTContext *clang_type_system = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + TypeSystemClang *clang_type_system = + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_type_system) return nullptr; PDBASTParser *pdb = clang_type_system->GetPDBParser(); @@ -597,8 +599,8 @@ bool SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) { return false; } - ClangASTContext *clang_ast_ctx = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + TypeSystemClang *clang_ast_ctx = + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_ast_ctx) return false; @@ -619,8 +621,8 @@ lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) { return CompilerDecl(); } - ClangASTContext *clang_ast_ctx = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + TypeSystemClang *clang_ast_ctx = + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_ast_ctx) return CompilerDecl(); @@ -636,7 +638,7 @@ lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) { if (!decl) return CompilerDecl(); - return CompilerDecl(clang_ast_ctx, decl); + return clang_ast_ctx->GetCompilerDecl(decl); } lldb_private::CompilerDeclContext @@ -649,8 +651,8 @@ SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) { return CompilerDeclContext(); } - ClangASTContext *clang_ast_ctx = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + TypeSystemClang *clang_ast_ctx = + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_ast_ctx) return CompilerDeclContext(); @@ -679,8 +681,8 @@ SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { return CompilerDeclContext(); } - ClangASTContext *clang_ast_ctx = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + TypeSystemClang *clang_ast_ctx = + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_ast_ctx) return CompilerDeclContext(); @@ -708,8 +710,8 @@ void SymbolFilePDB::ParseDeclsForContext( return; } - ClangASTContext *clang_ast_ctx = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + TypeSystemClang *clang_ast_ctx = + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_ast_ctx) return; @@ -1096,8 +1098,7 @@ SymbolFilePDB::ParseVariables(const lldb_private::SymbolContext &sc, } void SymbolFilePDB::FindGlobalVariables( - lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + lldb_private::ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, lldb_private::VariableList &variables) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) @@ -1129,8 +1130,8 @@ void SymbolFilePDB::FindGlobalVariables( if (sc.comp_unit == nullptr) continue; - if (parent_decl_ctx && GetDeclContextContainingUID( - result->getSymIndexId()) != *parent_decl_ctx) + if (parent_decl_ctx.IsValid() && + GetDeclContextContainingUID(result->getSymIndexId()) != parent_decl_ctx) continue; ParseVariables(sc, *pdb_data, &variables); @@ -1225,7 +1226,7 @@ void SymbolFilePDB::CacheFunctionNames() { // To search a method name, like NS::Class:MemberFunc, LLDB searches // its base name, i.e. MemberFunc by default. Since PDBSymbolFunc does - // not have inforamtion of this, we extract base names and cache them + // not have information of this, we extract base names and cache them // by our own effort. llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name); if (!basename.empty()) @@ -1294,7 +1295,7 @@ void SymbolFilePDB::CacheFunctionNames() { void SymbolFilePDB::FindFunctions( lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, FunctionNameType name_type_mask, bool include_inlines, lldb_private::SymbolContextList &sc_list) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); @@ -1323,8 +1324,8 @@ void SymbolFilePDB::FindFunctions( if (resolved_ids.find(id) != resolved_ids.end()) continue; - if (parent_decl_ctx && - GetDeclContextContainingUID(id) != *parent_decl_ctx) + if (parent_decl_ctx.IsValid() && + GetDeclContextContainingUID(id) != parent_decl_ctx) continue; if (ResolveFunction(id, include_inlines, sc_list)) @@ -1422,8 +1423,7 @@ void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) { } void SymbolFilePDB::FindTypes( - lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + 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) { @@ -1450,7 +1450,7 @@ void SymbolFilePDB::DumpClangAST(Stream &s) { } auto *clang_type_system = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_type_system) return; clang_type_system->Dump(s); @@ -1513,7 +1513,7 @@ void SymbolFilePDB::FindTypesByRegex( void SymbolFilePDB::FindTypesByName( llvm::StringRef name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, lldb_private::TypeMap &types) { std::unique_ptr<IPDBEnumSymbols> results; if (name.empty()) @@ -1548,8 +1548,8 @@ void SymbolFilePDB::FindTypesByName( if (!ResolveTypeUID(result->getSymIndexId())) continue; - if (parent_decl_ctx && GetDeclContextContainingUID( - result->getSymIndexId()) != *parent_decl_ctx) + if (parent_decl_ctx.IsValid() && + GetDeclContextContainingUID(result->getSymIndexId()) != parent_decl_ctx) continue; auto iter = m_types.find(result->getSymIndexId()); @@ -1663,17 +1663,16 @@ PDBASTParser *SymbolFilePDB::GetPDBAstParser() { } auto *clang_type_system = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_type_system) return nullptr; return clang_type_system->GetPDBParser(); } - -lldb_private::CompilerDeclContext SymbolFilePDB::FindNamespace( - lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx) { +lldb_private::CompilerDeclContext +SymbolFilePDB::FindNamespace(lldb_private::ConstString name, + const CompilerDeclContext &parent_decl_ctx) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); auto type_system_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); @@ -1685,7 +1684,7 @@ lldb_private::CompilerDeclContext SymbolFilePDB::FindNamespace( } auto *clang_type_system = - llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); + llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); if (!clang_type_system) return CompilerDeclContext(); @@ -1696,7 +1695,7 @@ lldb_private::CompilerDeclContext SymbolFilePDB::FindNamespace( clang::DeclContext *decl_context = nullptr; if (parent_decl_ctx) decl_context = static_cast<clang::DeclContext *>( - parent_decl_ctx->GetOpaqueDeclContext()); + parent_decl_ctx.GetOpaqueDeclContext()); auto namespace_decl = pdb->FindNamespaceDecl(decl_context, name.GetStringRef()); @@ -1817,7 +1816,7 @@ bool SymbolFilePDB::ParseCompileUnitLineTable(CompileUnit &comp_unit, prev_source_idx, false, false, false, false, true); line_table->InsertSequence(sequence.release()); - sequence.reset(line_table->CreateLineSequenceContainer()); + sequence = line_table->CreateLineSequenceContainer(); } if (ShouldAddLine(match_line, lno, length)) { @@ -1854,7 +1853,7 @@ bool SymbolFilePDB::ParseCompileUnitLineTable(CompileUnit &comp_unit, prev_source_idx, false, false, false, false, true); } - line_table->InsertSequence(sequence.release()); + line_table->InsertSequence(sequence.get()); } if (line_table->GetSize()) { @@ -1940,18 +1939,17 @@ SymbolFilePDB::GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func) { mangled.SetMangledName(ConstString(func_decorated_name)); // For MSVC, format of C funciton's decorated name depends on calling - // conventon. Unfortunately none of the format is recognized by current + // convention. Unfortunately none of the format is recognized by current // LLDB. For example, `_purecall` is a __cdecl C function. From PDB, // `__purecall` is retrieved as both its decorated and undecorated name // (using PDBSymbolFunc::getUndecoratedName method). However `__purecall` // string is not treated as mangled in LLDB (neither `?` nor `_Z` prefix). // Mangled::GetDemangledName method will fail internally and caches an - // empty string as its undecorated name. So we will face a contradition + // empty string as its undecorated name. So we will face a contradiction // here for the same symbol: // non-empty undecorated name from PDB // empty undecorated name from LLDB - if (!func_undecorated_name.empty() && - mangled.GetDemangledName(mangled.GuessLanguage()).IsEmpty()) + if (!func_undecorated_name.empty() && mangled.GetDemangledName().IsEmpty()) mangled.SetDemangledName(ConstString(func_undecorated_name)); // LLDB uses several flags to control how a C++ decorated name is @@ -1960,8 +1958,7 @@ SymbolFilePDB::GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func) { // PDB source unless we also apply same flags in getting undecorated // name through PDBSymbolFunc::getUndecoratedNameEx method. if (!func_undecorated_name.empty() && - mangled.GetDemangledName(mangled.GuessLanguage()) != - ConstString(func_undecorated_name)) + mangled.GetDemangledName() != ConstString(func_undecorated_name)) mangled.SetDemangledName(ConstString(func_undecorated_name)); } else if (!func_undecorated_name.empty()) { mangled.SetDemangledName(ConstString(func_undecorated_name)); @@ -1972,11 +1969,11 @@ SymbolFilePDB::GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func) { } bool SymbolFilePDB::DeclContextMatchesThisSymbolFile( - const lldb_private::CompilerDeclContext *decl_ctx) { - if (decl_ctx == nullptr || !decl_ctx->IsValid()) + const lldb_private::CompilerDeclContext &decl_ctx) { + if (!decl_ctx.IsValid()) return true; - TypeSystem *decl_ctx_type_system = decl_ctx->GetTypeSystem(); + TypeSystem *decl_ctx_type_system = decl_ctx.GetTypeSystem(); if (!decl_ctx_type_system) return false; auto type_system_or_err = GetTypeSystemForLanguage( diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h index 7a4eee48771a..928cbffc5f63 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ -#define lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_SYMBOLFILEPDB_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_SYMBOLFILEPDB_H #include "lldb/Core/UniqueCStringMap.h" #include "lldb/Symbol/SymbolFile.h" @@ -112,7 +112,7 @@ public: void FindGlobalVariables(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, lldb_private::VariableList &variables) override; @@ -121,7 +121,7 @@ public: lldb_private::VariableList &variables) override; void FindFunctions(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, lldb::FunctionNameType name_type_mask, bool include_inlines, lldb_private::SymbolContextList &sc_list) override; @@ -138,7 +138,7 @@ public: void FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; @@ -160,7 +160,7 @@ public: lldb_private::CompilerDeclContext FindNamespace( lldb_private::ConstString name, - const lldb_private::CompilerDeclContext *parent_decl_ctx) override; + const lldb_private::CompilerDeclContext &parent_decl_ctx) override; lldb_private::ConstString GetPluginName() override; @@ -195,7 +195,7 @@ private: llvm::DenseMap<uint32_t, uint32_t> &index_map) const; void FindTypesByName(llvm::StringRef name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, + const lldb_private::CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, lldb_private::TypeMap &types); std::string GetMangledForPDBData(const llvm::pdb::PDBSymbolData &pdb_data); @@ -242,7 +242,7 @@ private: void CacheFunctionNames(); bool DeclContextMatchesThisSymbolFile( - const lldb_private::CompilerDeclContext *decl_ctx); + const lldb_private::CompilerDeclContext &decl_ctx); uint32_t GetCompilandId(const llvm::pdb::PDBSymbolData &data); @@ -262,4 +262,4 @@ private: lldb_private::UniqueCStringMap<uint32_t> m_func_method_names; }; -#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_SYMBOLFILEPDB_H diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index 305efea1afab..c4a0e609aa22 100644 --- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -1,4 +1,4 @@ -//===-- SymbolFileSymtab.cpp ------------------------------------*- C++ -*-===// +//===-- SymbolFileSymtab.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -25,6 +25,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(SymbolFileSymtab) + char SymbolFileSymtab::ID; void SymbolFileSymtab::Initialize() { diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h index 1fff8188433e..9557ebbcb272 100644 --- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_SymbolFileSymtab_h_ -#define liblldb_SymbolFileSymtab_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_SYMTAB_SYMBOLFILESYMTAB_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_SYMTAB_SYMBOLFILESYMTAB_H #include <map> #include <vector> @@ -106,7 +106,8 @@ protected: TypeMap m_objc_class_types; private: - DISALLOW_COPY_AND_ASSIGN(SymbolFileSymtab); + SymbolFileSymtab(const SymbolFileSymtab &) = delete; + const SymbolFileSymtab &operator=(const SymbolFileSymtab &) = delete; }; -#endif // liblldb_SymbolFileSymtab_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_SYMTAB_SYMBOLFILESYMTAB_H diff --git a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index d4d7a8937c12..2e6fd4365021 100644 --- a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -1,4 +1,4 @@ -//===-- SymbolVendorELF.cpp ----------------------------------*- C++ -*-===// +//===-- SymbolVendorELF.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -25,6 +25,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(SymbolVendorELF) + // SymbolVendorELF constructor SymbolVendorELF::SymbolVendorELF(const lldb::ModuleSP &module_sp) : SymbolVendor(module_sp) {} diff --git a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h index 0cd740da5ce3..824906c04955 100644 --- a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h +++ b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_SymbolVendorELF_h_ -#define liblldb_SymbolVendorELF_h_ +#ifndef LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_ELF_SYMBOLVENDORELF_H +#define LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_ELF_SYMBOLVENDORELF_H #include "lldb/Symbol/SymbolVendor.h" #include "lldb/lldb-private.h" @@ -38,7 +38,8 @@ public: uint32_t GetPluginVersion() override; private: - DISALLOW_COPY_AND_ASSIGN(SymbolVendorELF); + SymbolVendorELF(const SymbolVendorELF &) = delete; + const SymbolVendorELF &operator=(const SymbolVendorELF &) = delete; }; -#endif // liblldb_SymbolVendorELF_h_ +#endif // LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_ELF_SYMBOLVENDORELF_H diff --git a/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp new file mode 100644 index 000000000000..1c09dabc5622 --- /dev/null +++ b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp @@ -0,0 +1,147 @@ +//===-- SymbolVendorWasm.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 "SymbolVendorWasm.h" + +#include <string.h> + +#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#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" +#include "lldb/Utility/Timer.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::wasm; + +LLDB_PLUGIN_DEFINE(SymbolVendorWasm) + +// SymbolVendorWasm constructor +SymbolVendorWasm::SymbolVendorWasm(const lldb::ModuleSP &module_sp) + : SymbolVendor(module_sp) {} + +void SymbolVendorWasm::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +void SymbolVendorWasm::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +lldb_private::ConstString SymbolVendorWasm::GetPluginNameStatic() { + static ConstString g_name("WASM"); + return g_name; +} + +const char *SymbolVendorWasm::GetPluginDescriptionStatic() { + return "Symbol vendor for WASM that looks for dwo files that match " + "executables."; +} + +// CreateInstance +// +// Platforms can register a callback to use when creating symbol vendors to +// allow for complex debug information file setups, and to also allow for +// finding separate debug information files. +SymbolVendor * +SymbolVendorWasm::CreateInstance(const lldb::ModuleSP &module_sp, + lldb_private::Stream *feedback_strm) { + if (!module_sp) + return nullptr; + + ObjectFileWasm *obj_file = + llvm::dyn_cast_or_null<ObjectFileWasm>(module_sp->GetObjectFile()); + if (!obj_file) + return nullptr; + + // If the main object file already contains debug info, then we are done. + if (obj_file->GetSectionList()->FindSectionByType( + lldb::eSectionTypeDWARFDebugInfo, true)) + return nullptr; + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer(func_cat, "SymbolVendorWasm::CreateInstance (module = %s)", + module_sp->GetFileSpec().GetPath().c_str()); + + ModuleSpec module_spec; + module_spec.GetFileSpec() = obj_file->GetFileSpec(); + FileSystem::Instance().Resolve(module_spec.GetFileSpec()); + module_spec.GetUUID() = obj_file->GetUUID(); + + // A Wasm module may have a custom section named "external_debug_info" whose + // content is the absolute or relative path of the Wasm module that contains + // debug symbols for this module. + llvm::Optional<FileSpec> symbol_file_spec = + obj_file->GetExternalDebugInfoFileSpec(); + if (!symbol_file_spec) + return nullptr; + module_spec.GetSymbolFileSpec() = *symbol_file_spec; + + FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); + FileSpec sym_fspec = + Symbols::LocateExecutableSymbolFile(module_spec, search_paths); + if (!sym_fspec) + return nullptr; + + DataBufferSP sym_file_data_sp; + lldb::offset_t sym_file_data_offset = 0; + ObjectFileSP sym_objfile_sp = ObjectFile::FindPlugin( + module_sp, &sym_fspec, 0, FileSystem::Instance().GetByteSize(sym_fspec), + sym_file_data_sp, sym_file_data_offset); + if (!sym_objfile_sp) + return nullptr; + + // This objfile is for debugging purposes. + sym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo); + + SymbolVendorWasm *symbol_vendor = new SymbolVendorWasm(module_sp); + + // Get the module unified section list and add our debug sections to + // that. + SectionList *module_section_list = module_sp->GetSectionList(); + SectionList *objfile_section_list = sym_objfile_sp->GetSectionList(); + + static const SectionType g_sections[] = { + eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAddr, + eSectionTypeDWARFDebugAranges, eSectionTypeDWARFDebugCuIndex, + eSectionTypeDWARFDebugFrame, eSectionTypeDWARFDebugInfo, + eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLineStr, + eSectionTypeDWARFDebugLoc, eSectionTypeDWARFDebugLocLists, + eSectionTypeDWARFDebugMacInfo, eSectionTypeDWARFDebugMacro, + eSectionTypeDWARFDebugPubNames, eSectionTypeDWARFDebugPubTypes, + eSectionTypeDWARFDebugRanges, eSectionTypeDWARFDebugRngLists, + eSectionTypeDWARFDebugStr, eSectionTypeDWARFDebugStrOffsets, + eSectionTypeDWARFDebugTypes}; + for (SectionType section_type : g_sections) { + if (SectionSP section_sp = + objfile_section_list->FindSectionByType(section_type, true)) { + if (SectionSP module_section_sp = + module_section_list->FindSectionByType(section_type, true)) + module_section_list->ReplaceSection(module_section_sp->GetID(), + section_sp); + else + module_section_list->AddSection(section_sp); + } + } + + symbol_vendor->AddSymbolFileRepresentation(sym_objfile_sp); + return symbol_vendor; +} + +// PluginInterface protocol +ConstString SymbolVendorWasm::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t SymbolVendorWasm::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h new file mode 100644 index 000000000000..96e737b1be96 --- /dev/null +++ b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h @@ -0,0 +1,45 @@ +//===-- SymbolVendorWasm.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_SYMBOLVENDOR_WASM_SYMBOLVENDORWASM_H +#define LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_WASM_SYMBOLVENDORWASM_H + +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { +namespace wasm { + +class SymbolVendorWasm : public lldb_private::SymbolVendor { +public: + SymbolVendorWasm(const lldb::ModuleSP &module_sp); + + static void Initialize(); + static void Terminate(); + static lldb_private::ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic(); + + static lldb_private::SymbolVendor * + CreateInstance(const lldb::ModuleSP &module_sp, + lldb_private::Stream *feedback_strm); + + /// PluginInterface protocol. + /// \{ + lldb_private::ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; + /// \} + +private: + SymbolVendorWasm(const SymbolVendorWasm &) = delete; + const SymbolVendorWasm &operator=(const SymbolVendorWasm &) = delete; +}; + +} // namespace wasm +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_WASM_SYMBOLVENDORWASM_H diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp new file mode 100644 index 000000000000..bc06ea8164d4 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -0,0 +1,9587 @@ +//===-- TypeSystemClang.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 "TypeSystemClang.h" + +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" + +#include <mutex> +#include <string> +#include <vector> + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTImporter.h" +#include "clang/AST/Attr.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Mangle.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "clang/AST/VTableBuilder.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LangStandard.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/ModuleMap.h" +#include "clang/Sema/Sema.h" + +#include "llvm/Support/Signals.h" +#include "llvm/Support/Threading.h" + +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" +#include "Plugins/ExpressionParser/Clang/ClangFunctionCaller.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "Plugins/ExpressionParser/Clang/ClangUserExpression.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/ExpressionParser/Clang/ClangUtilityFunction.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Flags.h" + +#include "lldb/Core/DumpDataExtractor.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/ThreadSafeDenseMap.h" +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Language.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/Scalar.h" + +#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" +#include "Plugins/SymbolFile/PDB/PDBASTParser.h" + +#include <stdio.h> + +#include <mutex> + +using namespace lldb; +using namespace lldb_private; +using namespace clang; +using llvm::StringSwitch; + +LLDB_PLUGIN_DEFINE(TypeSystemClang) + +namespace { +static void VerifyDecl(clang::Decl *decl) { + assert(decl && "VerifyDecl called with nullptr?"); +#ifndef NDEBUG + // We don't care about the actual access value here but only want to trigger + // that Clang calls its internal Decl::AccessDeclContextSanity check. + decl->getAccess(); +#endif +} + +static inline bool +TypeSystemClangSupportsLanguage(lldb::LanguageType language) { + return language == eLanguageTypeUnknown || // Clang is the default type system + lldb_private::Language::LanguageIsC(language) || + lldb_private::Language::LanguageIsCPlusPlus(language) || + lldb_private::Language::LanguageIsObjC(language) || + lldb_private::Language::LanguageIsPascal(language) || + // Use Clang for Rust until there is a proper language plugin for it + language == eLanguageTypeRust || + language == eLanguageTypeExtRenderScript || + // Use Clang for D until there is a proper language plugin for it + language == eLanguageTypeD || + // Open Dylan compiler debug info is designed to be Clang-compatible + language == eLanguageTypeDylan; +} + +// Checks whether m1 is an overload of m2 (as opposed to an override). This is +// called by addOverridesForMethod to distinguish overrides (which share a +// vtable entry) from overloads (which require distinct entries). +bool isOverload(clang::CXXMethodDecl *m1, clang::CXXMethodDecl *m2) { + // FIXME: This should detect covariant return types, but currently doesn't. + lldbassert(&m1->getASTContext() == &m2->getASTContext() && + "Methods should have the same AST context"); + clang::ASTContext &context = m1->getASTContext(); + + const auto *m1Type = llvm::cast<clang::FunctionProtoType>( + context.getCanonicalType(m1->getType())); + + const auto *m2Type = llvm::cast<clang::FunctionProtoType>( + context.getCanonicalType(m2->getType())); + + auto compareArgTypes = [&context](const clang::QualType &m1p, + const clang::QualType &m2p) { + return context.hasSameType(m1p.getUnqualifiedType(), + m2p.getUnqualifiedType()); + }; + + // FIXME: In C++14 and later, we can just pass m2Type->param_type_end() + // as a fourth parameter to std::equal(). + return (m1->getNumParams() != m2->getNumParams()) || + !std::equal(m1Type->param_type_begin(), m1Type->param_type_end(), + m2Type->param_type_begin(), compareArgTypes); +} + +// If decl is a virtual method, walk the base classes looking for methods that +// decl overrides. This table of overridden methods is used by IRGen to +// determine the vtable layout for decl's parent class. +void addOverridesForMethod(clang::CXXMethodDecl *decl) { + if (!decl->isVirtual()) + return; + + clang::CXXBasePaths paths; + + auto find_overridden_methods = + [decl](const clang::CXXBaseSpecifier *specifier, + clang::CXXBasePath &path) { + if (auto *base_record = llvm::dyn_cast<clang::CXXRecordDecl>( + specifier->getType()->getAs<clang::RecordType>()->getDecl())) { + + clang::DeclarationName name = decl->getDeclName(); + + // If this is a destructor, check whether the base class destructor is + // virtual. + if (name.getNameKind() == clang::DeclarationName::CXXDestructorName) + if (auto *baseDtorDecl = base_record->getDestructor()) { + if (baseDtorDecl->isVirtual()) { + path.Decls = baseDtorDecl; + return true; + } else + return false; + } + + // Otherwise, search for name in the base class. + for (path.Decls = base_record->lookup(name); !path.Decls.empty(); + path.Decls = path.Decls.slice(1)) { + if (auto *method_decl = + llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front())) + if (method_decl->isVirtual() && !isOverload(decl, method_decl)) { + path.Decls = method_decl; + return true; + } + } + } + + return false; + }; + + if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) { + for (auto *overridden_decl : paths.found_decls()) + decl->addOverriddenMethod( + llvm::cast<clang::CXXMethodDecl>(overridden_decl)); + } +} +} + +static lldb::addr_t GetVTableAddress(Process &process, + VTableContextBase &vtable_ctx, + ValueObject &valobj, + const ASTRecordLayout &record_layout) { + // Retrieve type info + CompilerType pointee_type; + CompilerType this_type(valobj.GetCompilerType()); + uint32_t type_info = this_type.GetTypeInfo(&pointee_type); + if (!type_info) + return LLDB_INVALID_ADDRESS; + + // Check if it's a pointer or reference + bool ptr_or_ref = false; + if (type_info & (eTypeIsPointer | eTypeIsReference)) { + ptr_or_ref = true; + type_info = pointee_type.GetTypeInfo(); + } + + // We process only C++ classes + const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus; + if ((type_info & cpp_class) != cpp_class) + return LLDB_INVALID_ADDRESS; + + // Calculate offset to VTable pointer + lldb::offset_t vbtable_ptr_offset = + vtable_ctx.isMicrosoft() ? record_layout.getVBPtrOffset().getQuantity() + : 0; + + if (ptr_or_ref) { + // We have a pointer / ref to object, so read + // VTable pointer from process memory + + if (valobj.GetAddressTypeOfChildren() != eAddressTypeLoad) + return LLDB_INVALID_ADDRESS; + + auto vbtable_ptr_addr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + if (vbtable_ptr_addr == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + vbtable_ptr_addr += vbtable_ptr_offset; + + Status err; + return process.ReadPointerFromMemory(vbtable_ptr_addr, err); + } + + // We have an object already read from process memory, + // so just extract VTable pointer from it + + DataExtractor data; + Status err; + auto size = valobj.GetData(data, err); + if (err.Fail() || vbtable_ptr_offset + data.GetAddressByteSize() > size) + return LLDB_INVALID_ADDRESS; + + return data.GetAddress(&vbtable_ptr_offset); +} + +static int64_t ReadVBaseOffsetFromVTable(Process &process, + VTableContextBase &vtable_ctx, + lldb::addr_t vtable_ptr, + const CXXRecordDecl *cxx_record_decl, + const CXXRecordDecl *base_class_decl) { + if (vtable_ctx.isMicrosoft()) { + clang::MicrosoftVTableContext &msoft_vtable_ctx = + static_cast<clang::MicrosoftVTableContext &>(vtable_ctx); + + // Get the index into the virtual base table. The + // index is the index in uint32_t from vbtable_ptr + const unsigned vbtable_index = + msoft_vtable_ctx.getVBTableIndex(cxx_record_decl, base_class_decl); + const lldb::addr_t base_offset_addr = vtable_ptr + vbtable_index * 4; + Status err; + return process.ReadSignedIntegerFromMemory(base_offset_addr, 4, INT64_MAX, + err); + } + + clang::ItaniumVTableContext &itanium_vtable_ctx = + static_cast<clang::ItaniumVTableContext &>(vtable_ctx); + + clang::CharUnits base_offset_offset = + itanium_vtable_ctx.getVirtualBaseOffsetOffset(cxx_record_decl, + base_class_decl); + const lldb::addr_t base_offset_addr = + vtable_ptr + base_offset_offset.getQuantity(); + const uint32_t base_offset_size = process.GetAddressByteSize(); + Status err; + return process.ReadSignedIntegerFromMemory(base_offset_addr, base_offset_size, + INT64_MAX, err); +} + +static bool GetVBaseBitOffset(VTableContextBase &vtable_ctx, + ValueObject &valobj, + const ASTRecordLayout &record_layout, + const CXXRecordDecl *cxx_record_decl, + const CXXRecordDecl *base_class_decl, + int32_t &bit_offset) { + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (!process) + return false; + + lldb::addr_t vtable_ptr = + GetVTableAddress(*process, vtable_ctx, valobj, record_layout); + if (vtable_ptr == LLDB_INVALID_ADDRESS) + return false; + + auto base_offset = ReadVBaseOffsetFromVTable( + *process, vtable_ctx, vtable_ptr, cxx_record_decl, base_class_decl); + if (base_offset == INT64_MAX) + return false; + + bit_offset = base_offset * 8; + + return true; +} + +typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, TypeSystemClang *> + ClangASTMap; + +static ClangASTMap &GetASTMap() { + static ClangASTMap *g_map_ptr = nullptr; + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { + g_map_ptr = new ClangASTMap(); // leaked on purpose to avoid spins + }); + return *g_map_ptr; +} + +TypePayloadClang::TypePayloadClang(OptionalClangModuleID owning_module, + bool is_complete_objc_class) + : m_payload(owning_module.GetValue()) { + SetIsCompleteObjCClass(is_complete_objc_class); +} + +void TypePayloadClang::SetOwningModule(OptionalClangModuleID id) { + assert(id.GetValue() < ObjCClassBit); + bool is_complete = IsCompleteObjCClass(); + m_payload = id.GetValue(); + SetIsCompleteObjCClass(is_complete); +} + +static void SetMemberOwningModule(clang::Decl *member, + const clang::Decl *parent) { + if (!member || !parent) + return; + + OptionalClangModuleID id(parent->getOwningModuleID()); + if (!id.HasValue()) + return; + + member->setFromASTFile(); + member->setOwningModuleID(id.GetValue()); + member->setModuleOwnershipKind(clang::Decl::ModuleOwnershipKind::Visible); + if (llvm::isa<clang::NamedDecl>(member)) + if (auto *dc = llvm::dyn_cast<clang::DeclContext>(parent)) { + dc->setHasExternalVisibleStorage(true); + // This triggers ExternalASTSource::FindExternalVisibleDeclsByName() to be + // called when searching for members. + dc->setHasExternalLexicalStorage(true); + } +} + +char TypeSystemClang::ID; + +bool TypeSystemClang::IsOperator(llvm::StringRef name, + clang::OverloadedOperatorKind &op_kind) { + // All operators have to start with "operator". + if (!name.consume_front("operator")) + return false; + + // Remember if there was a space after "operator". This is necessary to + // check for collisions with strangely named functions like "operatorint()". + bool space_after_operator = name.consume_front(" "); + + op_kind = StringSwitch<clang::OverloadedOperatorKind>(name) + .Case("+", clang::OO_Plus) + .Case("+=", clang::OO_PlusEqual) + .Case("++", clang::OO_PlusPlus) + .Case("-", clang::OO_Minus) + .Case("-=", clang::OO_MinusEqual) + .Case("--", clang::OO_MinusMinus) + .Case("->", clang::OO_Arrow) + .Case("->*", clang::OO_ArrowStar) + .Case("*", clang::OO_Star) + .Case("*=", clang::OO_StarEqual) + .Case("/", clang::OO_Slash) + .Case("/=", clang::OO_SlashEqual) + .Case("%", clang::OO_Percent) + .Case("%=", clang::OO_PercentEqual) + .Case("^", clang::OO_Caret) + .Case("^=", clang::OO_CaretEqual) + .Case("&", clang::OO_Amp) + .Case("&=", clang::OO_AmpEqual) + .Case("&&", clang::OO_AmpAmp) + .Case("|", clang::OO_Pipe) + .Case("|=", clang::OO_PipeEqual) + .Case("||", clang::OO_PipePipe) + .Case("~", clang::OO_Tilde) + .Case("!", clang::OO_Exclaim) + .Case("!=", clang::OO_ExclaimEqual) + .Case("=", clang::OO_Equal) + .Case("==", clang::OO_EqualEqual) + .Case("<", clang::OO_Less) + .Case("<<", clang::OO_LessLess) + .Case("<<=", clang::OO_LessLessEqual) + .Case("<=", clang::OO_LessEqual) + .Case(">", clang::OO_Greater) + .Case(">>", clang::OO_GreaterGreater) + .Case(">>=", clang::OO_GreaterGreaterEqual) + .Case(">=", clang::OO_GreaterEqual) + .Case("()", clang::OO_Call) + .Case("[]", clang::OO_Subscript) + .Case(",", clang::OO_Comma) + .Default(clang::NUM_OVERLOADED_OPERATORS); + + // We found a fitting operator, so we can exit now. + if (op_kind != clang::NUM_OVERLOADED_OPERATORS) + return true; + + // After the "operator " or "operator" part is something unknown. This means + // it's either one of the named operators (new/delete), a conversion operator + // (e.g. operator bool) or a function which name starts with "operator" + // (e.g. void operatorbool). + + // If it's a function that starts with operator it can't have a space after + // "operator" because identifiers can't contain spaces. + // E.g. "operator int" (conversion operator) + // vs. "operatorint" (function with colliding name). + if (!space_after_operator) + return false; // not an operator. + + // Now the operator is either one of the named operators or a conversion + // operator. + op_kind = StringSwitch<clang::OverloadedOperatorKind>(name) + .Case("new", clang::OO_New) + .Case("new[]", clang::OO_Array_New) + .Case("delete", clang::OO_Delete) + .Case("delete[]", clang::OO_Array_Delete) + // conversion operators hit this case. + .Default(clang::NUM_OVERLOADED_OPERATORS); + + return true; +} + +clang::AccessSpecifier +TypeSystemClang::ConvertAccessTypeToAccessSpecifier(AccessType access) { + switch (access) { + default: + break; + case eAccessNone: + return AS_none; + case eAccessPublic: + return AS_public; + case eAccessPrivate: + return AS_private; + case eAccessProtected: + return AS_protected; + } + return AS_none; +} + +static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { + // FIXME: Cleanup per-file based stuff. + + // Set some properties which depend solely on the input kind; it would be + // nice to move these to the language standard, and have the driver resolve + // the input kind + language standard. + if (IK.getLanguage() == clang::Language::Asm) { + Opts.AsmPreprocessor = 1; + } else if (IK.isObjectiveC()) { + Opts.ObjC = 1; + } + + LangStandard::Kind LangStd = LangStandard::lang_unspecified; + + if (LangStd == LangStandard::lang_unspecified) { + // Based on the base language, pick one. + switch (IK.getLanguage()) { + case clang::Language::Unknown: + case clang::Language::LLVM_IR: + case clang::Language::RenderScript: + llvm_unreachable("Invalid input kind!"); + case clang::Language::OpenCL: + LangStd = LangStandard::lang_opencl10; + break; + case clang::Language::CUDA: + LangStd = LangStandard::lang_cuda; + break; + case clang::Language::Asm: + case clang::Language::C: + case clang::Language::ObjC: + LangStd = LangStandard::lang_gnu99; + break; + case clang::Language::CXX: + case clang::Language::ObjCXX: + LangStd = LangStandard::lang_gnucxx98; + break; + case clang::Language::HIP: + LangStd = LangStandard::lang_hip; + break; + } + } + + const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); + Opts.LineComment = Std.hasLineComments(); + Opts.C99 = Std.isC99(); + Opts.CPlusPlus = Std.isCPlusPlus(); + Opts.CPlusPlus11 = Std.isCPlusPlus11(); + Opts.Digraphs = Std.hasDigraphs(); + Opts.GNUMode = Std.isGNUMode(); + Opts.GNUInline = !Std.isC99(); + Opts.HexFloats = Std.hasHexFloats(); + Opts.ImplicitInt = Std.hasImplicitInt(); + + Opts.WChar = true; + + // OpenCL has some additional defaults. + if (LangStd == LangStandard::lang_opencl10) { + Opts.OpenCL = 1; + Opts.AltiVec = 1; + Opts.CXXOperatorNames = 1; + Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::All); + } + + // OpenCL and C++ both have bool, true, false keywords. + Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + + Opts.setValueVisibilityMode(DefaultVisibility); + + // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs is + // specified, or -std is set to a conforming mode. + Opts.Trigraphs = !Opts.GNUMode; + Opts.CharIsSigned = ArchSpec(triple).CharIsSignedByDefault(); + Opts.OptimizeSize = 0; + + // FIXME: Eliminate this dependency. + // unsigned Opt = + // Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags); + // Opts.Optimize = Opt != 0; + unsigned Opt = 0; + + // This is the __NO_INLINE__ define, which just depends on things like the + // optimization level and -fno-inline, not actually whether the backend has + // inlining enabled. + // + // FIXME: This is affected by other options (-fno-inline). + Opts.NoInlineDefine = !Opt; + + // This is needed to allocate the extra space for the owning module + // on each decl. + Opts.ModulesLocalVisibility = 1; +} + +TypeSystemClang::TypeSystemClang(llvm::StringRef name, + llvm::Triple target_triple) { + m_display_name = name.str(); + if (!target_triple.str().empty()) + SetTargetTriple(target_triple.str()); + // The caller didn't pass an ASTContext so create a new one for this + // TypeSystemClang. + CreateASTContext(); +} + +TypeSystemClang::TypeSystemClang(llvm::StringRef name, + ASTContext &existing_ctxt) { + m_display_name = name.str(); + SetTargetTriple(existing_ctxt.getTargetInfo().getTriple().str()); + + m_ast_up.reset(&existing_ctxt); + GetASTMap().Insert(&existing_ctxt, this); +} + +// Destructor +TypeSystemClang::~TypeSystemClang() { Finalize(); } + +ConstString TypeSystemClang::GetPluginNameStatic() { + return ConstString("clang"); +} + +ConstString TypeSystemClang::GetPluginName() { + return TypeSystemClang::GetPluginNameStatic(); +} + +uint32_t TypeSystemClang::GetPluginVersion() { return 1; } + +lldb::TypeSystemSP TypeSystemClang::CreateInstance(lldb::LanguageType language, + lldb_private::Module *module, + Target *target) { + if (!TypeSystemClangSupportsLanguage(language)) + return lldb::TypeSystemSP(); + ArchSpec arch; + if (module) + arch = module->GetArchitecture(); + else if (target) + arch = target->GetArchitecture(); + + if (!arch.IsValid()) + return lldb::TypeSystemSP(); + + llvm::Triple triple = arch.GetTriple(); + // LLVM wants this to be set to iOS or MacOSX; if we're working on + // a bare-boards type image, change the triple for llvm's benefit. + if (triple.getVendor() == llvm::Triple::Apple && + triple.getOS() == llvm::Triple::UnknownOS) { + if (triple.getArch() == llvm::Triple::arm || + triple.getArch() == llvm::Triple::aarch64 || + triple.getArch() == llvm::Triple::aarch64_32 || + triple.getArch() == llvm::Triple::thumb) { + triple.setOS(llvm::Triple::IOS); + } else { + triple.setOS(llvm::Triple::MacOSX); + } + } + + if (module) { + std::string ast_name = + "ASTContext for '" + module->GetFileSpec().GetPath() + "'"; + return std::make_shared<TypeSystemClang>(ast_name, triple); + } else if (target && target->IsValid()) + return std::make_shared<TypeSystemClangForExpressions>(*target, triple); + return lldb::TypeSystemSP(); +} + +LanguageSet TypeSystemClang::GetSupportedLanguagesForTypes() { + LanguageSet languages; + languages.Insert(lldb::eLanguageTypeC89); + languages.Insert(lldb::eLanguageTypeC); + languages.Insert(lldb::eLanguageTypeC11); + languages.Insert(lldb::eLanguageTypeC_plus_plus); + languages.Insert(lldb::eLanguageTypeC99); + languages.Insert(lldb::eLanguageTypeObjC); + languages.Insert(lldb::eLanguageTypeObjC_plus_plus); + languages.Insert(lldb::eLanguageTypeC_plus_plus_03); + languages.Insert(lldb::eLanguageTypeC_plus_plus_11); + languages.Insert(lldb::eLanguageTypeC11); + languages.Insert(lldb::eLanguageTypeC_plus_plus_14); + return languages; +} + +LanguageSet TypeSystemClang::GetSupportedLanguagesForExpressions() { + LanguageSet languages; + languages.Insert(lldb::eLanguageTypeC_plus_plus); + languages.Insert(lldb::eLanguageTypeObjC_plus_plus); + languages.Insert(lldb::eLanguageTypeC_plus_plus_03); + languages.Insert(lldb::eLanguageTypeC_plus_plus_11); + languages.Insert(lldb::eLanguageTypeC_plus_plus_14); + return languages; +} + +void TypeSystemClang::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "clang base AST context plug-in", CreateInstance, + GetSupportedLanguagesForTypes(), GetSupportedLanguagesForExpressions()); +} + +void TypeSystemClang::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +void TypeSystemClang::Finalize() { + assert(m_ast_up); + GetASTMap().Erase(m_ast_up.get()); + if (!m_ast_owned) + m_ast_up.release(); + + m_builtins_up.reset(); + m_selector_table_up.reset(); + m_identifier_table_up.reset(); + m_target_info_up.reset(); + m_target_options_rp.reset(); + m_diagnostics_engine_up.reset(); + m_source_manager_up.reset(); + m_language_options_up.reset(); +} + +void TypeSystemClang::setSema(Sema *s) { + // Ensure that the new sema actually belongs to our ASTContext. + assert(s == nullptr || &s->getASTContext() == m_ast_up.get()); + m_sema = s; +} + +const char *TypeSystemClang::GetTargetTriple() { + return m_target_triple.c_str(); +} + +void TypeSystemClang::SetTargetTriple(llvm::StringRef target_triple) { + m_target_triple = target_triple.str(); +} + +void TypeSystemClang::SetExternalSource( + llvm::IntrusiveRefCntPtr<ExternalASTSource> &ast_source_up) { + ASTContext &ast = getASTContext(); + ast.setExternalSource(ast_source_up); + ast.getTranslationUnitDecl()->setHasExternalLexicalStorage(true); +} + +ASTContext &TypeSystemClang::getASTContext() { + assert(m_ast_up); + return *m_ast_up; +} + +class NullDiagnosticConsumer : public DiagnosticConsumer { +public: + NullDiagnosticConsumer() { + m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + } + + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const clang::Diagnostic &info) override { + if (m_log) { + llvm::SmallVector<char, 32> diag_str(10); + info.FormatDiagnostic(diag_str); + diag_str.push_back('\0'); + LLDB_LOGF(m_log, "Compiler diagnostic: %s\n", diag_str.data()); + } + } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new NullDiagnosticConsumer(); + } + +private: + Log *m_log; +}; + +void TypeSystemClang::CreateASTContext() { + assert(!m_ast_up); + m_ast_owned = true; + + m_language_options_up = std::make_unique<LangOptions>(); + ParseLangArgs(*m_language_options_up, clang::Language::ObjCXX, + GetTargetTriple()); + + m_identifier_table_up = + std::make_unique<IdentifierTable>(*m_language_options_up, nullptr); + m_builtins_up = std::make_unique<Builtin::Context>(); + + m_selector_table_up = std::make_unique<SelectorTable>(); + + clang::FileSystemOptions file_system_options; + m_file_manager_up = std::make_unique<clang::FileManager>( + file_system_options, FileSystem::Instance().GetVirtualFileSystem()); + + llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs()); + m_diagnostics_engine_up = + std::make_unique<DiagnosticsEngine>(diag_id_sp, new DiagnosticOptions()); + + m_source_manager_up = std::make_unique<clang::SourceManager>( + *m_diagnostics_engine_up, *m_file_manager_up); + m_ast_up = std::make_unique<ASTContext>( + *m_language_options_up, *m_source_manager_up, *m_identifier_table_up, + *m_selector_table_up, *m_builtins_up); + + m_diagnostic_consumer_up = std::make_unique<NullDiagnosticConsumer>(); + m_ast_up->getDiagnostics().setClient(m_diagnostic_consumer_up.get(), false); + + // This can be NULL if we don't know anything about the architecture or if + // the target for an architecture isn't enabled in the llvm/clang that we + // built + TargetInfo *target_info = getTargetInfo(); + if (target_info) + m_ast_up->InitBuiltinTypes(*target_info); + + GetASTMap().Insert(m_ast_up.get(), this); + + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_up( + new ClangExternalASTSourceCallbacks(*this)); + SetExternalSource(ast_source_up); +} + +TypeSystemClang *TypeSystemClang::GetASTContext(clang::ASTContext *ast) { + TypeSystemClang *clang_ast = GetASTMap().Lookup(ast); + return clang_ast; +} + +clang::MangleContext *TypeSystemClang::getMangleContext() { + if (m_mangle_ctx_up == nullptr) + m_mangle_ctx_up.reset(getASTContext().createMangleContext()); + return m_mangle_ctx_up.get(); +} + +std::shared_ptr<clang::TargetOptions> &TypeSystemClang::getTargetOptions() { + if (m_target_options_rp == nullptr && !m_target_triple.empty()) { + m_target_options_rp = std::make_shared<clang::TargetOptions>(); + if (m_target_options_rp != nullptr) + m_target_options_rp->Triple = m_target_triple; + } + return m_target_options_rp; +} + +TargetInfo *TypeSystemClang::getTargetInfo() { + // target_triple should be something like "x86_64-apple-macosx" + if (m_target_info_up == nullptr && !m_target_triple.empty()) + m_target_info_up.reset(TargetInfo::CreateTargetInfo( + getASTContext().getDiagnostics(), getTargetOptions())); + return m_target_info_up.get(); +} + +#pragma mark Basic Types + +static inline bool QualTypeMatchesBitSize(const uint64_t bit_size, + ASTContext &ast, QualType qual_type) { + uint64_t qual_type_bit_size = ast.getTypeSize(qual_type); + return qual_type_bit_size == bit_size; +} + +CompilerType +TypeSystemClang::GetBuiltinTypeForEncodingAndBitSize(Encoding encoding, + size_t bit_size) { + ASTContext &ast = getASTContext(); + switch (encoding) { + case eEncodingInvalid: + if (QualTypeMatchesBitSize(bit_size, ast, ast.VoidPtrTy)) + return GetType(ast.VoidPtrTy); + break; + + case eEncodingUint: + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) + return GetType(ast.UnsignedCharTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) + return GetType(ast.UnsignedShortTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy)) + return GetType(ast.UnsignedIntTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy)) + return GetType(ast.UnsignedLongTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy)) + return GetType(ast.UnsignedLongLongTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty)) + return GetType(ast.UnsignedInt128Ty); + break; + + case eEncodingSint: + if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy)) + return GetType(ast.SignedCharTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy)) + return GetType(ast.ShortTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy)) + return GetType(ast.IntTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.LongTy)) + return GetType(ast.LongTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy)) + return GetType(ast.LongLongTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty)) + return GetType(ast.Int128Ty); + break; + + case eEncodingIEEE754: + if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy)) + return GetType(ast.FloatTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy)) + return GetType(ast.DoubleTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy)) + return GetType(ast.LongDoubleTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy)) + return GetType(ast.HalfTy); + break; + + case eEncodingVector: + // Sanity check that bit_size is a multiple of 8's. + if (bit_size && !(bit_size & 0x7u)) + return GetType(ast.getExtVectorType(ast.UnsignedCharTy, bit_size / 8)); + break; + } + + return CompilerType(); +} + +lldb::BasicType +TypeSystemClang::GetBasicTypeEnumeration(ConstString name) { + if (name) { + typedef UniqueCStringMap<lldb::BasicType> TypeNameToBasicTypeMap; + static TypeNameToBasicTypeMap g_type_map; + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { + // "void" + g_type_map.Append(ConstString("void"), eBasicTypeVoid); + + // "char" + g_type_map.Append(ConstString("char"), eBasicTypeChar); + g_type_map.Append(ConstString("signed char"), eBasicTypeSignedChar); + g_type_map.Append(ConstString("unsigned char"), eBasicTypeUnsignedChar); + g_type_map.Append(ConstString("wchar_t"), eBasicTypeWChar); + g_type_map.Append(ConstString("signed wchar_t"), eBasicTypeSignedWChar); + g_type_map.Append(ConstString("unsigned wchar_t"), + eBasicTypeUnsignedWChar); + // "short" + g_type_map.Append(ConstString("short"), eBasicTypeShort); + g_type_map.Append(ConstString("short int"), eBasicTypeShort); + g_type_map.Append(ConstString("unsigned short"), eBasicTypeUnsignedShort); + g_type_map.Append(ConstString("unsigned short int"), + eBasicTypeUnsignedShort); + + // "int" + g_type_map.Append(ConstString("int"), eBasicTypeInt); + g_type_map.Append(ConstString("signed int"), eBasicTypeInt); + g_type_map.Append(ConstString("unsigned int"), eBasicTypeUnsignedInt); + g_type_map.Append(ConstString("unsigned"), eBasicTypeUnsignedInt); + + // "long" + g_type_map.Append(ConstString("long"), eBasicTypeLong); + g_type_map.Append(ConstString("long int"), eBasicTypeLong); + g_type_map.Append(ConstString("unsigned long"), eBasicTypeUnsignedLong); + g_type_map.Append(ConstString("unsigned long int"), + eBasicTypeUnsignedLong); + + // "long long" + g_type_map.Append(ConstString("long long"), eBasicTypeLongLong); + g_type_map.Append(ConstString("long long int"), eBasicTypeLongLong); + g_type_map.Append(ConstString("unsigned long long"), + eBasicTypeUnsignedLongLong); + g_type_map.Append(ConstString("unsigned long long int"), + eBasicTypeUnsignedLongLong); + + // "int128" + g_type_map.Append(ConstString("__int128_t"), eBasicTypeInt128); + g_type_map.Append(ConstString("__uint128_t"), eBasicTypeUnsignedInt128); + + // Miscellaneous + g_type_map.Append(ConstString("bool"), eBasicTypeBool); + g_type_map.Append(ConstString("float"), eBasicTypeFloat); + g_type_map.Append(ConstString("double"), eBasicTypeDouble); + g_type_map.Append(ConstString("long double"), eBasicTypeLongDouble); + g_type_map.Append(ConstString("id"), eBasicTypeObjCID); + g_type_map.Append(ConstString("SEL"), eBasicTypeObjCSel); + g_type_map.Append(ConstString("nullptr"), eBasicTypeNullPtr); + g_type_map.Sort(); + }); + + return g_type_map.Find(name, eBasicTypeInvalid); + } + return eBasicTypeInvalid; +} + +uint32_t TypeSystemClang::GetPointerByteSize() { + if (m_pointer_byte_size == 0) + if (auto size = GetBasicType(lldb::eBasicTypeVoid) + .GetPointerType() + .GetByteSize(nullptr)) + m_pointer_byte_size = *size; + return m_pointer_byte_size; +} + +CompilerType TypeSystemClang::GetBasicType(lldb::BasicType basic_type) { + clang::ASTContext &ast = getASTContext(); + + lldb::opaque_compiler_type_t clang_type = + GetOpaqueCompilerType(&ast, basic_type); + + if (clang_type) + return CompilerType(this, clang_type); + return CompilerType(); +} + +CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize( + llvm::StringRef type_name, uint32_t dw_ate, uint32_t bit_size) { + ASTContext &ast = getASTContext(); + + switch (dw_ate) { + default: + break; + + case DW_ATE_address: + if (QualTypeMatchesBitSize(bit_size, ast, ast.VoidPtrTy)) + return GetType(ast.VoidPtrTy); + break; + + case DW_ATE_boolean: + if (QualTypeMatchesBitSize(bit_size, ast, ast.BoolTy)) + return GetType(ast.BoolTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) + return GetType(ast.UnsignedCharTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) + return GetType(ast.UnsignedShortTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy)) + return GetType(ast.UnsignedIntTy); + break; + + case DW_ATE_lo_user: + // This has been seen to mean DW_AT_complex_integer + if (type_name.contains("complex")) { + CompilerType complex_int_clang_type = + GetBuiltinTypeForDWARFEncodingAndBitSize("int", DW_ATE_signed, + bit_size / 2); + return GetType( + ast.getComplexType(ClangUtil::GetQualType(complex_int_clang_type))); + } + break; + + case DW_ATE_complex_float: + if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatComplexTy)) + return GetType(ast.FloatComplexTy); + else if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleComplexTy)) + return GetType(ast.DoubleComplexTy); + else if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleComplexTy)) + return GetType(ast.LongDoubleComplexTy); + else { + CompilerType complex_float_clang_type = + GetBuiltinTypeForDWARFEncodingAndBitSize("float", DW_ATE_float, + bit_size / 2); + return GetType( + ast.getComplexType(ClangUtil::GetQualType(complex_float_clang_type))); + } + break; + + case DW_ATE_float: + if (type_name == "float" && + QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy)) + return GetType(ast.FloatTy); + if (type_name == "double" && + QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy)) + return GetType(ast.DoubleTy); + if (type_name == "long double" && + QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy)) + return GetType(ast.LongDoubleTy); + // Fall back to not requiring a name match + if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy)) + return GetType(ast.FloatTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy)) + return GetType(ast.DoubleTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy)) + return GetType(ast.LongDoubleTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy)) + return GetType(ast.HalfTy); + break; + + case DW_ATE_signed: + if (!type_name.empty()) { + if (type_name == "wchar_t" && + QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy) && + (getTargetInfo() && + TargetInfo::isTypeSigned(getTargetInfo()->getWCharType()))) + return GetType(ast.WCharTy); + if (type_name == "void" && + QualTypeMatchesBitSize(bit_size, ast, ast.VoidTy)) + return GetType(ast.VoidTy); + if (type_name.contains("long long") && + QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy)) + return GetType(ast.LongLongTy); + if (type_name.contains("long") && + QualTypeMatchesBitSize(bit_size, ast, ast.LongTy)) + return GetType(ast.LongTy); + if (type_name.contains("short") && + QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy)) + return GetType(ast.ShortTy); + if (type_name.contains("char")) { + if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy)) + return GetType(ast.CharTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy)) + return GetType(ast.SignedCharTy); + } + if (type_name.contains("int")) { + if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy)) + return GetType(ast.IntTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty)) + return GetType(ast.Int128Ty); + } + } + // We weren't able to match up a type name, just search by size + if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy)) + return GetType(ast.CharTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy)) + return GetType(ast.ShortTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy)) + return GetType(ast.IntTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.LongTy)) + return GetType(ast.LongTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy)) + return GetType(ast.LongLongTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty)) + return GetType(ast.Int128Ty); + break; + + case DW_ATE_signed_char: + if (ast.getLangOpts().CharIsSigned && type_name == "char") { + if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy)) + return GetType(ast.CharTy); + } + if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy)) + return GetType(ast.SignedCharTy); + break; + + case DW_ATE_unsigned: + if (!type_name.empty()) { + if (type_name == "wchar_t") { + if (QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy)) { + if (!(getTargetInfo() && + TargetInfo::isTypeSigned(getTargetInfo()->getWCharType()))) + return GetType(ast.WCharTy); + } + } + if (type_name.contains("long long")) { + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy)) + return GetType(ast.UnsignedLongLongTy); + } else if (type_name.contains("long")) { + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy)) + return GetType(ast.UnsignedLongTy); + } else if (type_name.contains("short")) { + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) + return GetType(ast.UnsignedShortTy); + } else if (type_name.contains("char")) { + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) + return GetType(ast.UnsignedCharTy); + } else if (type_name.contains("int")) { + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy)) + return GetType(ast.UnsignedIntTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty)) + return GetType(ast.UnsignedInt128Ty); + } + } + // We weren't able to match up a type name, just search by size + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) + return GetType(ast.UnsignedCharTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) + return GetType(ast.UnsignedShortTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy)) + return GetType(ast.UnsignedIntTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy)) + return GetType(ast.UnsignedLongTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy)) + return GetType(ast.UnsignedLongLongTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty)) + return GetType(ast.UnsignedInt128Ty); + break; + + case DW_ATE_unsigned_char: + if (!ast.getLangOpts().CharIsSigned && type_name == "char") { + if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy)) + return GetType(ast.CharTy); + } + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy)) + return GetType(ast.UnsignedCharTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy)) + return GetType(ast.UnsignedShortTy); + break; + + case DW_ATE_imaginary_float: + break; + + case DW_ATE_UTF: + switch (bit_size) { + case 8: + return GetType(ast.Char8Ty); + case 16: + return GetType(ast.Char16Ty); + case 32: + return GetType(ast.Char32Ty); + default: + if (!type_name.empty()) { + if (type_name == "char16_t") + return GetType(ast.Char16Ty); + if (type_name == "char32_t") + return GetType(ast.Char32Ty); + if (type_name == "char8_t") + return GetType(ast.Char8Ty); + } + } + break; + } + // This assert should fire for anything that we don't catch above so we know + // to fix any issues we run into. + if (!type_name.empty()) { + std::string type_name_str = type_name.str(); + Host::SystemLog(Host::eSystemLogError, + "error: need to add support for DW_TAG_base_type '%s' " + "encoded with DW_ATE = 0x%x, bit_size = %u\n", + type_name_str.c_str(), dw_ate, bit_size); + } else { + Host::SystemLog(Host::eSystemLogError, "error: need to add support for " + "DW_TAG_base_type encoded with " + "DW_ATE = 0x%x, bit_size = %u\n", + dw_ate, bit_size); + } + return CompilerType(); +} + +CompilerType TypeSystemClang::GetCStringType(bool is_const) { + ASTContext &ast = getASTContext(); + QualType char_type(ast.CharTy); + + if (is_const) + char_type.addConst(); + + return GetType(ast.getPointerType(char_type)); +} + +bool TypeSystemClang::AreTypesSame(CompilerType type1, CompilerType type2, + bool ignore_qualifiers) { + TypeSystemClang *ast = + llvm::dyn_cast_or_null<TypeSystemClang>(type1.GetTypeSystem()); + if (!ast || ast != type2.GetTypeSystem()) + return false; + + if (type1.GetOpaqueQualType() == type2.GetOpaqueQualType()) + return true; + + QualType type1_qual = ClangUtil::GetQualType(type1); + QualType type2_qual = ClangUtil::GetQualType(type2); + + if (ignore_qualifiers) { + type1_qual = type1_qual.getUnqualifiedType(); + type2_qual = type2_qual.getUnqualifiedType(); + } + + return ast->getASTContext().hasSameType(type1_qual, type2_qual); +} + +CompilerType TypeSystemClang::GetTypeForDecl(void *opaque_decl) { + if (!opaque_decl) + return CompilerType(); + + clang::Decl *decl = static_cast<clang::Decl *>(opaque_decl); + if (auto *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl)) + return GetTypeForDecl(named_decl); + return CompilerType(); +} + +CompilerDeclContext TypeSystemClang::CreateDeclContext(DeclContext *ctx) { + // Check that the DeclContext actually belongs to this ASTContext. + assert(&ctx->getParentASTContext() == &getASTContext()); + return CompilerDeclContext(this, ctx); +} + +CompilerType TypeSystemClang::GetTypeForDecl(clang::NamedDecl *decl) { + if (clang::ObjCInterfaceDecl *interface_decl = + llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl)) + return GetTypeForDecl(interface_decl); + if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl)) + return GetTypeForDecl(tag_decl); + return CompilerType(); +} + +CompilerType TypeSystemClang::GetTypeForDecl(TagDecl *decl) { + return GetType(getASTContext().getTagDeclType(decl)); +} + +CompilerType TypeSystemClang::GetTypeForDecl(ObjCInterfaceDecl *decl) { + return GetType(getASTContext().getObjCInterfaceType(decl)); +} + +#pragma mark Structure, Unions, Classes + +void TypeSystemClang::SetOwningModule(clang::Decl *decl, + OptionalClangModuleID owning_module) { + if (!decl || !owning_module.HasValue()) + return; + + decl->setFromASTFile(); + decl->setOwningModuleID(owning_module.GetValue()); + decl->setModuleOwnershipKind(clang::Decl::ModuleOwnershipKind::Visible); +} + +OptionalClangModuleID +TypeSystemClang::GetOrCreateClangModule(llvm::StringRef name, + OptionalClangModuleID parent, + bool is_framework, bool is_explicit) { + // Get the external AST source which holds the modules. + auto *ast_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>( + getASTContext().getExternalSource()); + assert(ast_source && "external ast source was lost"); + if (!ast_source) + return {}; + + // Lazily initialize the module map. + if (!m_header_search_up) { + auto HSOpts = std::make_shared<clang::HeaderSearchOptions>(); + m_header_search_up = std::make_unique<clang::HeaderSearch>( + HSOpts, *m_source_manager_up, *m_diagnostics_engine_up, + *m_language_options_up, m_target_info_up.get()); + m_module_map_up = std::make_unique<clang::ModuleMap>( + *m_source_manager_up, *m_diagnostics_engine_up, *m_language_options_up, + m_target_info_up.get(), *m_header_search_up); + } + + // Get or create the module context. + bool created; + clang::Module *module; + auto parent_desc = ast_source->getSourceDescriptor(parent.GetValue()); + std::tie(module, created) = m_module_map_up->findOrCreateModule( + name, parent_desc ? parent_desc->getModuleOrNull() : nullptr, + is_framework, is_explicit); + if (!created) + return ast_source->GetIDForModule(module); + + return ast_source->RegisterModule(module); +} + +CompilerType TypeSystemClang::CreateRecordType( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + AccessType access_type, llvm::StringRef name, int kind, + LanguageType language, ClangASTMetadata *metadata, bool exports_symbols) { + ASTContext &ast = getASTContext(); + + if (decl_ctx == nullptr) + decl_ctx = ast.getTranslationUnitDecl(); + + if (language == eLanguageTypeObjC || + language == eLanguageTypeObjC_plus_plus) { + bool isForwardDecl = true; + bool isInternal = false; + return CreateObjCClass(name, decl_ctx, owning_module, isForwardDecl, + isInternal, metadata); + } + + // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and + // we will need to update this code. I was told to currently always use the + // CXXRecordDecl class since we often don't know from debug information if + // something is struct or a class, so we default to always use the more + // complete definition just in case. + + bool has_name = !name.empty(); + CXXRecordDecl *decl = CXXRecordDecl::CreateDeserialized(ast, 0); + decl->setTagKind(static_cast<TagDecl::TagKind>(kind)); + decl->setDeclContext(decl_ctx); + if (has_name) + decl->setDeclName(&ast.Idents.get(name)); + SetOwningModule(decl, owning_module); + + if (!has_name) { + // In C++ a lambda is also represented as an unnamed class. This is + // different from an *anonymous class* that the user wrote: + // + // struct A { + // // anonymous class (GNU/MSVC extension) + // struct { + // int x; + // }; + // // unnamed class within a class + // struct { + // int y; + // } B; + // }; + // + // void f() { + // // unammed class outside of a class + // struct { + // int z; + // } C; + // } + // + // Anonymous classes is a GNU/MSVC extension that clang supports. It + // requires the anonymous class be embedded within a class. So the new + // heuristic verifies this condition. + if (isa<CXXRecordDecl>(decl_ctx) && exports_symbols) + decl->setAnonymousStructOrUnion(true); + } + + if (decl) { + if (metadata) + SetMetadata(decl, *metadata); + + if (access_type != eAccessNone) + decl->setAccess(ConvertAccessTypeToAccessSpecifier(access_type)); + + if (decl_ctx) + decl_ctx->addDecl(decl); + + return GetType(ast.getTagDeclType(decl)); + } + return CompilerType(); +} + +namespace { + bool IsValueParam(const clang::TemplateArgument &argument) { + return argument.getKind() == TemplateArgument::Integral; + } +} + +static TemplateParameterList *CreateTemplateParameterList( + ASTContext &ast, + const TypeSystemClang::TemplateParameterInfos &template_param_infos, + llvm::SmallVector<NamedDecl *, 8> &template_param_decls) { + const bool parameter_pack = false; + const bool is_typename = false; + const unsigned depth = 0; + const size_t num_template_params = template_param_infos.args.size(); + DeclContext *const decl_context = + ast.getTranslationUnitDecl(); // Is this the right decl context?, + for (size_t i = 0; i < num_template_params; ++i) { + const char *name = template_param_infos.names[i]; + + IdentifierInfo *identifier_info = nullptr; + if (name && name[0]) + identifier_info = &ast.Idents.get(name); + if (IsValueParam(template_param_infos.args[i])) { + QualType template_param_type = + template_param_infos.args[i].getIntegralType(); + template_param_decls.push_back(NonTypeTemplateParmDecl::Create( + ast, decl_context, SourceLocation(), SourceLocation(), depth, i, + identifier_info, template_param_type, parameter_pack, + ast.getTrivialTypeSourceInfo(template_param_type))); + } else { + template_param_decls.push_back(TemplateTypeParmDecl::Create( + ast, decl_context, SourceLocation(), SourceLocation(), depth, i, + identifier_info, is_typename, parameter_pack)); + } + } + + if (template_param_infos.packed_args) { + IdentifierInfo *identifier_info = nullptr; + if (template_param_infos.pack_name && template_param_infos.pack_name[0]) + identifier_info = &ast.Idents.get(template_param_infos.pack_name); + const bool parameter_pack_true = true; + + if (!template_param_infos.packed_args->args.empty() && + IsValueParam(template_param_infos.packed_args->args[0])) { + QualType template_param_type = + template_param_infos.packed_args->args[0].getIntegralType(); + template_param_decls.push_back(NonTypeTemplateParmDecl::Create( + ast, decl_context, SourceLocation(), SourceLocation(), depth, + num_template_params, identifier_info, template_param_type, + parameter_pack_true, + ast.getTrivialTypeSourceInfo(template_param_type))); + } else { + template_param_decls.push_back(TemplateTypeParmDecl::Create( + ast, decl_context, SourceLocation(), SourceLocation(), depth, + num_template_params, identifier_info, is_typename, + parameter_pack_true)); + } + } + clang::Expr *const requires_clause = nullptr; // TODO: Concepts + TemplateParameterList *template_param_list = TemplateParameterList::Create( + ast, SourceLocation(), SourceLocation(), template_param_decls, + SourceLocation(), requires_clause); + return template_param_list; +} + +clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + clang::FunctionDecl *func_decl, const char *name, + const TemplateParameterInfos &template_param_infos) { + // /// Create a function template node. + ASTContext &ast = getASTContext(); + + llvm::SmallVector<NamedDecl *, 8> template_param_decls; + TemplateParameterList *template_param_list = CreateTemplateParameterList( + ast, template_param_infos, template_param_decls); + FunctionTemplateDecl *func_tmpl_decl = + FunctionTemplateDecl::CreateDeserialized(ast, 0); + func_tmpl_decl->setDeclContext(decl_ctx); + func_tmpl_decl->setLocation(func_decl->getLocation()); + func_tmpl_decl->setDeclName(func_decl->getDeclName()); + func_tmpl_decl->init(func_decl, template_param_list); + SetOwningModule(func_tmpl_decl, owning_module); + + for (size_t i = 0, template_param_decl_count = template_param_decls.size(); + i < template_param_decl_count; ++i) { + // TODO: verify which decl context we should put template_param_decls into.. + template_param_decls[i]->setDeclContext(func_decl); + } + // Function templates inside a record need to have an access specifier. + // It doesn't matter what access specifier we give the template as LLDB + // anyway allows accessing everything inside a record. + if (decl_ctx->isRecord()) + func_tmpl_decl->setAccess(clang::AccessSpecifier::AS_public); + + return func_tmpl_decl; +} + +void TypeSystemClang::CreateFunctionTemplateSpecializationInfo( + FunctionDecl *func_decl, clang::FunctionTemplateDecl *func_tmpl_decl, + const TemplateParameterInfos &infos) { + TemplateArgumentList *template_args_ptr = + TemplateArgumentList::CreateCopy(func_decl->getASTContext(), infos.args); + + func_decl->setFunctionTemplateSpecialization(func_tmpl_decl, + template_args_ptr, nullptr); +} + +ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( + DeclContext *decl_ctx, OptionalClangModuleID owning_module, + lldb::AccessType access_type, const char *class_name, int kind, + const TemplateParameterInfos &template_param_infos) { + ASTContext &ast = getASTContext(); + + ClassTemplateDecl *class_template_decl = nullptr; + if (decl_ctx == nullptr) + decl_ctx = ast.getTranslationUnitDecl(); + + IdentifierInfo &identifier_info = ast.Idents.get(class_name); + DeclarationName decl_name(&identifier_info); + + clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name); + + for (NamedDecl *decl : result) { + class_template_decl = dyn_cast<clang::ClassTemplateDecl>(decl); + if (class_template_decl) + return class_template_decl; + } + + llvm::SmallVector<NamedDecl *, 8> template_param_decls; + + TemplateParameterList *template_param_list = CreateTemplateParameterList( + ast, template_param_infos, template_param_decls); + + CXXRecordDecl *template_cxx_decl = CXXRecordDecl::CreateDeserialized(ast, 0); + template_cxx_decl->setTagKind(static_cast<TagDecl::TagKind>(kind)); + // What decl context do we use here? TU? The actual decl context? + template_cxx_decl->setDeclContext(decl_ctx); + template_cxx_decl->setDeclName(decl_name); + SetOwningModule(template_cxx_decl, owning_module); + + for (size_t i = 0, template_param_decl_count = template_param_decls.size(); + i < template_param_decl_count; ++i) { + template_param_decls[i]->setDeclContext(template_cxx_decl); + } + + // With templated classes, we say that a class is templated with + // specializations, but that the bare class has no functions. + // template_cxx_decl->startDefinition(); + // template_cxx_decl->completeDefinition(); + + class_template_decl = ClassTemplateDecl::CreateDeserialized(ast, 0); + // What decl context do we use here? TU? The actual decl context? + class_template_decl->setDeclContext(decl_ctx); + class_template_decl->setDeclName(decl_name); + class_template_decl->init(template_cxx_decl, template_param_list); + template_cxx_decl->setDescribedClassTemplate(class_template_decl); + SetOwningModule(class_template_decl, owning_module); + + if (class_template_decl) { + if (access_type != eAccessNone) + class_template_decl->setAccess( + ConvertAccessTypeToAccessSpecifier(access_type)); + + decl_ctx->addDecl(class_template_decl); + + VerifyDecl(class_template_decl); + } + + return class_template_decl; +} + +TemplateTemplateParmDecl * +TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) { + ASTContext &ast = getASTContext(); + + auto *decl_ctx = ast.getTranslationUnitDecl(); + + IdentifierInfo &identifier_info = ast.Idents.get(template_name); + llvm::SmallVector<NamedDecl *, 8> template_param_decls; + + TypeSystemClang::TemplateParameterInfos template_param_infos; + TemplateParameterList *template_param_list = CreateTemplateParameterList( + ast, template_param_infos, template_param_decls); + + // LLDB needs to create those decls only to be able to display a + // type that includes a template template argument. Only the name matters for + // this purpose, so we use dummy values for the other characteristics of the + // type. + return TemplateTemplateParmDecl::Create( + ast, decl_ctx, SourceLocation(), + /*Depth*/ 0, /*Position*/ 0, + /*IsParameterPack*/ false, &identifier_info, template_param_list); +} + +ClassTemplateSpecializationDecl * +TypeSystemClang::CreateClassTemplateSpecializationDecl( + DeclContext *decl_ctx, OptionalClangModuleID owning_module, + ClassTemplateDecl *class_template_decl, int kind, + const TemplateParameterInfos &template_param_infos) { + ASTContext &ast = getASTContext(); + llvm::SmallVector<clang::TemplateArgument, 2> args( + template_param_infos.args.size() + + (template_param_infos.packed_args ? 1 : 0)); + std::copy(template_param_infos.args.begin(), template_param_infos.args.end(), + args.begin()); + if (template_param_infos.packed_args) { + args[args.size() - 1] = TemplateArgument::CreatePackCopy( + ast, template_param_infos.packed_args->args); + } + ClassTemplateSpecializationDecl *class_template_specialization_decl = + ClassTemplateSpecializationDecl::CreateDeserialized(ast, 0); + class_template_specialization_decl->setTagKind( + static_cast<TagDecl::TagKind>(kind)); + class_template_specialization_decl->setDeclContext(decl_ctx); + class_template_specialization_decl->setInstantiationOf(class_template_decl); + class_template_specialization_decl->setTemplateArgs( + TemplateArgumentList::CreateCopy(ast, args)); + ast.getTypeDeclType(class_template_specialization_decl, nullptr); + class_template_specialization_decl->setDeclName( + class_template_decl->getDeclName()); + SetOwningModule(class_template_specialization_decl, owning_module); + decl_ctx->addDecl(class_template_specialization_decl); + + class_template_specialization_decl->setSpecializationKind( + TSK_ExplicitSpecialization); + + return class_template_specialization_decl; +} + +CompilerType TypeSystemClang::CreateClassTemplateSpecializationType( + ClassTemplateSpecializationDecl *class_template_specialization_decl) { + if (class_template_specialization_decl) { + ASTContext &ast = getASTContext(); + return GetType(ast.getTagDeclType(class_template_specialization_decl)); + } + return CompilerType(); +} + +static inline bool check_op_param(bool is_method, + clang::OverloadedOperatorKind op_kind, + bool unary, bool binary, + uint32_t num_params) { + // Special-case call since it can take any number of operands + if (op_kind == OO_Call) + return true; + + // The parameter count doesn't include "this" + if (is_method) + ++num_params; + if (num_params == 1) + return unary; + if (num_params == 2) + return binary; + else + return false; +} + +bool TypeSystemClang::CheckOverloadedOperatorKindParameterCount( + bool is_method, clang::OverloadedOperatorKind op_kind, + uint32_t num_params) { + switch (op_kind) { + default: + break; + // C++ standard allows any number of arguments to new/delete + case OO_New: + case OO_Array_New: + case OO_Delete: + case OO_Array_Delete: + return true; + } + +#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ + case OO_##Name: \ + return check_op_param(is_method, op_kind, Unary, Binary, num_params); + switch (op_kind) { +#include "clang/Basic/OperatorKinds.def" + default: + break; + } + return false; +} + +clang::AccessSpecifier +TypeSystemClang::UnifyAccessSpecifiers(clang::AccessSpecifier lhs, + clang::AccessSpecifier rhs) { + // Make the access equal to the stricter of the field and the nested field's + // access + if (lhs == AS_none || rhs == AS_none) + return AS_none; + if (lhs == AS_private || rhs == AS_private) + return AS_private; + if (lhs == AS_protected || rhs == AS_protected) + return AS_protected; + return AS_public; +} + +bool TypeSystemClang::FieldIsBitfield(FieldDecl *field, + uint32_t &bitfield_bit_size) { + ASTContext &ast = getASTContext(); + if (field == nullptr) + return false; + + if (field->isBitField()) { + Expr *bit_width_expr = field->getBitWidth(); + if (bit_width_expr) { + llvm::APSInt bit_width_apsint; + if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, ast)) { + bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX); + return true; + } + } + } + return false; +} + +bool TypeSystemClang::RecordHasFields(const RecordDecl *record_decl) { + if (record_decl == nullptr) + return false; + + if (!record_decl->field_empty()) + return true; + + // No fields, lets check this is a CXX record and check the base classes + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) { + 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 CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>( + base_class->getType()->getAs<RecordType>()->getDecl()); + if (RecordHasFields(base_class_decl)) + return true; + } + } + return false; +} + +#pragma mark Objective-C Classes + +CompilerType TypeSystemClang::CreateObjCClass( + llvm::StringRef name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, bool isForwardDecl, bool isInternal, + ClangASTMetadata *metadata) { + ASTContext &ast = getASTContext(); + assert(!name.empty()); + if (!decl_ctx) + decl_ctx = ast.getTranslationUnitDecl(); + + ObjCInterfaceDecl *decl = ObjCInterfaceDecl::CreateDeserialized(ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&ast.Idents.get(name)); + /*isForwardDecl,*/ + decl->setImplicit(isInternal); + SetOwningModule(decl, owning_module); + + if (decl && metadata) + SetMetadata(decl, *metadata); + + return GetType(ast.getObjCInterfaceType(decl)); +} + +static inline bool BaseSpecifierIsEmpty(const CXXBaseSpecifier *b) { + return !TypeSystemClang::RecordHasFields(b->getType()->getAsCXXRecordDecl()); +} + +uint32_t +TypeSystemClang::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl, + bool omit_empty_base_classes) { + uint32_t num_bases = 0; + if (cxx_record_decl) { + if (omit_empty_base_classes) { + 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) { + // Skip empty base classes + if (BaseSpecifierIsEmpty(base_class)) + continue; + ++num_bases; + } + } else + num_bases = cxx_record_decl->getNumBases(); + } + return num_bases; +} + +#pragma mark Namespace Declarations + +NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( + const char *name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, bool is_inline) { + NamespaceDecl *namespace_decl = nullptr; + ASTContext &ast = getASTContext(); + TranslationUnitDecl *translation_unit_decl = ast.getTranslationUnitDecl(); + if (!decl_ctx) + decl_ctx = translation_unit_decl; + + if (name) { + IdentifierInfo &identifier_info = ast.Idents.get(name); + DeclarationName decl_name(&identifier_info); + clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name); + for (NamedDecl *decl : result) { + namespace_decl = dyn_cast<clang::NamespaceDecl>(decl); + if (namespace_decl) + return namespace_decl; + } + + namespace_decl = + NamespaceDecl::Create(ast, decl_ctx, is_inline, SourceLocation(), + SourceLocation(), &identifier_info, nullptr); + + decl_ctx->addDecl(namespace_decl); + } else { + if (decl_ctx == translation_unit_decl) { + namespace_decl = translation_unit_decl->getAnonymousNamespace(); + if (namespace_decl) + return namespace_decl; + + namespace_decl = + NamespaceDecl::Create(ast, decl_ctx, false, SourceLocation(), + SourceLocation(), nullptr, nullptr); + translation_unit_decl->setAnonymousNamespace(namespace_decl); + translation_unit_decl->addDecl(namespace_decl); + assert(namespace_decl == translation_unit_decl->getAnonymousNamespace()); + } else { + NamespaceDecl *parent_namespace_decl = cast<NamespaceDecl>(decl_ctx); + if (parent_namespace_decl) { + namespace_decl = parent_namespace_decl->getAnonymousNamespace(); + if (namespace_decl) + return namespace_decl; + namespace_decl = + NamespaceDecl::Create(ast, decl_ctx, false, SourceLocation(), + SourceLocation(), nullptr, nullptr); + parent_namespace_decl->setAnonymousNamespace(namespace_decl); + parent_namespace_decl->addDecl(namespace_decl); + assert(namespace_decl == + parent_namespace_decl->getAnonymousNamespace()); + } else { + assert(false && "GetUniqueNamespaceDeclaration called with no name and " + "no namespace as decl_ctx"); + } + } + } + // Note: namespaces can span multiple modules, so perhaps this isn't a good + // idea. + SetOwningModule(namespace_decl, owning_module); + + VerifyDecl(namespace_decl); + return namespace_decl; +} + +clang::BlockDecl * +TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx, + OptionalClangModuleID owning_module) { + if (ctx) { + clang::BlockDecl *decl = + clang::BlockDecl::CreateDeserialized(getASTContext(), 0); + decl->setDeclContext(ctx); + ctx->addDecl(decl); + SetOwningModule(decl, owning_module); + return decl; + } + return nullptr; +} + +clang::DeclContext *FindLCABetweenDecls(clang::DeclContext *left, + clang::DeclContext *right, + clang::DeclContext *root) { + if (root == nullptr) + return nullptr; + + std::set<clang::DeclContext *> path_left; + for (clang::DeclContext *d = left; d != nullptr; d = d->getParent()) + path_left.insert(d); + + for (clang::DeclContext *d = right; d != nullptr; d = d->getParent()) + if (path_left.find(d) != path_left.end()) + return d; + + return nullptr; +} + +clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + clang::NamespaceDecl *ns_decl) { + if (decl_ctx && ns_decl) { + auto *translation_unit = getASTContext().getTranslationUnitDecl(); + clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create( + getASTContext(), decl_ctx, clang::SourceLocation(), + clang::SourceLocation(), clang::NestedNameSpecifierLoc(), + clang::SourceLocation(), ns_decl, + FindLCABetweenDecls(decl_ctx, ns_decl, + translation_unit)); + decl_ctx->addDecl(using_decl); + SetOwningModule(using_decl, owning_module); + return using_decl; + } + return nullptr; +} + +clang::UsingDecl * +TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, + OptionalClangModuleID owning_module, + clang::NamedDecl *target) { + if (current_decl_ctx && target) { + clang::UsingDecl *using_decl = clang::UsingDecl::Create( + getASTContext(), current_decl_ctx, clang::SourceLocation(), + clang::NestedNameSpecifierLoc(), clang::DeclarationNameInfo(), false); + SetOwningModule(using_decl, owning_module); + clang::UsingShadowDecl *shadow_decl = clang::UsingShadowDecl::Create( + getASTContext(), current_decl_ctx, clang::SourceLocation(), using_decl, + target); + SetOwningModule(shadow_decl, owning_module); + using_decl->addShadowDecl(shadow_decl); + current_decl_ctx->addDecl(using_decl); + return using_decl; + } + return nullptr; +} + +clang::VarDecl *TypeSystemClang::CreateVariableDeclaration( + clang::DeclContext *decl_context, OptionalClangModuleID owning_module, + const char *name, clang::QualType type) { + if (decl_context) { + clang::VarDecl *var_decl = + clang::VarDecl::CreateDeserialized(getASTContext(), 0); + var_decl->setDeclContext(decl_context); + if (name && name[0]) + var_decl->setDeclName(&getASTContext().Idents.getOwn(name)); + var_decl->setType(type); + SetOwningModule(var_decl, owning_module); + var_decl->setAccess(clang::AS_public); + decl_context->addDecl(var_decl); + return var_decl; + } + return nullptr; +} + +lldb::opaque_compiler_type_t +TypeSystemClang::GetOpaqueCompilerType(clang::ASTContext *ast, + lldb::BasicType basic_type) { + switch (basic_type) { + case eBasicTypeVoid: + return ast->VoidTy.getAsOpaquePtr(); + case eBasicTypeChar: + return ast->CharTy.getAsOpaquePtr(); + case eBasicTypeSignedChar: + return ast->SignedCharTy.getAsOpaquePtr(); + case eBasicTypeUnsignedChar: + return ast->UnsignedCharTy.getAsOpaquePtr(); + case eBasicTypeWChar: + return ast->getWCharType().getAsOpaquePtr(); + case eBasicTypeSignedWChar: + return ast->getSignedWCharType().getAsOpaquePtr(); + case eBasicTypeUnsignedWChar: + return ast->getUnsignedWCharType().getAsOpaquePtr(); + case eBasicTypeChar16: + return ast->Char16Ty.getAsOpaquePtr(); + case eBasicTypeChar32: + return ast->Char32Ty.getAsOpaquePtr(); + case eBasicTypeShort: + return ast->ShortTy.getAsOpaquePtr(); + case eBasicTypeUnsignedShort: + return ast->UnsignedShortTy.getAsOpaquePtr(); + case eBasicTypeInt: + return ast->IntTy.getAsOpaquePtr(); + case eBasicTypeUnsignedInt: + return ast->UnsignedIntTy.getAsOpaquePtr(); + case eBasicTypeLong: + return ast->LongTy.getAsOpaquePtr(); + case eBasicTypeUnsignedLong: + return ast->UnsignedLongTy.getAsOpaquePtr(); + case eBasicTypeLongLong: + return ast->LongLongTy.getAsOpaquePtr(); + case eBasicTypeUnsignedLongLong: + return ast->UnsignedLongLongTy.getAsOpaquePtr(); + case eBasicTypeInt128: + return ast->Int128Ty.getAsOpaquePtr(); + case eBasicTypeUnsignedInt128: + return ast->UnsignedInt128Ty.getAsOpaquePtr(); + case eBasicTypeBool: + return ast->BoolTy.getAsOpaquePtr(); + case eBasicTypeHalf: + return ast->HalfTy.getAsOpaquePtr(); + case eBasicTypeFloat: + return ast->FloatTy.getAsOpaquePtr(); + case eBasicTypeDouble: + return ast->DoubleTy.getAsOpaquePtr(); + case eBasicTypeLongDouble: + return ast->LongDoubleTy.getAsOpaquePtr(); + case eBasicTypeFloatComplex: + return ast->FloatComplexTy.getAsOpaquePtr(); + case eBasicTypeDoubleComplex: + return ast->DoubleComplexTy.getAsOpaquePtr(); + case eBasicTypeLongDoubleComplex: + return ast->LongDoubleComplexTy.getAsOpaquePtr(); + case eBasicTypeObjCID: + return ast->getObjCIdType().getAsOpaquePtr(); + case eBasicTypeObjCClass: + return ast->getObjCClassType().getAsOpaquePtr(); + case eBasicTypeObjCSel: + return ast->getObjCSelType().getAsOpaquePtr(); + case eBasicTypeNullPtr: + return ast->NullPtrTy.getAsOpaquePtr(); + default: + return nullptr; + } +} + +#pragma mark Function Types + +clang::DeclarationName +TypeSystemClang::GetDeclarationName(const char *name, + const CompilerType &function_clang_type) { + if (!name || !name[0]) + return clang::DeclarationName(); + + clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; + if (!IsOperator(name, op_kind) || op_kind == clang::NUM_OVERLOADED_OPERATORS) + return DeclarationName(&getASTContext().Idents.get( + name)); // Not operator, but a regular function. + + // Check the number of operator parameters. Sometimes we have seen bad DWARF + // that doesn't correctly describe operators and if we try to create a method + // and add it to the class, clang will assert and crash, so we need to make + // sure things are acceptable. + clang::QualType method_qual_type(ClangUtil::GetQualType(function_clang_type)); + const clang::FunctionProtoType *function_type = + llvm::dyn_cast<clang::FunctionProtoType>(method_qual_type.getTypePtr()); + if (function_type == nullptr) + return clang::DeclarationName(); + + const bool is_method = false; + const unsigned int num_params = function_type->getNumParams(); + if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount( + is_method, op_kind, num_params)) + return clang::DeclarationName(); + + return getASTContext().DeclarationNames.getCXXOperatorName(op_kind); +} + +FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + const char *name, const CompilerType &function_clang_type, int storage, + bool is_inline) { + FunctionDecl *func_decl = nullptr; + ASTContext &ast = getASTContext(); + if (!decl_ctx) + decl_ctx = ast.getTranslationUnitDecl(); + + const bool hasWrittenPrototype = true; + const bool isConstexprSpecified = false; + + clang::DeclarationName declarationName = + GetDeclarationName(name, function_clang_type); + func_decl = FunctionDecl::CreateDeserialized(ast, 0); + func_decl->setDeclContext(decl_ctx); + func_decl->setDeclName(declarationName); + func_decl->setType(ClangUtil::GetQualType(function_clang_type)); + func_decl->setStorageClass(static_cast<clang::StorageClass>(storage)); + func_decl->setInlineSpecified(is_inline); + func_decl->setHasWrittenPrototype(hasWrittenPrototype); + func_decl->setConstexprKind(isConstexprSpecified ? CSK_constexpr + : CSK_unspecified); + SetOwningModule(func_decl, owning_module); + if (func_decl) + decl_ctx->addDecl(func_decl); + + VerifyDecl(func_decl); + + return func_decl; +} + +CompilerType +TypeSystemClang::CreateFunctionType(const CompilerType &result_type, + const CompilerType *args, unsigned num_args, + bool is_variadic, unsigned type_quals, + clang::CallingConv cc) { + if (!result_type || !ClangUtil::IsClangType(result_type)) + return CompilerType(); // invalid return type + + std::vector<QualType> qual_type_args; + if (num_args > 0 && args == nullptr) + return CompilerType(); // invalid argument array passed in + + // Verify that all arguments are valid and the right type + for (unsigned i = 0; i < num_args; ++i) { + if (args[i]) { + // Make sure we have a clang type in args[i] and not a type from another + // language whose name might match + const bool is_clang_type = ClangUtil::IsClangType(args[i]); + lldbassert(is_clang_type); + if (is_clang_type) + qual_type_args.push_back(ClangUtil::GetQualType(args[i])); + else + return CompilerType(); // invalid argument type (must be a clang type) + } else + return CompilerType(); // invalid argument type (empty) + } + + // TODO: Detect calling convention in DWARF? + FunctionProtoType::ExtProtoInfo proto_info; + proto_info.ExtInfo = cc; + proto_info.Variadic = is_variadic; + proto_info.ExceptionSpec = EST_None; + proto_info.TypeQuals = clang::Qualifiers::fromFastMask(type_quals); + proto_info.RefQualifier = RQ_None; + + return GetType(getASTContext().getFunctionType( + ClangUtil::GetQualType(result_type), qual_type_args, proto_info)); +} + +ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + const char *name, const CompilerType ¶m_type, int storage, + bool add_decl) { + ASTContext &ast = getASTContext(); + auto *decl = ParmVarDecl::CreateDeserialized(ast, 0); + decl->setDeclContext(decl_ctx); + if (name && name[0]) + decl->setDeclName(&ast.Idents.get(name)); + decl->setType(ClangUtil::GetQualType(param_type)); + decl->setStorageClass(static_cast<clang::StorageClass>(storage)); + SetOwningModule(decl, owning_module); + if (add_decl) + decl_ctx->addDecl(decl); + + return decl; +} + +void TypeSystemClang::SetFunctionParameters(FunctionDecl *function_decl, + ParmVarDecl **params, + unsigned num_params) { + if (function_decl) + function_decl->setParams(ArrayRef<ParmVarDecl *>(params, num_params)); +} + +CompilerType +TypeSystemClang::CreateBlockPointerType(const CompilerType &function_type) { + QualType block_type = m_ast_up->getBlockPointerType( + clang::QualType::getFromOpaquePtr(function_type.GetOpaqueQualType())); + + return GetType(block_type); +} + +#pragma mark Array Types + +CompilerType TypeSystemClang::CreateArrayType(const CompilerType &element_type, + size_t element_count, + bool is_vector) { + if (element_type.IsValid()) { + ASTContext &ast = getASTContext(); + + if (is_vector) { + return GetType(ast.getExtVectorType(ClangUtil::GetQualType(element_type), + element_count)); + } else { + + llvm::APInt ap_element_count(64, element_count); + if (element_count == 0) { + return GetType(ast.getIncompleteArrayType( + ClangUtil::GetQualType(element_type), clang::ArrayType::Normal, 0)); + } else { + return GetType(ast.getConstantArrayType( + ClangUtil::GetQualType(element_type), ap_element_count, nullptr, + clang::ArrayType::Normal, 0)); + } + } + } + return CompilerType(); +} + +CompilerType TypeSystemClang::CreateStructForIdentifier( + ConstString type_name, + const std::initializer_list<std::pair<const char *, CompilerType>> + &type_fields, + bool packed) { + CompilerType type; + if (!type_name.IsEmpty() && + (type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)) + .IsValid()) { + lldbassert(0 && "Trying to create a type for an existing name"); + return type; + } + + type = CreateRecordType(nullptr, OptionalClangModuleID(), lldb::eAccessPublic, + type_name.GetCString(), clang::TTK_Struct, + lldb::eLanguageTypeC); + StartTagDeclarationDefinition(type); + for (const auto &field : type_fields) + AddFieldToRecordType(type, field.first, field.second, lldb::eAccessPublic, + 0); + if (packed) + SetIsPacked(type); + CompleteTagDeclarationDefinition(type); + return type; +} + +CompilerType TypeSystemClang::GetOrCreateStructForIdentifier( + ConstString type_name, + const std::initializer_list<std::pair<const char *, CompilerType>> + &type_fields, + bool packed) { + CompilerType type; + if ((type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)).IsValid()) + return type; + + return CreateStructForIdentifier(type_name, type_fields, packed); +} + +#pragma mark Enumeration Types + +CompilerType TypeSystemClang::CreateEnumerationType( + const char *name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, const Declaration &decl, + const CompilerType &integer_clang_type, bool is_scoped) { + // TODO: Do something intelligent with the Declaration object passed in + // like maybe filling in the SourceLocation with it... + ASTContext &ast = getASTContext(); + + // TODO: ask about these... + // const bool IsFixed = false; + EnumDecl *enum_decl = EnumDecl::CreateDeserialized(ast, 0); + enum_decl->setDeclContext(decl_ctx); + if (name && name[0]) + enum_decl->setDeclName(&ast.Idents.get(name)); + enum_decl->setScoped(is_scoped); + enum_decl->setScopedUsingClassTag(is_scoped); + enum_decl->setFixed(false); + SetOwningModule(enum_decl, owning_module); + if (enum_decl) { + if (decl_ctx) + decl_ctx->addDecl(enum_decl); + + // TODO: check if we should be setting the promotion type too? + enum_decl->setIntegerType(ClangUtil::GetQualType(integer_clang_type)); + + enum_decl->setAccess(AS_public); // TODO respect what's in the debug info + + return GetType(ast.getTagDeclType(enum_decl)); + } + return CompilerType(); +} + +CompilerType TypeSystemClang::GetIntTypeFromBitSize(size_t bit_size, + bool is_signed) { + clang::ASTContext &ast = getASTContext(); + + if (is_signed) { + if (bit_size == ast.getTypeSize(ast.SignedCharTy)) + return GetType(ast.SignedCharTy); + + if (bit_size == ast.getTypeSize(ast.ShortTy)) + return GetType(ast.ShortTy); + + if (bit_size == ast.getTypeSize(ast.IntTy)) + return GetType(ast.IntTy); + + if (bit_size == ast.getTypeSize(ast.LongTy)) + return GetType(ast.LongTy); + + if (bit_size == ast.getTypeSize(ast.LongLongTy)) + return GetType(ast.LongLongTy); + + if (bit_size == ast.getTypeSize(ast.Int128Ty)) + return GetType(ast.Int128Ty); + } else { + if (bit_size == ast.getTypeSize(ast.UnsignedCharTy)) + return GetType(ast.UnsignedCharTy); + + if (bit_size == ast.getTypeSize(ast.UnsignedShortTy)) + return GetType(ast.UnsignedShortTy); + + if (bit_size == ast.getTypeSize(ast.UnsignedIntTy)) + return GetType(ast.UnsignedIntTy); + + if (bit_size == ast.getTypeSize(ast.UnsignedLongTy)) + return GetType(ast.UnsignedLongTy); + + if (bit_size == ast.getTypeSize(ast.UnsignedLongLongTy)) + return GetType(ast.UnsignedLongLongTy); + + if (bit_size == ast.getTypeSize(ast.UnsignedInt128Ty)) + return GetType(ast.UnsignedInt128Ty); + } + return CompilerType(); +} + +CompilerType TypeSystemClang::GetPointerSizedIntType(bool is_signed) { + return GetIntTypeFromBitSize( + getASTContext().getTypeSize(getASTContext().VoidPtrTy), is_signed); +} + +void TypeSystemClang::DumpDeclContextHiearchy(clang::DeclContext *decl_ctx) { + if (decl_ctx) { + DumpDeclContextHiearchy(decl_ctx->getParent()); + + clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl_ctx); + if (named_decl) { + printf("%20s: %s\n", decl_ctx->getDeclKindName(), + named_decl->getDeclName().getAsString().c_str()); + } else { + printf("%20s\n", decl_ctx->getDeclKindName()); + } + } +} + +void TypeSystemClang::DumpDeclHiearchy(clang::Decl *decl) { + if (decl == nullptr) + return; + DumpDeclContextHiearchy(decl->getDeclContext()); + + clang::RecordDecl *record_decl = llvm::dyn_cast<clang::RecordDecl>(decl); + if (record_decl) { + printf("%20s: %s%s\n", decl->getDeclKindName(), + record_decl->getDeclName().getAsString().c_str(), + record_decl->isInjectedClassName() ? " (injected class name)" : ""); + + } else { + clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl); + if (named_decl) { + printf("%20s: %s\n", decl->getDeclKindName(), + named_decl->getDeclName().getAsString().c_str()); + } else { + printf("%20s\n", decl->getDeclKindName()); + } + } +} + +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) + return false; + + ExternalASTSource *ast_source = ast->getExternalSource(); + + if (!ast_source) + return false; + + if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl)) { + if (tag_decl->isCompleteDefinition()) + return true; + + if (!tag_decl->hasExternalLexicalStorage()) + return false; + + ast_source->CompleteType(tag_decl); + + return !tag_decl->getTypeForDecl()->isIncompleteType(); + } else if (clang::ObjCInterfaceDecl *objc_interface_decl = + llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl)) { + if (objc_interface_decl->getDefinition()) + return true; + + if (!objc_interface_decl->hasExternalLexicalStorage()) + return false; + + ast_source->CompleteType(objc_interface_decl); + + return !objc_interface_decl->getTypeForDecl()->isIncompleteType(); + } else { + return false; + } +} + +void TypeSystemClang::SetMetadataAsUserID(const clang::Decl *decl, + user_id_t user_id) { + ClangASTMetadata meta_data; + meta_data.SetUserID(user_id); + SetMetadata(decl, meta_data); +} + +void TypeSystemClang::SetMetadataAsUserID(const clang::Type *type, + user_id_t user_id) { + ClangASTMetadata meta_data; + meta_data.SetUserID(user_id); + SetMetadata(type, meta_data); +} + +void TypeSystemClang::SetMetadata(const clang::Decl *object, + ClangASTMetadata &metadata) { + m_decl_metadata[object] = metadata; +} + +void TypeSystemClang::SetMetadata(const clang::Type *object, + ClangASTMetadata &metadata) { + m_type_metadata[object] = metadata; +} + +ClangASTMetadata *TypeSystemClang::GetMetadata(const clang::Decl *object) { + auto It = m_decl_metadata.find(object); + if (It != m_decl_metadata.end()) + return &It->second; + return nullptr; +} + +ClangASTMetadata *TypeSystemClang::GetMetadata(const clang::Type *object) { + auto It = m_type_metadata.find(object); + if (It != m_type_metadata.end()) + return &It->second; + return nullptr; +} + +bool TypeSystemClang::SetTagTypeKind(clang::QualType tag_qual_type, + int kind) const { + const clang::Type *clang_type = tag_qual_type.getTypePtr(); + if (clang_type) { + const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(clang_type); + if (tag_type) { + clang::TagDecl *tag_decl = + llvm::dyn_cast<clang::TagDecl>(tag_type->getDecl()); + if (tag_decl) { + tag_decl->setTagKind((clang::TagDecl::TagKind)kind); + return true; + } + } + } + return false; +} + +bool TypeSystemClang::SetDefaultAccessForRecordFields( + clang::RecordDecl *record_decl, int default_accessibility, + int *assigned_accessibilities, size_t num_assigned_accessibilities) { + if (record_decl) { + uint32_t field_idx; + clang::RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), + field_end = record_decl->field_end(), field_idx = 0; + field != field_end; ++field, ++field_idx) { + // If no accessibility was assigned, assign the correct one + if (field_idx < num_assigned_accessibilities && + assigned_accessibilities[field_idx] == clang::AS_none) + field->setAccess((clang::AccessSpecifier)default_accessibility); + } + return true; + } + return false; +} + +clang::DeclContext * +TypeSystemClang::GetDeclContextForType(const CompilerType &type) { + return GetDeclContextForType(ClangUtil::GetQualType(type)); +} + +/// 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, +/// when one wishes to handle a certain kind of type directly. +static QualType +RemoveWrappingTypes(QualType type, ArrayRef<clang::Type::TypeClass> mask = {}) { + while (true) { + if (find(mask, type->getTypeClass()) != mask.end()) + return type; + switch (type->getTypeClass()) { + // This is not fully correct as _Atomic is more than sugar, but it is + // sufficient for the purposes we care about. + case clang::Type::Atomic: + type = cast<clang::AtomicType>(type)->getValueType(); + break; + case clang::Type::Auto: + case clang::Type::Decltype: + case clang::Type::Elaborated: + case clang::Type::Paren: + case clang::Type::Typedef: + case clang::Type::TypeOf: + case clang::Type::TypeOfExpr: + type = type->getLocallyUnqualifiedSingleStepDesugaredType(); + break; + default: + return type; + } + } +} + +clang::DeclContext * +TypeSystemClang::GetDeclContextForType(clang::QualType type) { + if (type.isNull()) + return nullptr; + + clang::QualType qual_type = RemoveWrappingTypes(type.getCanonicalType()); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::ObjCInterface: + return llvm::cast<clang::ObjCObjectType>(qual_type.getTypePtr()) + ->getInterface(); + case clang::Type::ObjCObjectPointer: + return GetDeclContextForType( + llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr()) + ->getPointeeType()); + case clang::Type::Record: + return llvm::cast<clang::RecordType>(qual_type)->getDecl(); + case clang::Type::Enum: + return llvm::cast<clang::EnumType>(qual_type)->getDecl(); + default: + break; + } + // No DeclContext in this type... + return nullptr; +} + +static bool GetCompleteQualType(clang::ASTContext *ast, + clang::QualType qual_type, + bool allow_completion = true) { + qual_type = RemoveWrappingTypes(qual_type); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::ConstantArray: + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: { + const clang::ArrayType *array_type = + llvm::dyn_cast<clang::ArrayType>(qual_type.getTypePtr()); + + if (array_type) + return GetCompleteQualType(ast, array_type->getElementType(), + allow_completion); + } break; + case clang::Type::Record: { + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + if (cxx_record_decl->hasExternalLexicalStorage()) { + const bool is_complete = cxx_record_decl->isCompleteDefinition(); + const bool fields_loaded = + cxx_record_decl->hasLoadedFieldsFromExternalStorage(); + if (is_complete && fields_loaded) + return true; + + if (!allow_completion) + return false; + + // Call the field_begin() accessor to for it to use the external source + // to load the fields... + clang::ExternalASTSource *external_ast_source = + ast->getExternalSource(); + if (external_ast_source) { + external_ast_source->CompleteType(cxx_record_decl); + if (cxx_record_decl->isCompleteDefinition()) { + cxx_record_decl->field_begin(); + cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true); + } + } + } + } + const clang::TagType *tag_type = + llvm::cast<clang::TagType>(qual_type.getTypePtr()); + return !tag_type->isIncompleteType(); + } break; + + case clang::Type::Enum: { + const clang::TagType *tag_type = + llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr()); + if (tag_type) { + clang::TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) { + if (tag_decl->getDefinition()) + return true; + + if (!allow_completion) + return false; + + if (tag_decl->hasExternalLexicalStorage()) { + if (ast) { + clang::ExternalASTSource *external_ast_source = + ast->getExternalSource(); + if (external_ast_source) { + external_ast_source->CompleteType(tag_decl); + return !tag_type->isIncompleteType(); + } + } + } + return false; + } + } + + } break; + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added + // ASTContext because it only supports TagDecl objects right now... + if (class_interface_decl) { + if (class_interface_decl->getDefinition()) + return true; + + if (!allow_completion) + return false; + + if (class_interface_decl->hasExternalLexicalStorage()) { + if (ast) { + clang::ExternalASTSource *external_ast_source = + ast->getExternalSource(); + if (external_ast_source) { + external_ast_source->CompleteType(class_interface_decl); + return !objc_class_type->isIncompleteType(); + } + } + } + return false; + } + } + } break; + + case clang::Type::Attributed: + return GetCompleteQualType( + ast, llvm::cast<clang::AttributedType>(qual_type)->getModifiedType(), + allow_completion); + + default: + break; + } + + return true; +} + +static clang::ObjCIvarDecl::AccessControl +ConvertAccessTypeToObjCIvarAccessControl(AccessType access) { + switch (access) { + case eAccessNone: + return clang::ObjCIvarDecl::None; + case eAccessPublic: + return clang::ObjCIvarDecl::Public; + case eAccessPrivate: + return clang::ObjCIvarDecl::Private; + case eAccessProtected: + return clang::ObjCIvarDecl::Protected; + case eAccessPackage: + return clang::ObjCIvarDecl::Package; + } + return clang::ObjCIvarDecl::None; +} + +// Tests + +#ifndef NDEBUG +bool TypeSystemClang::Verify(lldb::opaque_compiler_type_t type) { + return !type || llvm::isa<clang::Type>(GetQualType(type).getTypePtr()); +} +#endif + +bool TypeSystemClang::IsAggregateType(lldb::opaque_compiler_type_t type) { + clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + case clang::Type::ConstantArray: + case clang::Type::ExtVector: + case clang::Type::Vector: + case clang::Type::Record: + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + return true; + default: + break; + } + // The clang type does have a value + return false; +} + +bool TypeSystemClang::IsAnonymousType(lldb::opaque_compiler_type_t type) { + clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: { + if (const clang::RecordType *record_type = + llvm::dyn_cast_or_null<clang::RecordType>( + qual_type.getTypePtrOrNull())) { + if (const clang::RecordDecl *record_decl = record_type->getDecl()) { + return record_decl->isAnonymousStructOrUnion(); + } + } + break; + } + default: + break; + } + // The clang type does have a value + return false; +} + +bool TypeSystemClang::IsArrayType(lldb::opaque_compiler_type_t type, + CompilerType *element_type_ptr, + uint64_t *size, bool *is_incomplete) { + clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + default: + break; + + case clang::Type::ConstantArray: + if (element_type_ptr) + element_type_ptr->SetCompilerType( + this, llvm::cast<clang::ConstantArrayType>(qual_type) + ->getElementType() + .getAsOpaquePtr()); + if (size) + *size = llvm::cast<clang::ConstantArrayType>(qual_type) + ->getSize() + .getLimitedValue(ULLONG_MAX); + if (is_incomplete) + *is_incomplete = false; + return true; + + case clang::Type::IncompleteArray: + if (element_type_ptr) + element_type_ptr->SetCompilerType( + this, llvm::cast<clang::IncompleteArrayType>(qual_type) + ->getElementType() + .getAsOpaquePtr()); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = true; + return true; + + case clang::Type::VariableArray: + if (element_type_ptr) + element_type_ptr->SetCompilerType( + this, llvm::cast<clang::VariableArrayType>(qual_type) + ->getElementType() + .getAsOpaquePtr()); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = false; + return true; + + case clang::Type::DependentSizedArray: + if (element_type_ptr) + element_type_ptr->SetCompilerType( + this, llvm::cast<clang::DependentSizedArrayType>(qual_type) + ->getElementType() + .getAsOpaquePtr()); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = false; + return true; + } + if (element_type_ptr) + element_type_ptr->Clear(); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = false; + return false; +} + +bool TypeSystemClang::IsVectorType(lldb::opaque_compiler_type_t type, + CompilerType *element_type, uint64_t *size) { + clang::QualType qual_type(GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Vector: { + const clang::VectorType *vector_type = + qual_type->getAs<clang::VectorType>(); + if (vector_type) { + if (size) + *size = vector_type->getNumElements(); + if (element_type) + *element_type = GetType(vector_type->getElementType()); + } + return true; + } break; + case clang::Type::ExtVector: { + const clang::ExtVectorType *ext_vector_type = + qual_type->getAs<clang::ExtVectorType>(); + if (ext_vector_type) { + if (size) + *size = ext_vector_type->getNumElements(); + if (element_type) + *element_type = + CompilerType(this, ext_vector_type->getElementType().getAsOpaquePtr()); + } + return true; + } + default: + break; + } + return false; +} + +bool TypeSystemClang::IsRuntimeGeneratedType( + lldb::opaque_compiler_type_t type) { + clang::DeclContext *decl_ctx = GetDeclContextForType(GetQualType(type)); + if (!decl_ctx) + return false; + + if (!llvm::isa<clang::ObjCInterfaceDecl>(decl_ctx)) + return false; + + clang::ObjCInterfaceDecl *result_iface_decl = + llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx); + + ClangASTMetadata *ast_metadata = GetMetadata(result_iface_decl); + if (!ast_metadata) + return false; + return (ast_metadata->GetISAPtr() != 0); +} + +bool TypeSystemClang::IsCharType(lldb::opaque_compiler_type_t type) { + return GetQualType(type).getUnqualifiedType()->isCharType(); +} + +bool TypeSystemClang::IsCompleteType(lldb::opaque_compiler_type_t type) { + const bool allow_completion = false; + return GetCompleteQualType(&getASTContext(), GetQualType(type), + allow_completion); +} + +bool TypeSystemClang::IsConst(lldb::opaque_compiler_type_t type) { + return GetQualType(type).isConstQualified(); +} + +bool TypeSystemClang::IsCStringType(lldb::opaque_compiler_type_t type, + uint32_t &length) { + CompilerType pointee_or_element_clang_type; + length = 0; + Flags type_flags(GetTypeInfo(type, &pointee_or_element_clang_type)); + + if (!pointee_or_element_clang_type.IsValid()) + return false; + + if (type_flags.AnySet(eTypeIsArray | eTypeIsPointer)) { + if (pointee_or_element_clang_type.IsCharType()) { + if (type_flags.Test(eTypeIsArray)) { + // We know the size of the array and it could be a C string since it is + // an array of characters + length = llvm::cast<clang::ConstantArrayType>( + GetCanonicalQualType(type).getTypePtr()) + ->getSize() + .getLimitedValue(); + } + return true; + } + } + return false; +} + +bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type, + bool *is_variadic_ptr) { + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + + if (qual_type->isFunctionType()) { + if (is_variadic_ptr) { + const clang::FunctionProtoType *function_proto_type = + llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); + if (function_proto_type) + *is_variadic_ptr = function_proto_type->isVariadic(); + else + *is_variadic_ptr = false; + } + return true; + } + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + default: + break; + case clang::Type::LValueReference: + case clang::Type::RValueReference: { + const clang::ReferenceType *reference_type = + llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + if (reference_type) + return IsFunctionType(reference_type->getPointeeType().getAsOpaquePtr(), + nullptr); + } break; + } + } + return false; +} + +// Used to detect "Homogeneous Floating-point Aggregates" +uint32_t +TypeSystemClang::IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, + CompilerType *base_type_ptr) { + if (!type) + return 0; + + clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: + if (GetCompleteType(type)) { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + if (cxx_record_decl->getNumBases() || cxx_record_decl->isDynamicClass()) + return 0; + } + const clang::RecordType *record_type = + llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + if (record_type) { + const clang::RecordDecl *record_decl = record_type->getDecl(); + if (record_decl) { + // We are looking for a structure that contains only floating point + // types + clang::RecordDecl::field_iterator field_pos, + field_end = record_decl->field_end(); + uint32_t num_fields = 0; + bool is_hva = false; + bool is_hfa = false; + clang::QualType base_qual_type; + uint64_t base_bitwidth = 0; + for (field_pos = record_decl->field_begin(); field_pos != field_end; + ++field_pos) { + clang::QualType field_qual_type = field_pos->getType(); + uint64_t field_bitwidth = getASTContext().getTypeSize(qual_type); + if (field_qual_type->isFloatingType()) { + if (field_qual_type->isComplexType()) + return 0; + else { + if (num_fields == 0) + base_qual_type = field_qual_type; + else { + if (is_hva) + return 0; + is_hfa = true; + if (field_qual_type.getTypePtr() != + base_qual_type.getTypePtr()) + return 0; + } + } + } else if (field_qual_type->isVectorType() || + field_qual_type->isExtVectorType()) { + if (num_fields == 0) { + base_qual_type = field_qual_type; + base_bitwidth = field_bitwidth; + } else { + if (is_hfa) + return 0; + is_hva = true; + if (base_bitwidth != field_bitwidth) + return 0; + if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr()) + return 0; + } + } else + return 0; + ++num_fields; + } + if (base_type_ptr) + *base_type_ptr = CompilerType(this, base_qual_type.getAsOpaquePtr()); + return num_fields; + } + } + } + break; + + default: + break; + } + return 0; +} + +size_t TypeSystemClang::GetNumberOfFunctionArguments( + lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::FunctionProtoType *func = + llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); + if (func) + return func->getNumParams(); + } + return 0; +} + +CompilerType +TypeSystemClang::GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type, + const size_t index) { + if (type) { + clang::QualType qual_type(GetQualType(type)); + const clang::FunctionProtoType *func = + llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); + if (func) { + if (index < func->getNumParams()) + return CompilerType(this, func->getParamType(index).getAsOpaquePtr()); + } + } + return CompilerType(); +} + +bool TypeSystemClang::IsFunctionPointerType(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + + if (qual_type->isFunctionPointerType()) + return true; + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + default: + break; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: { + const clang::ReferenceType *reference_type = + llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + if (reference_type) + return IsFunctionPointerType( + reference_type->getPointeeType().getAsOpaquePtr()); + } break; + } + } + return false; +} + +bool TypeSystemClang::IsBlockPointerType( + lldb::opaque_compiler_type_t type, + CompilerType *function_pointer_type_ptr) { + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + + if (qual_type->isBlockPointerType()) { + if (function_pointer_type_ptr) { + const clang::BlockPointerType *block_pointer_type = + qual_type->getAs<clang::BlockPointerType>(); + QualType pointee_type = block_pointer_type->getPointeeType(); + QualType function_pointer_type = m_ast_up->getPointerType(pointee_type); + *function_pointer_type_ptr = + CompilerType(this, function_pointer_type.getAsOpaquePtr()); + } + return true; + } + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + default: + break; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: { + const clang::ReferenceType *reference_type = + llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + if (reference_type) + return IsBlockPointerType( + reference_type->getPointeeType().getAsOpaquePtr(), + function_pointer_type_ptr); + } break; + } + } + return false; +} + +bool TypeSystemClang::IsIntegerType(lldb::opaque_compiler_type_t type, + bool &is_signed) { + if (!type) + return false; + + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::BuiltinType *builtin_type = + llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal()); + + if (builtin_type) { + if (builtin_type->isInteger()) { + is_signed = builtin_type->isSignedInteger(); + return true; + } + } + + return false; +} + +bool TypeSystemClang::IsEnumerationType(lldb::opaque_compiler_type_t type, + bool &is_signed) { + if (type) { + const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>( + GetCanonicalQualType(type)->getCanonicalTypeInternal()); + + if (enum_type) { + IsIntegerType(enum_type->getDecl()->getIntegerType().getAsOpaquePtr(), + is_signed); + return true; + } + } + + return false; +} + +bool TypeSystemClang::IsPointerType(lldb::opaque_compiler_type_t type, + CompilerType *pointee_type) { + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) { + default: + break; + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + return true; + } + return false; + case clang::Type::ObjCObjectPointer: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::ObjCObjectPointerType>(qual_type) + ->getPointeeType() + .getAsOpaquePtr()); + return true; + case clang::Type::BlockPointer: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::BlockPointerType>(qual_type) + ->getPointeeType() + .getAsOpaquePtr()); + return true; + case clang::Type::Pointer: + if (pointee_type) + pointee_type->SetCompilerType(this, + llvm::cast<clang::PointerType>(qual_type) + ->getPointeeType() + .getAsOpaquePtr()); + return true; + case clang::Type::MemberPointer: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::MemberPointerType>(qual_type) + ->getPointeeType() + .getAsOpaquePtr()); + return true; + default: + break; + } + } + if (pointee_type) + pointee_type->Clear(); + return false; +} + +bool TypeSystemClang::IsPointerOrReferenceType( + lldb::opaque_compiler_type_t type, CompilerType *pointee_type) { + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) { + default: + break; + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + return true; + } + return false; + case clang::Type::ObjCObjectPointer: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::ObjCObjectPointerType>(qual_type) + ->getPointeeType().getAsOpaquePtr()); + return true; + case clang::Type::BlockPointer: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::BlockPointerType>(qual_type) + ->getPointeeType() + .getAsOpaquePtr()); + return true; + case clang::Type::Pointer: + if (pointee_type) + pointee_type->SetCompilerType(this, + llvm::cast<clang::PointerType>(qual_type) + ->getPointeeType() + .getAsOpaquePtr()); + return true; + case clang::Type::MemberPointer: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::MemberPointerType>(qual_type) + ->getPointeeType() + .getAsOpaquePtr()); + return true; + case clang::Type::LValueReference: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::LValueReferenceType>(qual_type) + ->desugar() + .getAsOpaquePtr()); + return true; + case clang::Type::RValueReference: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::RValueReferenceType>(qual_type) + ->desugar() + .getAsOpaquePtr()); + return true; + default: + break; + } + } + if (pointee_type) + pointee_type->Clear(); + return false; +} + +bool TypeSystemClang::IsReferenceType(lldb::opaque_compiler_type_t type, + CompilerType *pointee_type, + bool *is_rvalue) { + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + + switch (type_class) { + case clang::Type::LValueReference: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::LValueReferenceType>(qual_type) + ->desugar() + .getAsOpaquePtr()); + if (is_rvalue) + *is_rvalue = false; + return true; + case clang::Type::RValueReference: + if (pointee_type) + pointee_type->SetCompilerType( + this, llvm::cast<clang::RValueReferenceType>(qual_type) + ->desugar() + .getAsOpaquePtr()); + if (is_rvalue) + *is_rvalue = true; + return true; + + default: + break; + } + } + if (pointee_type) + pointee_type->Clear(); + return false; +} + +bool TypeSystemClang::IsFloatingPointType(lldb::opaque_compiler_type_t type, + uint32_t &count, bool &is_complex) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + + if (const clang::BuiltinType *BT = llvm::dyn_cast<clang::BuiltinType>( + qual_type->getCanonicalTypeInternal())) { + clang::BuiltinType::Kind kind = BT->getKind(); + if (kind >= clang::BuiltinType::Float && + kind <= clang::BuiltinType::LongDouble) { + count = 1; + is_complex = false; + return true; + } + } else if (const clang::ComplexType *CT = + llvm::dyn_cast<clang::ComplexType>( + qual_type->getCanonicalTypeInternal())) { + if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count, + is_complex)) { + count = 2; + is_complex = true; + return true; + } + } else if (const clang::VectorType *VT = llvm::dyn_cast<clang::VectorType>( + qual_type->getCanonicalTypeInternal())) { + if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count, + is_complex)) { + count = VT->getNumElements(); + is_complex = false; + return true; + } + } + } + count = 0; + is_complex = false; + return false; +} + +bool TypeSystemClang::IsDefined(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + + clang::QualType qual_type(GetQualType(type)); + const clang::TagType *tag_type = + llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr()); + if (tag_type) { + clang::TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + return tag_decl->isCompleteDefinition(); + return false; + } else { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + if (class_interface_decl) + return class_interface_decl->getDefinition() != nullptr; + return false; + } + } + return true; +} + +bool TypeSystemClang::IsObjCClassType(const CompilerType &type) { + if (ClangUtil::IsClangType(type)) { + clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type)); + + const clang::ObjCObjectPointerType *obj_pointer_type = + llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type); + + if (obj_pointer_type) + return obj_pointer_type->isObjCClassType(); + } + return false; +} + +bool TypeSystemClang::IsObjCObjectOrInterfaceType(const CompilerType &type) { + if (ClangUtil::IsClangType(type)) + return ClangUtil::GetCanonicalQualType(type)->isObjCObjectOrInterfaceType(); + return false; +} + +bool TypeSystemClang::IsClassType(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + return (type_class == clang::Type::Record); +} + +bool TypeSystemClang::IsEnumType(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + return (type_class == clang::Type::Enum); +} + +bool TypeSystemClang::IsPolymorphicClass(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + 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(); + 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(); + } + } + break; + + default: + break; + } + } + return false; +} + +bool TypeSystemClang::IsPossibleDynamicType(lldb::opaque_compiler_type_t type, + CompilerType *dynamic_pointee_type, + bool check_cplusplus, + bool check_objc) { + clang::QualType pointee_qual_type; + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + bool success = false; + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Builtin: + if (check_objc && + llvm::cast<clang::BuiltinType>(qual_type)->getKind() == + clang::BuiltinType::ObjCId) { + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType(this, type); + return true; + } + break; + + case clang::Type::ObjCObjectPointer: + if (check_objc) { + if (const auto *objc_pointee_type = + qual_type->getPointeeType().getTypePtrOrNull()) { + if (const auto *objc_object_type = + llvm::dyn_cast_or_null<clang::ObjCObjectType>( + objc_pointee_type)) { + if (objc_object_type->isObjCClass()) + return false; + } + } + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType( + this, llvm::cast<clang::ObjCObjectPointerType>(qual_type) + ->getPointeeType() + .getAsOpaquePtr()); + return true; + } + break; + + case clang::Type::Pointer: + pointee_qual_type = + llvm::cast<clang::PointerType>(qual_type)->getPointeeType(); + success = true; + break; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + pointee_qual_type = + llvm::cast<clang::ReferenceType>(qual_type)->getPointeeType(); + success = true; + break; + + default: + break; + } + + if (success) { + // Check to make sure what we are pointing too is a possible dynamic C++ + // type We currently accept any "void *" (in case we have a class that + // has been watered down to an opaque pointer) and virtual C++ classes. + const clang::Type::TypeClass pointee_type_class = + pointee_qual_type.getCanonicalType()->getTypeClass(); + switch (pointee_type_class) { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(pointee_qual_type)->getKind()) { + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::Void: + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType( + this, pointee_qual_type.getAsOpaquePtr()); + return true; + default: + break; + } + break; + + case clang::Type::Record: + if (check_cplusplus) { + clang::CXXRecordDecl *cxx_record_decl = + pointee_qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + bool is_complete = cxx_record_decl->isCompleteDefinition(); + + if (is_complete) + success = cxx_record_decl->isDynamicClass(); + else { + ClangASTMetadata *metadata = GetMetadata(cxx_record_decl); + if (metadata) + success = metadata->GetIsDynamicCXXType(); + else { + is_complete = GetType(pointee_qual_type).GetCompleteType(); + if (is_complete) + success = cxx_record_decl->isDynamicClass(); + else + success = false; + } + } + + if (success) { + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType( + this, pointee_qual_type.getAsOpaquePtr()); + return true; + } + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (check_objc) { + if (dynamic_pointee_type) + dynamic_pointee_type->SetCompilerType( + this, pointee_qual_type.getAsOpaquePtr()); + return true; + } + break; + + default: + break; + } + } + } + if (dynamic_pointee_type) + dynamic_pointee_type->Clear(); + return false; +} + +bool TypeSystemClang::IsScalarType(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + + return (GetTypeInfo(type, nullptr) & eTypeIsScalar) != 0; +} + +bool TypeSystemClang::IsTypedefType(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + return RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef}) + ->getTypeClass() == clang::Type::Typedef; +} + +bool TypeSystemClang::IsVoidType(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + return GetCanonicalQualType(type)->isVoidType(); +} + +bool TypeSystemClang::CanPassInRegisters(const CompilerType &type) { + if (auto *record_decl = + TypeSystemClang::GetAsRecordDecl(type)) { + return record_decl->canPassInRegisters(); + } + return false; +} + +bool TypeSystemClang::SupportsLanguage(lldb::LanguageType language) { + return TypeSystemClangSupportsLanguage(language); +} + +Optional<std::string> +TypeSystemClang::GetCXXClassName(const CompilerType &type) { + if (!type) + return llvm::None; + + clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type)); + if (qual_type.isNull()) + return llvm::None; + + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (!cxx_record_decl) + return llvm::None; + + return std::string(cxx_record_decl->getIdentifier()->getNameStart()); +} + +bool TypeSystemClang::IsCXXClassType(const CompilerType &type) { + if (!type) + return false; + + clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type)); + return !qual_type.isNull() && qual_type->getAsCXXRecordDecl() != nullptr; +} + +bool TypeSystemClang::IsBeingDefined(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type); + if (tag_type) + return tag_type->isBeingDefined(); + return false; +} + +bool TypeSystemClang::IsObjCObjectPointerType(const CompilerType &type, + CompilerType *class_type_ptr) { + if (!ClangUtil::IsClangType(type)) + return false; + + clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type)); + + if (!qual_type.isNull() && qual_type->isObjCObjectPointerType()) { + if (class_type_ptr) { + if (!qual_type->isObjCClassType() && !qual_type->isObjCIdType()) { + const clang::ObjCObjectPointerType *obj_pointer_type = + llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type); + if (obj_pointer_type == nullptr) + class_type_ptr->Clear(); + else + class_type_ptr->SetCompilerType( + type.GetTypeSystem(), + clang::QualType(obj_pointer_type->getInterfaceType(), 0) + .getAsOpaquePtr()); + } + } + return true; + } + if (class_type_ptr) + class_type_ptr->Clear(); + return false; +} + +// Type Completion + +bool TypeSystemClang::GetCompleteType(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + const bool allow_completion = true; + return GetCompleteQualType(&getASTContext(), GetQualType(type), + allow_completion); +} + +ConstString TypeSystemClang::GetTypeName(lldb::opaque_compiler_type_t type) { + if (!type) + return ConstString(); + + clang::QualType qual_type(GetQualType(type)); + + // For a typedef just return the qualified name. + if (const auto *typedef_type = qual_type->getAs<clang::TypedefType>()) { + const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); + return ConstString(typedef_decl->getQualifiedNameAsString()); + } + + clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); + printing_policy.SuppressTagKeyword = true; + return ConstString(qual_type.getAsString(printing_policy)); +} + +ConstString +TypeSystemClang::GetDisplayTypeName(lldb::opaque_compiler_type_t type) { + if (!type) + return ConstString(); + + clang::QualType qual_type(GetQualType(type)); + clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); + printing_policy.SuppressTagKeyword = true; + printing_policy.SuppressScope = false; + printing_policy.SuppressUnwrittenScope = true; + return ConstString(qual_type.getAsString(printing_policy)); +} + +uint32_t +TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type, + CompilerType *pointee_or_element_clang_type) { + if (!type) + return 0; + + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->Clear(); + + clang::QualType qual_type = + RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef}); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Attributed: + return GetTypeInfo( + qual_type->getAs<clang::AttributedType>() + ->getModifiedType().getAsOpaquePtr(), + pointee_or_element_clang_type); + case clang::Type::Builtin: { + const clang::BuiltinType *builtin_type = llvm::dyn_cast<clang::BuiltinType>( + qual_type->getCanonicalTypeInternal()); + + uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue; + switch (builtin_type->getKind()) { + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType( + this, getASTContext().ObjCBuiltinClassTy.getAsOpaquePtr()); + builtin_type_flags |= eTypeIsPointer | eTypeIsObjC; + break; + + case clang::BuiltinType::ObjCSel: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType( + this, getASTContext().CharTy.getAsOpaquePtr()); + builtin_type_flags |= eTypeIsPointer | eTypeIsObjC; + break; + + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + builtin_type_flags |= eTypeIsScalar; + if (builtin_type->isInteger()) { + builtin_type_flags |= eTypeIsInteger; + if (builtin_type->isSignedInteger()) + builtin_type_flags |= eTypeIsSigned; + } else if (builtin_type->isFloatingPoint()) + builtin_type_flags |= eTypeIsFloat; + break; + default: + break; + } + return builtin_type_flags; + } + + case clang::Type::BlockPointer: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType( + this, qual_type->getPointeeType().getAsOpaquePtr()); + return eTypeIsPointer | eTypeHasChildren | eTypeIsBlock; + + case clang::Type::Complex: { + uint32_t complex_type_flags = + eTypeIsBuiltIn | eTypeHasValue | eTypeIsComplex; + const clang::ComplexType *complex_type = llvm::dyn_cast<clang::ComplexType>( + qual_type->getCanonicalTypeInternal()); + if (complex_type) { + clang::QualType complex_element_type(complex_type->getElementType()); + if (complex_element_type->isIntegerType()) + complex_type_flags |= eTypeIsFloat; + else if (complex_element_type->isFloatingType()) + complex_type_flags |= eTypeIsInteger; + } + return complex_type_flags; + } break; + + case clang::Type::ConstantArray: + case clang::Type::DependentSizedArray: + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType( + this, llvm::cast<clang::ArrayType>(qual_type.getTypePtr()) + ->getElementType() + .getAsOpaquePtr()); + return eTypeHasChildren | eTypeIsArray; + + case clang::Type::DependentName: + return 0; + case clang::Type::DependentSizedExtVector: + return eTypeHasChildren | eTypeIsVector; + case clang::Type::DependentTemplateSpecialization: + return eTypeIsTemplate; + + case clang::Type::Enum: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType( + this, llvm::cast<clang::EnumType>(qual_type) + ->getDecl() + ->getIntegerType() + .getAsOpaquePtr()); + return eTypeIsEnumeration | eTypeHasValue; + + case clang::Type::FunctionProto: + return eTypeIsFuncPrototype | eTypeHasValue; + case clang::Type::FunctionNoProto: + return eTypeIsFuncPrototype | eTypeHasValue; + case clang::Type::InjectedClassName: + return 0; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType( + this, llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()) + ->getPointeeType() + .getAsOpaquePtr()); + return eTypeHasChildren | eTypeIsReference | eTypeHasValue; + + case clang::Type::MemberPointer: + return eTypeIsPointer | eTypeIsMember | eTypeHasValue; + + case clang::Type::ObjCObjectPointer: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType( + this, qual_type->getPointeeType().getAsOpaquePtr()); + return eTypeHasChildren | eTypeIsObjC | eTypeIsClass | eTypeIsPointer | + eTypeHasValue; + + case clang::Type::ObjCObject: + return eTypeHasChildren | eTypeIsObjC | eTypeIsClass; + case clang::Type::ObjCInterface: + return eTypeHasChildren | eTypeIsObjC | eTypeIsClass; + + case clang::Type::Pointer: + if (pointee_or_element_clang_type) + pointee_or_element_clang_type->SetCompilerType( + this, qual_type->getPointeeType().getAsOpaquePtr()); + return eTypeHasChildren | eTypeIsPointer | eTypeHasValue; + + case clang::Type::Record: + if (qual_type->getAsCXXRecordDecl()) + return eTypeHasChildren | eTypeIsClass | eTypeIsCPlusPlus; + else + return eTypeHasChildren | eTypeIsStructUnion; + break; + case clang::Type::SubstTemplateTypeParm: + return eTypeIsTemplate; + case clang::Type::TemplateTypeParm: + return eTypeIsTemplate; + case clang::Type::TemplateSpecialization: + return eTypeIsTemplate; + + case clang::Type::Typedef: + return eTypeIsTypedef | GetType(llvm::cast<clang::TypedefType>(qual_type) + ->getDecl() + ->getUnderlyingType()) + .GetTypeInfo(pointee_or_element_clang_type); + case clang::Type::UnresolvedUsing: + return 0; + + case clang::Type::ExtVector: + case clang::Type::Vector: { + uint32_t vector_type_flags = eTypeHasChildren | eTypeIsVector; + const clang::VectorType *vector_type = llvm::dyn_cast<clang::VectorType>( + qual_type->getCanonicalTypeInternal()); + if (vector_type) { + if (vector_type->isIntegerType()) + vector_type_flags |= eTypeIsFloat; + else if (vector_type->isFloatingType()) + vector_type_flags |= eTypeIsInteger; + } + return vector_type_flags; + } + default: + return 0; + } + return 0; +} + +lldb::LanguageType +TypeSystemClang::GetMinimumLanguage(lldb::opaque_compiler_type_t type) { + if (!type) + return lldb::eLanguageTypeC; + + // If the type is a reference, then resolve it to what it refers to first: + clang::QualType qual_type(GetCanonicalQualType(type).getNonReferenceType()); + if (qual_type->isAnyPointerType()) { + if (qual_type->isObjCObjectPointerType()) + return lldb::eLanguageTypeObjC; + if (qual_type->getPointeeCXXRecordDecl()) + return lldb::eLanguageTypeC_plus_plus; + + clang::QualType pointee_type(qual_type->getPointeeType()); + if (pointee_type->getPointeeCXXRecordDecl()) + return lldb::eLanguageTypeC_plus_plus; + if (pointee_type->isObjCObjectOrInterfaceType()) + return lldb::eLanguageTypeObjC; + if (pointee_type->isObjCClassType()) + return lldb::eLanguageTypeObjC; + if (pointee_type.getTypePtr() == + getASTContext().ObjCBuiltinIdTy.getTypePtr()) + return lldb::eLanguageTypeObjC; + } else { + if (qual_type->isObjCObjectOrInterfaceType()) + return lldb::eLanguageTypeObjC; + if (qual_type->getAsCXXRecordDecl()) + return lldb::eLanguageTypeC_plus_plus; + switch (qual_type->getTypeClass()) { + default: + break; + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) { + default: + case clang::BuiltinType::Void: + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + break; + + case clang::BuiltinType::NullPtr: + return eLanguageTypeC_plus_plus; + + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCSel: + return eLanguageTypeObjC; + + case clang::BuiltinType::Dependent: + case clang::BuiltinType::Overload: + case clang::BuiltinType::BoundMember: + case clang::BuiltinType::UnknownAny: + break; + } + break; + case clang::Type::Typedef: + return GetType(llvm::cast<clang::TypedefType>(qual_type) + ->getDecl() + ->getUnderlyingType()) + .GetMinimumLanguage(); + } + } + return lldb::eLanguageTypeC; +} + +lldb::TypeClass +TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) { + if (!type) + return lldb::eTypeClassInvalid; + + clang::QualType qual_type = + RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef}); + + switch (qual_type->getTypeClass()) { + case clang::Type::Atomic: + case clang::Type::Auto: + case clang::Type::Decltype: + case clang::Type::Elaborated: + case clang::Type::Paren: + case clang::Type::TypeOf: + case clang::Type::TypeOfExpr: + llvm_unreachable("Handled in RemoveWrappingTypes!"); + case clang::Type::UnaryTransform: + break; + case clang::Type::FunctionNoProto: + return lldb::eTypeClassFunction; + case clang::Type::FunctionProto: + return lldb::eTypeClassFunction; + case clang::Type::IncompleteArray: + return lldb::eTypeClassArray; + case clang::Type::VariableArray: + return lldb::eTypeClassArray; + case clang::Type::ConstantArray: + return lldb::eTypeClassArray; + case clang::Type::DependentSizedArray: + return lldb::eTypeClassArray; + case clang::Type::DependentSizedExtVector: + return lldb::eTypeClassVector; + case clang::Type::DependentVector: + return lldb::eTypeClassVector; + case clang::Type::ExtVector: + return lldb::eTypeClassVector; + case clang::Type::Vector: + return lldb::eTypeClassVector; + case clang::Type::Builtin: + // Ext-Int is just an integer type. + case clang::Type::ExtInt: + case clang::Type::DependentExtInt: + return lldb::eTypeClassBuiltin; + case clang::Type::ObjCObjectPointer: + return lldb::eTypeClassObjCObjectPointer; + case clang::Type::BlockPointer: + return lldb::eTypeClassBlockPointer; + case clang::Type::Pointer: + return lldb::eTypeClassPointer; + case clang::Type::LValueReference: + return lldb::eTypeClassReference; + case clang::Type::RValueReference: + return lldb::eTypeClassReference; + case clang::Type::MemberPointer: + return lldb::eTypeClassMemberPointer; + case clang::Type::Complex: + if (qual_type->isComplexType()) + return lldb::eTypeClassComplexFloat; + else + return lldb::eTypeClassComplexInteger; + case clang::Type::ObjCObject: + return lldb::eTypeClassObjCObject; + case clang::Type::ObjCInterface: + return lldb::eTypeClassObjCInterface; + case clang::Type::Record: { + const clang::RecordType *record_type = + llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + if (record_decl->isUnion()) + return lldb::eTypeClassUnion; + else if (record_decl->isStruct()) + return lldb::eTypeClassStruct; + else + return lldb::eTypeClassClass; + } break; + case clang::Type::Enum: + return lldb::eTypeClassEnumeration; + case clang::Type::Typedef: + return lldb::eTypeClassTypedef; + case clang::Type::UnresolvedUsing: + break; + + case clang::Type::Attributed: + break; + case clang::Type::TemplateTypeParm: + break; + case clang::Type::SubstTemplateTypeParm: + break; + case clang::Type::SubstTemplateTypeParmPack: + break; + case clang::Type::InjectedClassName: + break; + case clang::Type::DependentName: + break; + case clang::Type::DependentTemplateSpecialization: + break; + case clang::Type::PackExpansion: + break; + + case clang::Type::TemplateSpecialization: + break; + case clang::Type::DeducedTemplateSpecialization: + break; + case clang::Type::Pipe: + break; + + // pointer type decayed from an array or function type. + case clang::Type::Decayed: + break; + case clang::Type::Adjusted: + break; + case clang::Type::ObjCTypeParam: + break; + + case clang::Type::DependentAddressSpace: + break; + case clang::Type::MacroQualified: + break; + + // Matrix types that we're not sure how to display at the moment. + case clang::Type::ConstantMatrix: + case clang::Type::DependentSizedMatrix: + break; + } + // We don't know hot to display this type... + return lldb::eTypeClassOther; +} + +unsigned TypeSystemClang::GetTypeQualifiers(lldb::opaque_compiler_type_t type) { + if (type) + return GetQualType(type).getQualifiers().getCVRQualifiers(); + return 0; +} + +// Creating related types + +CompilerType +TypeSystemClang::GetArrayElementType(lldb::opaque_compiler_type_t type, + uint64_t *stride) { + if (type) { + clang::QualType qual_type(GetQualType(type)); + + const clang::Type *array_eletype = + qual_type.getTypePtr()->getArrayElementTypeNoTypeQual(); + + if (!array_eletype) + return CompilerType(); + + CompilerType element_type = GetType(clang::QualType(array_eletype, 0)); + + // TODO: the real stride will be >= this value.. find the real one! + if (stride) + if (Optional<uint64_t> size = element_type.GetByteSize(nullptr)) + *stride = *size; + + return element_type; + } + return CompilerType(); +} + +CompilerType TypeSystemClang::GetArrayType(lldb::opaque_compiler_type_t type, + uint64_t size) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + clang::ASTContext &ast_ctx = getASTContext(); + if (size != 0) + return GetType(ast_ctx.getConstantArrayType( + qual_type, llvm::APInt(64, size), nullptr, + clang::ArrayType::ArraySizeModifier::Normal, 0)); + else + return GetType(ast_ctx.getIncompleteArrayType( + qual_type, clang::ArrayType::ArraySizeModifier::Normal, 0)); + } + + return CompilerType(); +} + +CompilerType +TypeSystemClang::GetCanonicalType(lldb::opaque_compiler_type_t type) { + if (type) + return GetType(GetCanonicalQualType(type)); + return CompilerType(); +} + +static clang::QualType GetFullyUnqualifiedType_Impl(clang::ASTContext *ast, + clang::QualType qual_type) { + if (qual_type->isPointerType()) + qual_type = ast->getPointerType( + GetFullyUnqualifiedType_Impl(ast, qual_type->getPointeeType())); + else + qual_type = qual_type.getUnqualifiedType(); + qual_type.removeLocalConst(); + qual_type.removeLocalRestrict(); + qual_type.removeLocalVolatile(); + return qual_type; +} + +CompilerType +TypeSystemClang::GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) { + if (type) + return GetType( + GetFullyUnqualifiedType_Impl(&getASTContext(), GetQualType(type))); + return CompilerType(); +} + +int TypeSystemClang::GetFunctionArgumentCount( + lldb::opaque_compiler_type_t type) { + if (type) { + const clang::FunctionProtoType *func = + llvm::dyn_cast<clang::FunctionProtoType>(GetCanonicalQualType(type)); + if (func) + return func->getNumParams(); + } + return -1; +} + +CompilerType TypeSystemClang::GetFunctionArgumentTypeAtIndex( + lldb::opaque_compiler_type_t type, size_t idx) { + if (type) { + const clang::FunctionProtoType *func = + llvm::dyn_cast<clang::FunctionProtoType>(GetQualType(type)); + if (func) { + const uint32_t num_args = func->getNumParams(); + if (idx < num_args) + return GetType(func->getParamType(idx)); + } + } + return CompilerType(); +} + +CompilerType +TypeSystemClang::GetFunctionReturnType(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetQualType(type)); + const clang::FunctionProtoType *func = + llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr()); + if (func) + return GetType(func->getReturnType()); + } + return CompilerType(); +} + +size_t +TypeSystemClang::GetNumMemberFunctions(lldb::opaque_compiler_type_t type) { + size_t num_functions = 0; + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + switch (qual_type->getTypeClass()) { + case clang::Type::Record: + if (GetCompleteQualType(&getASTContext(), qual_type)) { + const clang::RecordType *record_type = + llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const clang::CXXRecordDecl *cxx_record_decl = + llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) + num_functions = std::distance(cxx_record_decl->method_begin(), + cxx_record_decl->method_end()); + } + break; + + case clang::Type::ObjCObjectPointer: { + const clang::ObjCObjectPointerType *objc_class_type = + qual_type->getAs<clang::ObjCObjectPointerType>(); + const clang::ObjCInterfaceType *objc_interface_type = + objc_class_type->getInterfaceType(); + if (objc_interface_type && + GetCompleteType(static_cast<lldb::opaque_compiler_type_t>( + const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_interface_type->getDecl(); + if (class_interface_decl) { + num_functions = std::distance(class_interface_decl->meth_begin(), + class_interface_decl->meth_end()); + } + } + break; + } + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + if (class_interface_decl) + num_functions = std::distance(class_interface_decl->meth_begin(), + class_interface_decl->meth_end()); + } + } + break; + + default: + break; + } + } + return num_functions; +} + +TypeMemberFunctionImpl +TypeSystemClang::GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type, + size_t idx) { + std::string name; + MemberFunctionKind kind(MemberFunctionKind::eMemberFunctionKindUnknown); + CompilerType clang_type; + CompilerDecl clang_decl; + if (type) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + switch (qual_type->getTypeClass()) { + case clang::Type::Record: + if (GetCompleteQualType(&getASTContext(), qual_type)) { + const clang::RecordType *record_type = + llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const clang::CXXRecordDecl *cxx_record_decl = + llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) { + auto method_iter = cxx_record_decl->method_begin(); + auto method_end = cxx_record_decl->method_end(); + if (idx < + static_cast<size_t>(std::distance(method_iter, method_end))) { + std::advance(method_iter, idx); + clang::CXXMethodDecl *cxx_method_decl = + method_iter->getCanonicalDecl(); + if (cxx_method_decl) { + name = cxx_method_decl->getDeclName().getAsString(); + if (cxx_method_decl->isStatic()) + kind = lldb::eMemberFunctionKindStaticMethod; + else if (llvm::isa<clang::CXXConstructorDecl>(cxx_method_decl)) + kind = lldb::eMemberFunctionKindConstructor; + else if (llvm::isa<clang::CXXDestructorDecl>(cxx_method_decl)) + kind = lldb::eMemberFunctionKindDestructor; + else + kind = lldb::eMemberFunctionKindInstanceMethod; + clang_type = GetType(cxx_method_decl->getType()); + clang_decl = GetCompilerDecl(cxx_method_decl); + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: { + const clang::ObjCObjectPointerType *objc_class_type = + qual_type->getAs<clang::ObjCObjectPointerType>(); + const clang::ObjCInterfaceType *objc_interface_type = + objc_class_type->getInterfaceType(); + if (objc_interface_type && + GetCompleteType(static_cast<lldb::opaque_compiler_type_t>( + const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_interface_type->getDecl(); + if (class_interface_decl) { + auto method_iter = class_interface_decl->meth_begin(); + auto method_end = class_interface_decl->meth_end(); + if (idx < + static_cast<size_t>(std::distance(method_iter, method_end))) { + std::advance(method_iter, idx); + clang::ObjCMethodDecl *objc_method_decl = + method_iter->getCanonicalDecl(); + if (objc_method_decl) { + clang_decl = GetCompilerDecl(objc_method_decl); + name = objc_method_decl->getSelector().getAsString(); + if (objc_method_decl->isClassMethod()) + kind = lldb::eMemberFunctionKindStaticMethod; + else + kind = lldb::eMemberFunctionKindInstanceMethod; + } + } + } + } + break; + } + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + if (class_interface_decl) { + auto method_iter = class_interface_decl->meth_begin(); + auto method_end = class_interface_decl->meth_end(); + if (idx < + static_cast<size_t>(std::distance(method_iter, method_end))) { + std::advance(method_iter, idx); + clang::ObjCMethodDecl *objc_method_decl = + method_iter->getCanonicalDecl(); + if (objc_method_decl) { + clang_decl = GetCompilerDecl(objc_method_decl); + name = objc_method_decl->getSelector().getAsString(); + if (objc_method_decl->isClassMethod()) + kind = lldb::eMemberFunctionKindStaticMethod; + else + kind = lldb::eMemberFunctionKindInstanceMethod; + } + } + } + } + } + break; + + default: + break; + } + } + + if (kind == eMemberFunctionKindUnknown) + return TypeMemberFunctionImpl(); + else + return TypeMemberFunctionImpl(clang_type, clang_decl, name, kind); +} + +CompilerType +TypeSystemClang::GetNonReferenceType(lldb::opaque_compiler_type_t type) { + if (type) + return GetType(GetQualType(type).getNonReferenceType()); + return CompilerType(); +} + +CompilerType TypeSystemClang::CreateTypedefType( + const CompilerType &type, const char *typedef_name, + const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { + if (type && typedef_name && typedef_name[0]) { + TypeSystemClang *ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!ast) + return CompilerType(); + clang::ASTContext &clang_ast = ast->getASTContext(); + clang::QualType qual_type(ClangUtil::GetQualType(type)); + + clang::DeclContext *decl_ctx = + TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx); + if (!decl_ctx) + decl_ctx = ast->getASTContext().getTranslationUnitDecl(); + + clang::TypedefDecl *decl = + clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&clang_ast.Idents.get(typedef_name)); + decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); + + SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); + decl->setAccess(clang::AS_public); // TODO respect proper access specifier + + decl_ctx->addDecl(decl); + + // Get a uniqued clang::QualType for the typedef decl type + return ast->GetType(clang_ast.getTypedefType(decl)); + } + return CompilerType(); +} + +CompilerType +TypeSystemClang::GetPointeeType(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetQualType(type)); + return GetType(qual_type.getTypePtr()->getPointeeType()); + } + return CompilerType(); +} + +CompilerType +TypeSystemClang::GetPointerType(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetQualType(type)); + + switch (qual_type.getDesugaredType(getASTContext())->getTypeClass()) { + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + return GetType(getASTContext().getObjCObjectPointerType(qual_type)); + + default: + return GetType(getASTContext().getPointerType(qual_type)); + } + } + return CompilerType(); +} + +CompilerType +TypeSystemClang::GetLValueReferenceType(lldb::opaque_compiler_type_t type) { + if (type) + return GetType(getASTContext().getLValueReferenceType(GetQualType(type))); + else + return CompilerType(); +} + +CompilerType +TypeSystemClang::GetRValueReferenceType(lldb::opaque_compiler_type_t type) { + if (type) + return GetType(getASTContext().getRValueReferenceType(GetQualType(type))); + else + return CompilerType(); +} + +CompilerType TypeSystemClang::GetAtomicType(lldb::opaque_compiler_type_t type) { + if (!type) + return CompilerType(); + return GetType(getASTContext().getAtomicType(GetQualType(type))); +} + +CompilerType +TypeSystemClang::AddConstModifier(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType result(GetQualType(type)); + result.addConst(); + return GetType(result); + } + return CompilerType(); +} + +CompilerType +TypeSystemClang::AddVolatileModifier(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType result(GetQualType(type)); + result.addVolatile(); + return GetType(result); + } + return CompilerType(); +} + +CompilerType +TypeSystemClang::AddRestrictModifier(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType result(GetQualType(type)); + result.addRestrict(); + return GetType(result); + } + return CompilerType(); +} + +CompilerType TypeSystemClang::CreateTypedef( + lldb::opaque_compiler_type_t type, const char *typedef_name, + const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { + if (type) { + clang::ASTContext &clang_ast = getASTContext(); + clang::QualType qual_type(GetQualType(type)); + + clang::DeclContext *decl_ctx = + TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx); + if (!decl_ctx) + decl_ctx = getASTContext().getTranslationUnitDecl(); + + clang::TypedefDecl *decl = clang::TypedefDecl::Create( + clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), + &clang_ast.Idents.get(typedef_name), + clang_ast.getTrivialTypeSourceInfo(qual_type)); + SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); + + clang::TagDecl *tdecl = nullptr; + if (!qual_type.isNull()) { + if (const clang::RecordType *rt = qual_type->getAs<clang::RecordType>()) + tdecl = rt->getDecl(); + if (const clang::EnumType *et = qual_type->getAs<clang::EnumType>()) + tdecl = et->getDecl(); + } + + // Check whether this declaration is an anonymous struct, union, or enum, + // hidden behind a typedef. If so, we try to check whether we have a + // typedef tag to attach to the original record declaration + if (tdecl && !tdecl->getIdentifier() && !tdecl->getTypedefNameForAnonDecl()) + tdecl->setTypedefNameForAnonDecl(decl); + + decl->setAccess(clang::AS_public); // TODO respect proper access specifier + + // Get a uniqued clang::QualType for the typedef decl type + return GetType(clang_ast.getTypedefType(decl)); + } + return CompilerType(); +} + +CompilerType +TypeSystemClang::GetTypedefedType(lldb::opaque_compiler_type_t type) { + if (type) { + const clang::TypedefType *typedef_type = llvm::dyn_cast<clang::TypedefType>( + RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef})); + if (typedef_type) + return GetType(typedef_type->getDecl()->getUnderlyingType()); + } + return CompilerType(); +} + +// Create related types using the current type's AST + +CompilerType TypeSystemClang::GetBasicTypeFromAST(lldb::BasicType basic_type) { + return TypeSystemClang::GetBasicType(basic_type); +} +// Exploring the type + +const llvm::fltSemantics & +TypeSystemClang::GetFloatTypeSemantics(size_t byte_size) { + clang::ASTContext &ast = getASTContext(); + const size_t bit_size = byte_size * 8; + if (bit_size == ast.getTypeSize(ast.FloatTy)) + return ast.getFloatTypeSemantics(ast.FloatTy); + else if (bit_size == ast.getTypeSize(ast.DoubleTy)) + return ast.getFloatTypeSemantics(ast.DoubleTy); + else if (bit_size == ast.getTypeSize(ast.LongDoubleTy)) + return ast.getFloatTypeSemantics(ast.LongDoubleTy); + else if (bit_size == ast.getTypeSize(ast.HalfTy)) + return ast.getFloatTypeSemantics(ast.HalfTy); + return llvm::APFloatBase::Bogus(); +} + +Optional<uint64_t> +TypeSystemClang::GetBitSize(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + if (GetCompleteType(type)) { + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: + if (GetCompleteType(type)) + return getASTContext().getTypeSize(qual_type); + else + return None; + break; + + case clang::Type::ObjCInterface: + case clang::Type::ObjCObject: { + ExecutionContext exe_ctx(exe_scope); + Process *process = exe_ctx.GetProcessPtr(); + if (process) { + ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process); + if (objc_runtime) { + uint64_t bit_size = 0; + if (objc_runtime->GetTypeBitSize(GetType(qual_type), bit_size)) + return bit_size; + } + } else { + static bool g_printed = false; + if (!g_printed) { + StreamString s; + DumpTypeDescription(type, &s); + + llvm::outs() << "warning: trying to determine the size of type "; + llvm::outs() << s.GetString() << "\n"; + llvm::outs() << "without a valid ExecutionContext. this is not " + "reliable. please file a bug against LLDB.\n"; + llvm::outs() << "backtrace:\n"; + llvm::sys::PrintStackTrace(llvm::outs()); + llvm::outs() << "\n"; + g_printed = true; + } + } + } + LLVM_FALLTHROUGH; + default: + const uint32_t bit_size = getASTContext().getTypeSize(qual_type); + if (bit_size == 0) { + if (qual_type->isIncompleteArrayType()) + return getASTContext().getTypeSize( + qual_type->getArrayElementTypeNoTypeQual() + ->getCanonicalTypeUnqualified()); + } + if (qual_type->isObjCObjectOrInterfaceType()) + return bit_size + + getASTContext().getTypeSize(getASTContext().ObjCBuiltinClassTy); + // Function types actually have a size of 0, that's not an error. + if (qual_type->isFunctionProtoType()) + return bit_size; + if (bit_size) + return bit_size; + } + } + return None; +} + +llvm::Optional<size_t> +TypeSystemClang::GetTypeBitAlign(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + if (GetCompleteType(type)) + return getASTContext().getTypeAlign(GetQualType(type)); + return {}; +} + +lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, + uint64_t &count) { + if (!type) + return lldb::eEncodingInvalid; + + count = 1; + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + + switch (qual_type->getTypeClass()) { + case clang::Type::Atomic: + case clang::Type::Auto: + case clang::Type::Decltype: + case clang::Type::Elaborated: + case clang::Type::Paren: + case clang::Type::Typedef: + case clang::Type::TypeOf: + case clang::Type::TypeOfExpr: + llvm_unreachable("Handled in RemoveWrappingTypes!"); + + case clang::Type::UnaryTransform: + break; + + case clang::Type::FunctionNoProto: + case clang::Type::FunctionProto: + break; + + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + break; + + case clang::Type::ConstantArray: + break; + + case clang::Type::DependentVector: + case clang::Type::ExtVector: + case clang::Type::Vector: + // TODO: Set this to more than one??? + break; + + case clang::Type::ExtInt: + case clang::Type::DependentExtInt: + return qual_type->isUnsignedIntegerType() ? lldb::eEncodingUint + : lldb::eEncodingSint; + + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) { + case clang::BuiltinType::Void: + break; + + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + return lldb::eEncodingSint; + + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char8: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + return lldb::eEncodingUint; + + // Fixed point types. Note that they are currently ignored. + case clang::BuiltinType::ShortAccum: + case clang::BuiltinType::Accum: + case clang::BuiltinType::LongAccum: + case clang::BuiltinType::UShortAccum: + case clang::BuiltinType::UAccum: + case clang::BuiltinType::ULongAccum: + case clang::BuiltinType::ShortFract: + case clang::BuiltinType::Fract: + case clang::BuiltinType::LongFract: + case clang::BuiltinType::UShortFract: + case clang::BuiltinType::UFract: + case clang::BuiltinType::ULongFract: + case clang::BuiltinType::SatShortAccum: + case clang::BuiltinType::SatAccum: + case clang::BuiltinType::SatLongAccum: + case clang::BuiltinType::SatUShortAccum: + case clang::BuiltinType::SatUAccum: + case clang::BuiltinType::SatULongAccum: + case clang::BuiltinType::SatShortFract: + case clang::BuiltinType::SatFract: + case clang::BuiltinType::SatLongFract: + case clang::BuiltinType::SatUShortFract: + case clang::BuiltinType::SatUFract: + case clang::BuiltinType::SatULongFract: + break; + + case clang::BuiltinType::Half: + case clang::BuiltinType::Float: + case clang::BuiltinType::Float16: + case clang::BuiltinType::Float128: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + case clang::BuiltinType::BFloat16: + return lldb::eEncodingIEEE754; + + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCSel: + return lldb::eEncodingUint; + + case clang::BuiltinType::NullPtr: + return lldb::eEncodingUint; + + case clang::BuiltinType::Kind::ARCUnbridgedCast: + case clang::BuiltinType::Kind::BoundMember: + case clang::BuiltinType::Kind::BuiltinFn: + case clang::BuiltinType::Kind::Dependent: + case clang::BuiltinType::Kind::OCLClkEvent: + case clang::BuiltinType::Kind::OCLEvent: + case clang::BuiltinType::Kind::OCLImage1dRO: + case clang::BuiltinType::Kind::OCLImage1dWO: + case clang::BuiltinType::Kind::OCLImage1dRW: + case clang::BuiltinType::Kind::OCLImage1dArrayRO: + case clang::BuiltinType::Kind::OCLImage1dArrayWO: + case clang::BuiltinType::Kind::OCLImage1dArrayRW: + case clang::BuiltinType::Kind::OCLImage1dBufferRO: + case clang::BuiltinType::Kind::OCLImage1dBufferWO: + case clang::BuiltinType::Kind::OCLImage1dBufferRW: + case clang::BuiltinType::Kind::OCLImage2dRO: + case clang::BuiltinType::Kind::OCLImage2dWO: + case clang::BuiltinType::Kind::OCLImage2dRW: + case clang::BuiltinType::Kind::OCLImage2dArrayRO: + case clang::BuiltinType::Kind::OCLImage2dArrayWO: + case clang::BuiltinType::Kind::OCLImage2dArrayRW: + case clang::BuiltinType::Kind::OCLImage2dArrayDepthRO: + case clang::BuiltinType::Kind::OCLImage2dArrayDepthWO: + case clang::BuiltinType::Kind::OCLImage2dArrayDepthRW: + case clang::BuiltinType::Kind::OCLImage2dArrayMSAARO: + case clang::BuiltinType::Kind::OCLImage2dArrayMSAAWO: + case clang::BuiltinType::Kind::OCLImage2dArrayMSAARW: + case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthRO: + case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthWO: + case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthRW: + case clang::BuiltinType::Kind::OCLImage2dDepthRO: + case clang::BuiltinType::Kind::OCLImage2dDepthWO: + case clang::BuiltinType::Kind::OCLImage2dDepthRW: + case clang::BuiltinType::Kind::OCLImage2dMSAARO: + case clang::BuiltinType::Kind::OCLImage2dMSAAWO: + case clang::BuiltinType::Kind::OCLImage2dMSAARW: + case clang::BuiltinType::Kind::OCLImage2dMSAADepthRO: + case clang::BuiltinType::Kind::OCLImage2dMSAADepthWO: + case clang::BuiltinType::Kind::OCLImage2dMSAADepthRW: + case clang::BuiltinType::Kind::OCLImage3dRO: + case clang::BuiltinType::Kind::OCLImage3dWO: + case clang::BuiltinType::Kind::OCLImage3dRW: + case clang::BuiltinType::Kind::OCLQueue: + case clang::BuiltinType::Kind::OCLReserveID: + case clang::BuiltinType::Kind::OCLSampler: + case clang::BuiltinType::Kind::OMPArraySection: + case clang::BuiltinType::Kind::OMPArrayShaping: + case clang::BuiltinType::Kind::OMPIterator: + case clang::BuiltinType::Kind::Overload: + case clang::BuiltinType::Kind::PseudoObject: + case clang::BuiltinType::Kind::UnknownAny: + break; + + case clang::BuiltinType::OCLIntelSubgroupAVCMcePayload: + case clang::BuiltinType::OCLIntelSubgroupAVCImePayload: + case clang::BuiltinType::OCLIntelSubgroupAVCRefPayload: + case clang::BuiltinType::OCLIntelSubgroupAVCSicPayload: + case clang::BuiltinType::OCLIntelSubgroupAVCMceResult: + case clang::BuiltinType::OCLIntelSubgroupAVCImeResult: + case clang::BuiltinType::OCLIntelSubgroupAVCRefResult: + case clang::BuiltinType::OCLIntelSubgroupAVCSicResult: + case clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout: + case clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout: + case clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin: + case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin: + break; + + case clang::BuiltinType::SveBool: + case clang::BuiltinType::SveInt8: + case clang::BuiltinType::SveInt8x2: + case clang::BuiltinType::SveInt8x3: + case clang::BuiltinType::SveInt8x4: + case clang::BuiltinType::SveInt16: + case clang::BuiltinType::SveInt16x2: + case clang::BuiltinType::SveInt16x3: + case clang::BuiltinType::SveInt16x4: + case clang::BuiltinType::SveInt32: + case clang::BuiltinType::SveInt32x2: + case clang::BuiltinType::SveInt32x3: + case clang::BuiltinType::SveInt32x4: + case clang::BuiltinType::SveInt64: + case clang::BuiltinType::SveInt64x2: + case clang::BuiltinType::SveInt64x3: + case clang::BuiltinType::SveInt64x4: + case clang::BuiltinType::SveUint8: + case clang::BuiltinType::SveUint8x2: + case clang::BuiltinType::SveUint8x3: + case clang::BuiltinType::SveUint8x4: + case clang::BuiltinType::SveUint16: + case clang::BuiltinType::SveUint16x2: + case clang::BuiltinType::SveUint16x3: + case clang::BuiltinType::SveUint16x4: + case clang::BuiltinType::SveUint32: + case clang::BuiltinType::SveUint32x2: + case clang::BuiltinType::SveUint32x3: + case clang::BuiltinType::SveUint32x4: + case clang::BuiltinType::SveUint64: + case clang::BuiltinType::SveUint64x2: + case clang::BuiltinType::SveUint64x3: + case clang::BuiltinType::SveUint64x4: + case clang::BuiltinType::SveFloat16: + case clang::BuiltinType::SveBFloat16: + case clang::BuiltinType::SveBFloat16x2: + case clang::BuiltinType::SveBFloat16x3: + case clang::BuiltinType::SveBFloat16x4: + case clang::BuiltinType::SveFloat16x2: + case clang::BuiltinType::SveFloat16x3: + case clang::BuiltinType::SveFloat16x4: + case clang::BuiltinType::SveFloat32: + case clang::BuiltinType::SveFloat32x2: + case clang::BuiltinType::SveFloat32x3: + case clang::BuiltinType::SveFloat32x4: + case clang::BuiltinType::SveFloat64: + case clang::BuiltinType::SveFloat64x2: + case clang::BuiltinType::SveFloat64x3: + case clang::BuiltinType::SveFloat64x4: + break; + + case clang::BuiltinType::IncompleteMatrixIdx: + break; + } + break; + // All pointer types are represented as unsigned integer encodings. We may + // nee to add a eEncodingPointer if we ever need to know the difference + case clang::Type::ObjCObjectPointer: + case clang::Type::BlockPointer: + case clang::Type::Pointer: + case clang::Type::LValueReference: + case clang::Type::RValueReference: + case clang::Type::MemberPointer: + return lldb::eEncodingUint; + case clang::Type::Complex: { + lldb::Encoding encoding = lldb::eEncodingIEEE754; + if (qual_type->isComplexType()) + encoding = lldb::eEncodingIEEE754; + else { + const clang::ComplexType *complex_type = + qual_type->getAsComplexIntegerType(); + if (complex_type) + encoding = GetType(complex_type->getElementType()).GetEncoding(count); + else + encoding = lldb::eEncodingSint; + } + count = 2; + return encoding; + } + + case clang::Type::ObjCInterface: + break; + case clang::Type::Record: + break; + case clang::Type::Enum: + return lldb::eEncodingSint; + case clang::Type::DependentSizedArray: + case clang::Type::DependentSizedExtVector: + case clang::Type::UnresolvedUsing: + case clang::Type::Attributed: + case clang::Type::TemplateTypeParm: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::SubstTemplateTypeParmPack: + case clang::Type::InjectedClassName: + case clang::Type::DependentName: + case clang::Type::DependentTemplateSpecialization: + case clang::Type::PackExpansion: + case clang::Type::ObjCObject: + + case clang::Type::TemplateSpecialization: + case clang::Type::DeducedTemplateSpecialization: + case clang::Type::Adjusted: + case clang::Type::Pipe: + break; + + // pointer type decayed from an array or function type. + case clang::Type::Decayed: + break; + case clang::Type::ObjCTypeParam: + break; + + case clang::Type::DependentAddressSpace: + break; + case clang::Type::MacroQualified: + break; + + case clang::Type::ConstantMatrix: + case clang::Type::DependentSizedMatrix: + break; + } + count = 0; + return lldb::eEncodingInvalid; +} + +lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { + if (!type) + return lldb::eFormatDefault; + + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + + switch (qual_type->getTypeClass()) { + case clang::Type::Atomic: + case clang::Type::Auto: + case clang::Type::Decltype: + case clang::Type::Elaborated: + case clang::Type::Paren: + case clang::Type::Typedef: + case clang::Type::TypeOf: + case clang::Type::TypeOfExpr: + llvm_unreachable("Handled in RemoveWrappingTypes!"); + case clang::Type::UnaryTransform: + break; + + case clang::Type::FunctionNoProto: + case clang::Type::FunctionProto: + break; + + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + break; + + case clang::Type::ConstantArray: + return lldb::eFormatVoid; // no value + + case clang::Type::DependentVector: + case clang::Type::ExtVector: + case clang::Type::Vector: + break; + + case clang::Type::ExtInt: + case clang::Type::DependentExtInt: + return qual_type->isUnsignedIntegerType() ? lldb::eFormatUnsigned + : lldb::eFormatDecimal; + + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) { + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::Void: + case clang::BuiltinType::BoundMember: + break; + + case clang::BuiltinType::Bool: + return lldb::eFormatBoolean; + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + return lldb::eFormatChar; + case clang::BuiltinType::Char16: + return lldb::eFormatUnicode16; + case clang::BuiltinType::Char32: + return lldb::eFormatUnicode32; + case clang::BuiltinType::UShort: + return lldb::eFormatUnsigned; + case clang::BuiltinType::Short: + return lldb::eFormatDecimal; + case clang::BuiltinType::UInt: + return lldb::eFormatUnsigned; + case clang::BuiltinType::Int: + return lldb::eFormatDecimal; + case clang::BuiltinType::ULong: + return lldb::eFormatUnsigned; + case clang::BuiltinType::Long: + return lldb::eFormatDecimal; + case clang::BuiltinType::ULongLong: + return lldb::eFormatUnsigned; + case clang::BuiltinType::LongLong: + return lldb::eFormatDecimal; + case clang::BuiltinType::UInt128: + return lldb::eFormatUnsigned; + case clang::BuiltinType::Int128: + return lldb::eFormatDecimal; + case clang::BuiltinType::Half: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + return lldb::eFormatFloat; + default: + return lldb::eFormatHex; + } + break; + case clang::Type::ObjCObjectPointer: + return lldb::eFormatHex; + case clang::Type::BlockPointer: + return lldb::eFormatHex; + case clang::Type::Pointer: + return lldb::eFormatHex; + case clang::Type::LValueReference: + case clang::Type::RValueReference: + return lldb::eFormatHex; + case clang::Type::MemberPointer: + break; + case clang::Type::Complex: { + if (qual_type->isComplexType()) + return lldb::eFormatComplex; + else + return lldb::eFormatComplexInteger; + } + case clang::Type::ObjCInterface: + break; + case clang::Type::Record: + break; + case clang::Type::Enum: + return lldb::eFormatEnum; + case clang::Type::DependentSizedArray: + case clang::Type::DependentSizedExtVector: + case clang::Type::UnresolvedUsing: + case clang::Type::Attributed: + case clang::Type::TemplateTypeParm: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::SubstTemplateTypeParmPack: + case clang::Type::InjectedClassName: + case clang::Type::DependentName: + case clang::Type::DependentTemplateSpecialization: + case clang::Type::PackExpansion: + case clang::Type::ObjCObject: + + case clang::Type::TemplateSpecialization: + case clang::Type::DeducedTemplateSpecialization: + case clang::Type::Adjusted: + case clang::Type::Pipe: + break; + + // pointer type decayed from an array or function type. + case clang::Type::Decayed: + break; + case clang::Type::ObjCTypeParam: + break; + + case clang::Type::DependentAddressSpace: + break; + case clang::Type::MacroQualified: + break; + + // Matrix types we're not sure how to display yet. + case clang::Type::ConstantMatrix: + case clang::Type::DependentSizedMatrix: + break; + } + // We don't know hot to display this type... + return lldb::eFormatBytes; +} + +static bool ObjCDeclHasIVars(clang::ObjCInterfaceDecl *class_interface_decl, + bool check_superclass) { + while (class_interface_decl) { + if (class_interface_decl->ivar_size() > 0) + return true; + + if (check_superclass) + class_interface_decl = class_interface_decl->getSuperClass(); + else + break; + } + return false; +} + +static Optional<SymbolFile::ArrayInfo> +GetDynamicArrayInfo(TypeSystemClang &ast, SymbolFile *sym_file, + clang::QualType qual_type, + const ExecutionContext *exe_ctx) { + if (qual_type->isIncompleteArrayType()) + if (auto *metadata = ast.GetMetadata(qual_type.getTypePtr())) + return sym_file->GetDynamicArrayInfoForUID(metadata->GetUserID(), + exe_ctx); + return llvm::None; +} + +uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, + bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) { + if (!type) + return 0; + + uint32_t num_children = 0; + clang::QualType qual_type(RemoveWrappingTypes(GetQualType(type))); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) { + case clang::BuiltinType::ObjCId: // child is Class + case clang::BuiltinType::ObjCClass: // child is Class + num_children = 1; + break; + + default: + break; + } + break; + + case clang::Type::Complex: + return 0; + case clang::Type::Record: + if (GetCompleteQualType(&getASTContext(), qual_type)) { + const clang::RecordType *record_type = + llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const clang::CXXRecordDecl *cxx_record_decl = + llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) { + if (omit_empty_base_classes) { + // Check each base classes to see if it or any of its base classes + // contain any fields. This can help limit the noise in variable + // views by not having to show base classes that contain no members. + 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 (!TypeSystemClang::RecordHasFields(base_class_decl)) + continue; + + num_children++; + } + } else { + // Include all base classes + 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; + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteQualType(&getASTContext(), qual_type)) { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert(objc_class_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + + if (class_interface_decl) { + + clang::ObjCInterfaceDecl *superclass_interface_decl = + class_interface_decl->getSuperClass(); + if (superclass_interface_decl) { + if (omit_empty_base_classes) { + if (ObjCDeclHasIVars(superclass_interface_decl, true)) + ++num_children; + } else + ++num_children; + } + + num_children += class_interface_decl->ivar_size(); + } + } + } + break; + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + case clang::Type::ObjCObjectPointer: { + CompilerType pointee_clang_type(GetPointeeType(type)); + + uint32_t num_pointee_children = 0; + if (pointee_clang_type.IsAggregateType()) + num_pointee_children = + pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx); + // If this type points to a simple type, then it has 1 child + if (num_pointee_children == 0) + num_children = 1; + else + num_children = num_pointee_children; + } break; + + case clang::Type::Vector: + case clang::Type::ExtVector: + num_children = + llvm::cast<clang::VectorType>(qual_type.getTypePtr())->getNumElements(); + break; + + case clang::Type::ConstantArray: + num_children = llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr()) + ->getSize() + .getLimitedValue(); + break; + case clang::Type::IncompleteArray: + if (auto array_info = + GetDynamicArrayInfo(*this, GetSymbolFile(), qual_type, exe_ctx)) + // Only 1-dimensional arrays are supported. + num_children = array_info->element_orders.size() + ? array_info->element_orders.back() + : 0; + break; + + case clang::Type::Pointer: { + const clang::PointerType *pointer_type = + llvm::cast<clang::PointerType>(qual_type.getTypePtr()); + clang::QualType pointee_type(pointer_type->getPointeeType()); + CompilerType pointee_clang_type(GetType(pointee_type)); + uint32_t num_pointee_children = 0; + if (pointee_clang_type.IsAggregateType()) + num_pointee_children = + pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx); + if (num_pointee_children == 0) { + // We have a pointer to a pointee type that claims it has no children. We + // will want to look at + num_children = GetNumPointeeChildren(pointee_type); + } else + num_children = num_pointee_children; + } break; + + default: + break; + } + return num_children; +} + +CompilerType TypeSystemClang::GetBuiltinTypeByName(ConstString name) { + return GetBasicType(GetBasicTypeEnumeration(name)); +} + +lldb::BasicType +TypeSystemClang::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + if (type_class == clang::Type::Builtin) { + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) { + case clang::BuiltinType::Void: + return eBasicTypeVoid; + case clang::BuiltinType::Bool: + return eBasicTypeBool; + case clang::BuiltinType::Char_S: + return eBasicTypeSignedChar; + case clang::BuiltinType::Char_U: + return eBasicTypeUnsignedChar; + case clang::BuiltinType::Char16: + return eBasicTypeChar16; + case clang::BuiltinType::Char32: + return eBasicTypeChar32; + case clang::BuiltinType::UChar: + return eBasicTypeUnsignedChar; + case clang::BuiltinType::SChar: + return eBasicTypeSignedChar; + case clang::BuiltinType::WChar_S: + return eBasicTypeSignedWChar; + case clang::BuiltinType::WChar_U: + return eBasicTypeUnsignedWChar; + case clang::BuiltinType::Short: + return eBasicTypeShort; + case clang::BuiltinType::UShort: + return eBasicTypeUnsignedShort; + case clang::BuiltinType::Int: + return eBasicTypeInt; + case clang::BuiltinType::UInt: + return eBasicTypeUnsignedInt; + case clang::BuiltinType::Long: + return eBasicTypeLong; + case clang::BuiltinType::ULong: + return eBasicTypeUnsignedLong; + case clang::BuiltinType::LongLong: + return eBasicTypeLongLong; + case clang::BuiltinType::ULongLong: + return eBasicTypeUnsignedLongLong; + case clang::BuiltinType::Int128: + return eBasicTypeInt128; + case clang::BuiltinType::UInt128: + return eBasicTypeUnsignedInt128; + + case clang::BuiltinType::Half: + return eBasicTypeHalf; + case clang::BuiltinType::Float: + return eBasicTypeFloat; + case clang::BuiltinType::Double: + return eBasicTypeDouble; + case clang::BuiltinType::LongDouble: + return eBasicTypeLongDouble; + + case clang::BuiltinType::NullPtr: + return eBasicTypeNullPtr; + case clang::BuiltinType::ObjCId: + return eBasicTypeObjCID; + case clang::BuiltinType::ObjCClass: + return eBasicTypeObjCClass; + case clang::BuiltinType::ObjCSel: + return eBasicTypeObjCSel; + default: + return eBasicTypeOther; + } + } + } + return eBasicTypeInvalid; +} + +void TypeSystemClang::ForEachEnumerator( + lldb::opaque_compiler_type_t type, + std::function<bool(const CompilerType &integer_type, + ConstString name, + const llvm::APSInt &value)> const &callback) { + const clang::EnumType *enum_type = + llvm::dyn_cast<clang::EnumType>(GetCanonicalQualType(type)); + if (enum_type) { + const clang::EnumDecl *enum_decl = enum_type->getDecl(); + if (enum_decl) { + CompilerType integer_type = GetType(enum_decl->getIntegerType()); + + clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; + for (enum_pos = enum_decl->enumerator_begin(), + enum_end_pos = enum_decl->enumerator_end(); + enum_pos != enum_end_pos; ++enum_pos) { + ConstString name(enum_pos->getNameAsString().c_str()); + if (!callback(integer_type, name, enum_pos->getInitVal())) + break; + } + } + } +} + +#pragma mark Aggregate Types + +uint32_t TypeSystemClang::GetNumFields(lldb::opaque_compiler_type_t type) { + if (!type) + return 0; + + uint32_t count = 0; + clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: + if (GetCompleteType(type)) { + const clang::RecordType *record_type = + llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr()); + 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; + } + } + } + break; + + case clang::Type::ObjCObjectPointer: { + const clang::ObjCObjectPointerType *objc_class_type = + qual_type->getAs<clang::ObjCObjectPointerType>(); + const clang::ObjCInterfaceType *objc_interface_type = + objc_class_type->getInterfaceType(); + if (objc_interface_type && + GetCompleteType(static_cast<lldb::opaque_compiler_type_t>( + const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_interface_type->getDecl(); + if (class_interface_decl) { + count = class_interface_decl->ivar_size(); + } + } + break; + } + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + + if (class_interface_decl) + count = class_interface_decl->ivar_size(); + } + } + break; + + default: + break; + } + return count; +} + +static lldb::opaque_compiler_type_t +GetObjCFieldAtIndex(clang::ASTContext *ast, + clang::ObjCInterfaceDecl *class_interface_decl, size_t idx, + std::string &name, uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) { + if (class_interface_decl) { + if (idx < (class_interface_decl->ivar_size())) { + clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, + ivar_end = class_interface_decl->ivar_end(); + uint32_t ivar_idx = 0; + + for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; + ++ivar_pos, ++ivar_idx) { + if (ivar_idx == idx) { + const clang::ObjCIvarDecl *ivar_decl = *ivar_pos; + + clang::QualType ivar_qual_type(ivar_decl->getType()); + + name.assign(ivar_decl->getNameAsString()); + + if (bit_offset_ptr) { + const clang::ASTRecordLayout &interface_layout = + ast->getASTObjCInterfaceLayout(class_interface_decl); + *bit_offset_ptr = interface_layout.getFieldOffset(ivar_idx); + } + + const bool is_bitfield = ivar_pos->isBitField(); + + if (bitfield_bit_size_ptr) { + *bitfield_bit_size_ptr = 0; + + if (is_bitfield && ast) { + clang::Expr *bitfield_bit_size_expr = ivar_pos->getBitWidth(); + clang::Expr::EvalResult result; + if (bitfield_bit_size_expr && + bitfield_bit_size_expr->EvaluateAsInt(result, *ast)) { + llvm::APSInt bitfield_apsint = result.Val.getInt(); + *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue(); + } + } + } + if (is_bitfield_ptr) + *is_bitfield_ptr = is_bitfield; + + return ivar_qual_type.getAsOpaquePtr(); + } + } + } + } + return nullptr; +} + +CompilerType TypeSystemClang::GetFieldAtIndex(lldb::opaque_compiler_type_t type, + size_t idx, std::string &name, + uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, + bool *is_bitfield_ptr) { + if (!type) + return CompilerType(); + + clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + 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(); + 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) { + if (idx == field_idx) { + // Print the member type if requested + // Print the member name and equal sign + name.assign(field->getNameAsString()); + + // Figure out the type byte size (field_type_info.first) and + // alignment (field_type_info.second) from the AST context. + if (bit_offset_ptr) { + const clang::ASTRecordLayout &record_layout = + getASTContext().getASTRecordLayout(record_decl); + *bit_offset_ptr = record_layout.getFieldOffset(field_idx); + } + + const bool is_bitfield = field->isBitField(); + + if (bitfield_bit_size_ptr) { + *bitfield_bit_size_ptr = 0; + + if (is_bitfield) { + clang::Expr *bitfield_bit_size_expr = field->getBitWidth(); + clang::Expr::EvalResult result; + if (bitfield_bit_size_expr && + bitfield_bit_size_expr->EvaluateAsInt(result, + getASTContext())) { + llvm::APSInt bitfield_apsint = result.Val.getInt(); + *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue(); + } + } + } + if (is_bitfield_ptr) + *is_bitfield_ptr = is_bitfield; + + return GetType(field->getType()); + } + } + } + break; + + case clang::Type::ObjCObjectPointer: { + const clang::ObjCObjectPointerType *objc_class_type = + qual_type->getAs<clang::ObjCObjectPointerType>(); + const clang::ObjCInterfaceType *objc_interface_type = + objc_class_type->getInterfaceType(); + if (objc_interface_type && + GetCompleteType(static_cast<lldb::opaque_compiler_type_t>( + const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_interface_type->getDecl(); + if (class_interface_decl) { + return CompilerType( + this, GetObjCFieldAtIndex(&getASTContext(), class_interface_decl, + idx, name, bit_offset_ptr, + bitfield_bit_size_ptr, is_bitfield_ptr)); + } + } + break; + } + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert(objc_class_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + return CompilerType( + this, GetObjCFieldAtIndex(&getASTContext(), class_interface_decl, + idx, name, bit_offset_ptr, + bitfield_bit_size_ptr, is_bitfield_ptr)); + } + } + break; + + default: + break; + } + return CompilerType(); +} + +uint32_t +TypeSystemClang::GetNumDirectBaseClasses(lldb::opaque_compiler_type_t type) { + uint32_t count = 0; + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: + if (GetCompleteType(type)) { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + count = cxx_record_decl->getNumBases(); + } + break; + + case clang::Type::ObjCObjectPointer: + count = GetPointeeType(type).GetNumDirectBaseClasses(); + break; + + case clang::Type::ObjCObject: + if (GetCompleteType(type)) { + const clang::ObjCObjectType *objc_class_type = + qual_type->getAsObjCQualifiedInterfaceType(); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + + if (class_interface_decl && class_interface_decl->getSuperClass()) + count = 1; + } + } + break; + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) { + const clang::ObjCInterfaceType *objc_interface_type = + qual_type->getAs<clang::ObjCInterfaceType>(); + if (objc_interface_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_interface_type->getInterface(); + + if (class_interface_decl && class_interface_decl->getSuperClass()) + count = 1; + } + } + break; + + default: + break; + } + return count; +} + +uint32_t +TypeSystemClang::GetNumVirtualBaseClasses(lldb::opaque_compiler_type_t type) { + uint32_t count = 0; + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: + if (GetCompleteType(type)) { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + count = cxx_record_decl->getNumVBases(); + } + break; + + default: + break; + } + return count; +} + +CompilerType TypeSystemClang::GetDirectBaseClassAtIndex( + lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: + if (GetCompleteType(type)) { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + uint32_t curr_idx = 0; + 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, ++curr_idx) { + if (curr_idx == idx) { + if (bit_offset_ptr) { + const clang::ASTRecordLayout &record_layout = + getASTContext().getASTRecordLayout(cxx_record_decl); + const clang::CXXRecordDecl *base_class_decl = + llvm::cast<clang::CXXRecordDecl>( + base_class->getType() + ->getAs<clang::RecordType>() + ->getDecl()); + if (base_class->isVirtual()) + *bit_offset_ptr = + record_layout.getVBaseClassOffset(base_class_decl) + .getQuantity() * + 8; + else + *bit_offset_ptr = + record_layout.getBaseClassOffset(base_class_decl) + .getQuantity() * + 8; + } + return GetType(base_class->getType()); + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + return GetPointeeType(type).GetDirectBaseClassAtIndex(idx, bit_offset_ptr); + + case clang::Type::ObjCObject: + if (idx == 0 && GetCompleteType(type)) { + const clang::ObjCObjectType *objc_class_type = + qual_type->getAsObjCQualifiedInterfaceType(); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + + if (class_interface_decl) { + clang::ObjCInterfaceDecl *superclass_interface_decl = + class_interface_decl->getSuperClass(); + if (superclass_interface_decl) { + if (bit_offset_ptr) + *bit_offset_ptr = 0; + return GetType(getASTContext().getObjCInterfaceType( + superclass_interface_decl)); + } + } + } + } + break; + case clang::Type::ObjCInterface: + if (idx == 0 && GetCompleteType(type)) { + const clang::ObjCObjectType *objc_interface_type = + qual_type->getAs<clang::ObjCInterfaceType>(); + if (objc_interface_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_interface_type->getInterface(); + + if (class_interface_decl) { + clang::ObjCInterfaceDecl *superclass_interface_decl = + class_interface_decl->getSuperClass(); + if (superclass_interface_decl) { + if (bit_offset_ptr) + *bit_offset_ptr = 0; + return GetType(getASTContext().getObjCInterfaceType( + superclass_interface_decl)); + } + } + } + } + break; + + default: + break; + } + return CompilerType(); +} + +CompilerType TypeSystemClang::GetVirtualBaseClassAtIndex( + lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: + if (GetCompleteType(type)) { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + uint32_t curr_idx = 0; + clang::CXXRecordDecl::base_class_const_iterator base_class, + base_class_end; + for (base_class = cxx_record_decl->vbases_begin(), + base_class_end = cxx_record_decl->vbases_end(); + base_class != base_class_end; ++base_class, ++curr_idx) { + if (curr_idx == idx) { + if (bit_offset_ptr) { + const clang::ASTRecordLayout &record_layout = + getASTContext().getASTRecordLayout(cxx_record_decl); + const clang::CXXRecordDecl *base_class_decl = + llvm::cast<clang::CXXRecordDecl>( + base_class->getType() + ->getAs<clang::RecordType>() + ->getDecl()); + *bit_offset_ptr = + record_layout.getVBaseClassOffset(base_class_decl) + .getQuantity() * + 8; + } + return GetType(base_class->getType()); + } + } + } + } + break; + + default: + break; + } + return CompilerType(); +} + +// If a pointer to a pointee type (the clang_type arg) says that it has no +// children, then we either need to trust it, or override it and return a +// different result. For example, an "int *" has one child that is an integer, +// but a function pointer doesn't have any children. Likewise if a Record type +// claims it has no children, then there really is nothing to show. +uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) { + if (type.isNull()) + return 0; + + clang::QualType qual_type = RemoveWrappingTypes(type.getCanonicalType()); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Builtin: + switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) { + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::Void: + case clang::BuiltinType::NullPtr: + case clang::BuiltinType::OCLEvent: + case clang::BuiltinType::OCLImage1dRO: + case clang::BuiltinType::OCLImage1dWO: + case clang::BuiltinType::OCLImage1dRW: + case clang::BuiltinType::OCLImage1dArrayRO: + case clang::BuiltinType::OCLImage1dArrayWO: + case clang::BuiltinType::OCLImage1dArrayRW: + case clang::BuiltinType::OCLImage1dBufferRO: + case clang::BuiltinType::OCLImage1dBufferWO: + case clang::BuiltinType::OCLImage1dBufferRW: + case clang::BuiltinType::OCLImage2dRO: + case clang::BuiltinType::OCLImage2dWO: + case clang::BuiltinType::OCLImage2dRW: + case clang::BuiltinType::OCLImage2dArrayRO: + case clang::BuiltinType::OCLImage2dArrayWO: + case clang::BuiltinType::OCLImage2dArrayRW: + case clang::BuiltinType::OCLImage3dRO: + case clang::BuiltinType::OCLImage3dWO: + case clang::BuiltinType::OCLImage3dRW: + case clang::BuiltinType::OCLSampler: + return 0; + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + case clang::BuiltinType::Dependent: + case clang::BuiltinType::Overload: + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCSel: + case clang::BuiltinType::BoundMember: + case clang::BuiltinType::Half: + case clang::BuiltinType::ARCUnbridgedCast: + case clang::BuiltinType::PseudoObject: + case clang::BuiltinType::BuiltinFn: + case clang::BuiltinType::OMPArraySection: + return 1; + default: + return 0; + } + break; + + case clang::Type::Complex: + return 1; + case clang::Type::Pointer: + return 1; + case clang::Type::BlockPointer: + return 0; // If block pointers don't have debug info, then no children for + // them + case clang::Type::LValueReference: + return 1; + case clang::Type::RValueReference: + return 1; + case clang::Type::MemberPointer: + return 0; + case clang::Type::ConstantArray: + return 0; + case clang::Type::IncompleteArray: + return 0; + case clang::Type::VariableArray: + return 0; + case clang::Type::DependentSizedArray: + return 0; + case clang::Type::DependentSizedExtVector: + return 0; + case clang::Type::Vector: + return 0; + case clang::Type::ExtVector: + return 0; + case clang::Type::FunctionProto: + return 0; // When we function pointers, they have no children... + case clang::Type::FunctionNoProto: + return 0; // When we function pointers, they have no children... + case clang::Type::UnresolvedUsing: + return 0; + case clang::Type::Record: + return 0; + case clang::Type::Enum: + return 1; + case clang::Type::TemplateTypeParm: + return 1; + case clang::Type::SubstTemplateTypeParm: + return 1; + case clang::Type::TemplateSpecialization: + return 1; + case clang::Type::InjectedClassName: + return 0; + case clang::Type::DependentName: + return 1; + case clang::Type::DependentTemplateSpecialization: + return 1; + case clang::Type::ObjCObject: + return 0; + case clang::Type::ObjCInterface: + return 0; + case clang::Type::ObjCObjectPointer: + return 1; + default: + break; + } + return 0; +} + +CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex( + lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, + bool transparent_pointers, bool omit_empty_base_classes, + bool ignore_array_bounds, std::string &child_name, + uint32_t &child_byte_size, int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset, + bool &child_is_base_class, bool &child_is_deref_of_parent, + ValueObject *valobj, uint64_t &language_flags) { + if (!type) + return CompilerType(); + + auto get_exe_scope = [&exe_ctx]() { + return exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr; + }; + + clang::QualType parent_qual_type( + RemoveWrappingTypes(GetCanonicalQualType(type))); + const clang::Type::TypeClass parent_type_class = + parent_qual_type->getTypeClass(); + child_bitfield_bit_size = 0; + child_bitfield_bit_offset = 0; + child_is_base_class = false; + language_flags = 0; + + const bool idx_is_valid = + idx < GetNumChildren(type, omit_empty_base_classes, exe_ctx); + int32_t bit_offset; + switch (parent_type_class) { + case clang::Type::Builtin: + if (idx_is_valid) { + switch (llvm::cast<clang::BuiltinType>(parent_qual_type)->getKind()) { + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + child_name = "isa"; + child_byte_size = + getASTContext().getTypeSize(getASTContext().ObjCBuiltinClassTy) / + CHAR_BIT; + return GetType(getASTContext().ObjCBuiltinClassTy); + + default: + break; + } + } + break; + + case clang::Type::Record: + if (idx_is_valid && GetCompleteType(type)) { + const clang::RecordType *record_type = + llvm::cast<clang::RecordType>(parent_qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + 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 = nullptr; + + // Skip empty base classes + if (omit_empty_base_classes) { + base_class_decl = llvm::cast<clang::CXXRecordDecl>( + base_class->getType()->getAs<clang::RecordType>()->getDecl()); + if (!TypeSystemClang::RecordHasFields(base_class_decl)) + continue; + } + + if (idx == child_idx) { + if (base_class_decl == nullptr) + base_class_decl = llvm::cast<clang::CXXRecordDecl>( + base_class->getType()->getAs<clang::RecordType>()->getDecl()); + + if (base_class->isVirtual()) { + bool handled = false; + if (valobj) { + clang::VTableContextBase *vtable_ctx = + getASTContext().getVTableContext(); + if (vtable_ctx) + handled = GetVBaseBitOffset(*vtable_ctx, *valobj, + record_layout, cxx_record_decl, + base_class_decl, bit_offset); + } + if (!handled) + bit_offset = record_layout.getVBaseClassOffset(base_class_decl) + .getQuantity() * + 8; + } else + bit_offset = record_layout.getBaseClassOffset(base_class_decl) + .getQuantity() * + 8; + + // Base classes should be a multiple of 8 bits in size + child_byte_offset = bit_offset / 8; + CompilerType base_class_clang_type = GetType(base_class->getType()); + child_name = base_class_clang_type.GetTypeName().AsCString(""); + Optional<uint64_t> size = + base_class_clang_type.GetBitSize(get_exe_scope()); + if (!size) + return {}; + uint64_t base_class_clang_type_bit_size = *size; + + // Base classes bit sizes should be a multiple of 8 bits in size + assert(base_class_clang_type_bit_size % 8 == 0); + child_byte_size = base_class_clang_type_bit_size / 8; + child_is_base_class = true; + return base_class_clang_type; + } + // We don't increment the child index in the for loop since we might + // be skipping empty base classes + ++child_idx; + } + } + // Make sure index is in range... + 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) { + if (idx == child_idx) { + // Print the member type if requested + // Print the member name and equal sign + child_name.assign(field->getNameAsString()); + + // Figure out the type byte size (field_type_info.first) and + // alignment (field_type_info.second) from the AST context. + CompilerType field_clang_type = GetType(field->getType()); + assert(field_idx < record_layout.getFieldCount()); + Optional<uint64_t> size = + field_clang_type.GetByteSize(get_exe_scope()); + if (!size) + return {}; + child_byte_size = *size; + const uint32_t child_bit_size = child_byte_size * 8; + + // Figure out the field offset within the current struct/union/class + // type + bit_offset = record_layout.getFieldOffset(field_idx); + if (FieldIsBitfield(*field, child_bitfield_bit_size)) { + child_bitfield_bit_offset = bit_offset % child_bit_size; + const uint32_t child_bit_offset = + bit_offset - child_bitfield_bit_offset; + child_byte_offset = child_bit_offset / 8; + } else { + child_byte_offset = bit_offset / 8; + } + + return field_clang_type; + } + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (idx_is_valid && GetCompleteType(type)) { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(parent_qual_type.getTypePtr()); + assert(objc_class_type); + if (objc_class_type) { + uint32_t child_idx = 0; + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + + if (class_interface_decl) { + + const clang::ASTRecordLayout &interface_layout = + getASTContext().getASTObjCInterfaceLayout(class_interface_decl); + clang::ObjCInterfaceDecl *superclass_interface_decl = + class_interface_decl->getSuperClass(); + if (superclass_interface_decl) { + if (omit_empty_base_classes) { + CompilerType base_class_clang_type = + GetType(getASTContext().getObjCInterfaceType( + superclass_interface_decl)); + if (base_class_clang_type.GetNumChildren(omit_empty_base_classes, + exe_ctx) > 0) { + if (idx == 0) { + clang::QualType ivar_qual_type( + getASTContext().getObjCInterfaceType( + superclass_interface_decl)); + + child_name.assign( + superclass_interface_decl->getNameAsString()); + + clang::TypeInfo ivar_type_info = + getASTContext().getTypeInfo(ivar_qual_type.getTypePtr()); + + child_byte_size = ivar_type_info.Width / 8; + child_byte_offset = 0; + child_is_base_class = true; + + return GetType(ivar_qual_type); + } + + ++child_idx; + } + } else + ++child_idx; + } + + const uint32_t superclass_idx = child_idx; + + if (idx < (child_idx + class_interface_decl->ivar_size())) { + clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, + ivar_end = class_interface_decl->ivar_end(); + + for (ivar_pos = class_interface_decl->ivar_begin(); + ivar_pos != ivar_end; ++ivar_pos) { + if (child_idx == idx) { + clang::ObjCIvarDecl *ivar_decl = *ivar_pos; + + clang::QualType ivar_qual_type(ivar_decl->getType()); + + child_name.assign(ivar_decl->getNameAsString()); + + clang::TypeInfo ivar_type_info = + getASTContext().getTypeInfo(ivar_qual_type.getTypePtr()); + + child_byte_size = ivar_type_info.Width / 8; + + // Figure out the field offset within the current + // struct/union/class type For ObjC objects, we can't trust the + // bit offset we get from the Clang AST, since that doesn't + // account for the space taken up by unbacked properties, or + // from the changing size of base classes that are newer than + // this class. So if we have a process around that we can ask + // about this object, do so. + child_byte_offset = LLDB_INVALID_IVAR_OFFSET; + Process *process = nullptr; + if (exe_ctx) + process = exe_ctx->GetProcessPtr(); + if (process) { + ObjCLanguageRuntime *objc_runtime = + ObjCLanguageRuntime::Get(*process); + if (objc_runtime != nullptr) { + CompilerType parent_ast_type = GetType(parent_qual_type); + child_byte_offset = objc_runtime->GetByteOffsetForIvar( + parent_ast_type, ivar_decl->getNameAsString().c_str()); + } + } + + // Setting this to INT32_MAX to make sure we don't compute it + // twice... + bit_offset = INT32_MAX; + + if (child_byte_offset == + static_cast<int32_t>(LLDB_INVALID_IVAR_OFFSET)) { + bit_offset = interface_layout.getFieldOffset(child_idx - + superclass_idx); + child_byte_offset = bit_offset / 8; + } + + // Note, the ObjC Ivar Byte offset is just that, it doesn't + // account for the bit offset of a bitfield within its + // containing object. So regardless of where we get the byte + // offset from, we still need to get the bit offset for + // bitfields from the layout. + + if (FieldIsBitfield(ivar_decl, child_bitfield_bit_size)) { + if (bit_offset == INT32_MAX) + bit_offset = interface_layout.getFieldOffset( + child_idx - superclass_idx); + + child_bitfield_bit_offset = bit_offset % 8; + } + return GetType(ivar_qual_type); + } + ++child_idx; + } + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: + if (idx_is_valid) { + CompilerType pointee_clang_type(GetPointeeType(type)); + + if (transparent_pointers && pointee_clang_type.IsAggregateType()) { + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return pointee_clang_type.GetChildCompilerTypeAtIndex( + exe_ctx, idx, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, tmp_child_is_deref_of_parent, valobj, + language_flags); + } else { + child_is_deref_of_parent = true; + const char *parent_name = + valobj ? valobj->GetName().GetCString() : nullptr; + if (parent_name) { + child_name.assign(1, '*'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0 && pointee_clang_type.GetCompleteType()) { + if (Optional<uint64_t> size = + pointee_clang_type.GetByteSize(get_exe_scope())) { + child_byte_size = *size; + child_byte_offset = 0; + return pointee_clang_type; + } + } + } + } + break; + + case clang::Type::Vector: + case clang::Type::ExtVector: + if (idx_is_valid) { + const clang::VectorType *array = + llvm::cast<clang::VectorType>(parent_qual_type.getTypePtr()); + if (array) { + CompilerType element_type = GetType(array->getElementType()); + if (element_type.GetCompleteType()) { + char element_name[64]; + ::snprintf(element_name, sizeof(element_name), "[%" PRIu64 "]", + static_cast<uint64_t>(idx)); + child_name.assign(element_name); + if (Optional<uint64_t> size = + element_type.GetByteSize(get_exe_scope())) { + child_byte_size = *size; + child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; + return element_type; + } + } + } + } + break; + + case clang::Type::ConstantArray: + case clang::Type::IncompleteArray: + if (ignore_array_bounds || idx_is_valid) { + const clang::ArrayType *array = GetQualType(type)->getAsArrayTypeUnsafe(); + if (array) { + CompilerType element_type = GetType(array->getElementType()); + if (element_type.GetCompleteType()) { + child_name = std::string(llvm::formatv("[{0}]", idx)); + if (Optional<uint64_t> size = + element_type.GetByteSize(get_exe_scope())) { + child_byte_size = *size; + child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; + return element_type; + } + } + } + } + break; + + case clang::Type::Pointer: { + CompilerType pointee_clang_type(GetPointeeType(type)); + + // Don't dereference "void *" pointers + if (pointee_clang_type.IsVoidType()) + return CompilerType(); + + if (transparent_pointers && pointee_clang_type.IsAggregateType()) { + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return pointee_clang_type.GetChildCompilerTypeAtIndex( + exe_ctx, idx, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, tmp_child_is_deref_of_parent, valobj, + language_flags); + } else { + child_is_deref_of_parent = true; + + const char *parent_name = + valobj ? valobj->GetName().GetCString() : nullptr; + if (parent_name) { + child_name.assign(1, '*'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0) { + if (Optional<uint64_t> size = + pointee_clang_type.GetByteSize(get_exe_scope())) { + child_byte_size = *size; + child_byte_offset = 0; + return pointee_clang_type; + } + } + } + break; + } + + case clang::Type::LValueReference: + case clang::Type::RValueReference: + if (idx_is_valid) { + const clang::ReferenceType *reference_type = + llvm::cast<clang::ReferenceType>(parent_qual_type.getTypePtr()); + CompilerType pointee_clang_type = + GetType(reference_type->getPointeeType()); + if (transparent_pointers && pointee_clang_type.IsAggregateType()) { + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return pointee_clang_type.GetChildCompilerTypeAtIndex( + exe_ctx, idx, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, tmp_child_is_deref_of_parent, valobj, + language_flags); + } else { + const char *parent_name = + valobj ? valobj->GetName().GetCString() : nullptr; + if (parent_name) { + child_name.assign(1, '&'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0) { + if (Optional<uint64_t> size = + pointee_clang_type.GetByteSize(get_exe_scope())) { + child_byte_size = *size; + child_byte_offset = 0; + return pointee_clang_type; + } + } + } + } + break; + + default: + break; + } + return CompilerType(); +} + +static uint32_t GetIndexForRecordBase(const clang::RecordDecl *record_decl, + const clang::CXXBaseSpecifier *base_spec, + bool omit_empty_base_classes) { + uint32_t child_idx = 0; + + const clang::CXXRecordDecl *cxx_record_decl = + llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + + if (cxx_record_decl) { + 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) { + if (omit_empty_base_classes) { + if (BaseSpecifierIsEmpty(base_class)) + continue; + } + + if (base_class == base_spec) + return child_idx; + ++child_idx; + } + } + + return UINT32_MAX; +} + +static uint32_t GetIndexForRecordChild(const clang::RecordDecl *record_decl, + clang::NamedDecl *canonical_decl, + bool omit_empty_base_classes) { + uint32_t child_idx = TypeSystemClang::GetNumBaseClasses( + llvm::dyn_cast<clang::CXXRecordDecl>(record_decl), + omit_empty_base_classes); + + clang::RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; ++field, ++child_idx) { + if (field->getCanonicalDecl() == canonical_decl) + return child_idx; + } + + return UINT32_MAX; +} + +// Look for a child member (doesn't include base classes, but it does include +// their members) in the type hierarchy. Returns an index path into +// "clang_type" on how to reach the appropriate member. +// +// class A +// { +// public: +// int m_a; +// int m_b; +// }; +// +// class B +// { +// }; +// +// class C : +// public B, +// public A +// { +// }; +// +// If we have a clang type that describes "class C", and we wanted to looked +// "m_b" in it: +// +// With omit_empty_base_classes == false we would get an integer array back +// with: { 1, 1 } The first index 1 is the child index for "class A" within +// class C The second index 1 is the child index for "m_b" within class A +// +// With omit_empty_base_classes == true we would get an integer array back +// with: { 0, 1 } The first index 0 is the child index for "class A" within +// class C (since class B doesn't have any members it doesn't count) The second +// index 1 is the child index for "m_b" within class A + +size_t TypeSystemClang::GetIndexOfChildMemberWithName( + lldb::opaque_compiler_type_t type, const char *name, + bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) { + if (type && name && name[0]) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + 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 child_idx = 0; + + const clang::CXXRecordDecl *cxx_record_decl = + llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + + // Try and find a field that matches NAME + clang::RecordDecl::field_iterator field, field_end; + llvm::StringRef name_sref(name); + for (field = record_decl->field_begin(), + field_end = record_decl->field_end(); + field != field_end; ++field, ++child_idx) { + llvm::StringRef field_name = field->getName(); + if (field_name.empty()) { + CompilerType field_type = GetType(field->getType()); + child_indexes.push_back(child_idx); + if (field_type.GetIndexOfChildMemberWithName( + name, omit_empty_base_classes, child_indexes)) + return child_indexes.size(); + child_indexes.pop_back(); + + } else if (field_name.equals(name_sref)) { + // We have to add on the number of base classes to this index! + child_indexes.push_back( + child_idx + TypeSystemClang::GetNumBaseClasses( + cxx_record_decl, omit_empty_base_classes)); + return child_indexes.size(); + } + } + + if (cxx_record_decl) { + const clang::RecordDecl *parent_record_decl = cxx_record_decl; + + // Didn't find things easily, lets let clang do its thang... + clang::IdentifierInfo &ident_ref = + getASTContext().Idents.get(name_sref); + clang::DeclarationName decl_name(&ident_ref); + + clang::CXXBasePaths paths; + if (cxx_record_decl->lookupInBases( + [decl_name](const clang::CXXBaseSpecifier *specifier, + clang::CXXBasePath &path) { + return clang::CXXRecordDecl::FindOrdinaryMember( + specifier, path, decl_name); + }, + paths)) { + clang::CXXBasePaths::const_paths_iterator path, + path_end = paths.end(); + for (path = paths.begin(); path != path_end; ++path) { + const size_t num_path_elements = path->size(); + for (size_t e = 0; e < num_path_elements; ++e) { + clang::CXXBasePathElement elem = (*path)[e]; + + child_idx = GetIndexForRecordBase(parent_record_decl, elem.Base, + omit_empty_base_classes); + if (child_idx == UINT32_MAX) { + child_indexes.clear(); + return 0; + } else { + child_indexes.push_back(child_idx); + parent_record_decl = llvm::cast<clang::RecordDecl>( + elem.Base->getType() + ->getAs<clang::RecordType>() + ->getDecl()); + } + } + for (clang::NamedDecl *path_decl : path->Decls) { + child_idx = GetIndexForRecordChild( + parent_record_decl, path_decl, omit_empty_base_classes); + if (child_idx == UINT32_MAX) { + child_indexes.clear(); + return 0; + } else { + child_indexes.push_back(child_idx); + } + } + } + return child_indexes.size(); + } + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) { + llvm::StringRef name_sref(name); + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert(objc_class_type); + if (objc_class_type) { + uint32_t child_idx = 0; + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + + if (class_interface_decl) { + clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, + ivar_end = class_interface_decl->ivar_end(); + clang::ObjCInterfaceDecl *superclass_interface_decl = + class_interface_decl->getSuperClass(); + + for (ivar_pos = class_interface_decl->ivar_begin(); + ivar_pos != ivar_end; ++ivar_pos, ++child_idx) { + const clang::ObjCIvarDecl *ivar_decl = *ivar_pos; + + if (ivar_decl->getName().equals(name_sref)) { + if ((!omit_empty_base_classes && superclass_interface_decl) || + (omit_empty_base_classes && + ObjCDeclHasIVars(superclass_interface_decl, true))) + ++child_idx; + + child_indexes.push_back(child_idx); + return child_indexes.size(); + } + } + + if (superclass_interface_decl) { + // The super class index is always zero for ObjC classes, so we + // push it onto the child indexes in case we find an ivar in our + // superclass... + child_indexes.push_back(0); + + CompilerType superclass_clang_type = + GetType(getASTContext().getObjCInterfaceType( + superclass_interface_decl)); + if (superclass_clang_type.GetIndexOfChildMemberWithName( + name, omit_empty_base_classes, child_indexes)) { + // We did find an ivar in a superclass so just return the + // results! + return child_indexes.size(); + } + + // We didn't find an ivar matching "name" in our superclass, pop + // the superclass zero index that we pushed on above. + child_indexes.pop_back(); + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: { + CompilerType objc_object_clang_type = GetType( + llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr()) + ->getPointeeType()); + return objc_object_clang_type.GetIndexOfChildMemberWithName( + name, omit_empty_base_classes, child_indexes); + } break; + + case clang::Type::ConstantArray: { + // const clang::ConstantArrayType *array = + // llvm::cast<clang::ConstantArrayType>(parent_qual_type.getTypePtr()); + // const uint64_t element_count = + // array->getSize().getLimitedValue(); + // + // if (idx < element_count) + // { + // std::pair<uint64_t, unsigned> field_type_info = + // ast->getTypeInfo(array->getElementType()); + // + // char element_name[32]; + // ::snprintf (element_name, sizeof (element_name), + // "%s[%u]", parent_name ? parent_name : "", idx); + // + // child_name.assign(element_name); + // assert(field_type_info.first % 8 == 0); + // child_byte_size = field_type_info.first / 8; + // child_byte_offset = idx * child_byte_size; + // return array->getElementType().getAsOpaquePtr(); + // } + } break; + + // case clang::Type::MemberPointerType: + // { + // MemberPointerType *mem_ptr_type = + // llvm::cast<MemberPointerType>(qual_type.getTypePtr()); + // clang::QualType pointee_type = + // mem_ptr_type->getPointeeType(); + // + // if (TypeSystemClang::IsAggregateType + // (pointee_type.getAsOpaquePtr())) + // { + // return GetIndexOfChildWithName (ast, + // mem_ptr_type->getPointeeType().getAsOpaquePtr(), + // name); + // } + // } + // break; + // + case clang::Type::LValueReference: + case clang::Type::RValueReference: { + const clang::ReferenceType *reference_type = + llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + clang::QualType pointee_type(reference_type->getPointeeType()); + CompilerType pointee_clang_type = GetType(pointee_type); + + if (pointee_clang_type.IsAggregateType()) { + return pointee_clang_type.GetIndexOfChildMemberWithName( + name, omit_empty_base_classes, child_indexes); + } + } break; + + case clang::Type::Pointer: { + CompilerType pointee_clang_type(GetPointeeType(type)); + + if (pointee_clang_type.IsAggregateType()) { + return pointee_clang_type.GetIndexOfChildMemberWithName( + name, omit_empty_base_classes, child_indexes); + } + } break; + + default: + break; + } + } + return 0; +} + +// Get the index of the child of "clang_type" whose name matches. This function +// doesn't descend into the children, but only looks one level deep and name +// matches can include base class names. + +uint32_t +TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, + const char *name, + bool omit_empty_base_classes) { + if (type && name && name[0]) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + + switch (type_class) { + 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 child_idx = 0; + + const clang::CXXRecordDecl *cxx_record_decl = + llvm::dyn_cast<clang::CXXRecordDecl>(record_decl); + + if (cxx_record_decl) { + 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) { + // Skip empty base classes + clang::CXXRecordDecl *base_class_decl = + llvm::cast<clang::CXXRecordDecl>( + base_class->getType() + ->getAs<clang::RecordType>() + ->getDecl()); + if (omit_empty_base_classes && + !TypeSystemClang::RecordHasFields(base_class_decl)) + continue; + + CompilerType base_class_clang_type = GetType(base_class->getType()); + std::string base_class_type_name( + base_class_clang_type.GetTypeName().AsCString("")); + if (base_class_type_name == name) + return child_idx; + ++child_idx; + } + } + + // Try and find a field that matches NAME + clang::RecordDecl::field_iterator field, field_end; + llvm::StringRef name_sref(name); + for (field = record_decl->field_begin(), + field_end = record_decl->field_end(); + field != field_end; ++field, ++child_idx) { + if (field->getName().equals(name_sref)) + return child_idx; + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (GetCompleteType(type)) { + llvm::StringRef name_sref(name); + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert(objc_class_type); + if (objc_class_type) { + uint32_t child_idx = 0; + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + + if (class_interface_decl) { + clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, + ivar_end = class_interface_decl->ivar_end(); + clang::ObjCInterfaceDecl *superclass_interface_decl = + class_interface_decl->getSuperClass(); + + for (ivar_pos = class_interface_decl->ivar_begin(); + ivar_pos != ivar_end; ++ivar_pos, ++child_idx) { + const clang::ObjCIvarDecl *ivar_decl = *ivar_pos; + + if (ivar_decl->getName().equals(name_sref)) { + if ((!omit_empty_base_classes && superclass_interface_decl) || + (omit_empty_base_classes && + ObjCDeclHasIVars(superclass_interface_decl, true))) + ++child_idx; + + return child_idx; + } + } + + if (superclass_interface_decl) { + if (superclass_interface_decl->getName().equals(name_sref)) + return 0; + } + } + } + } + break; + + case clang::Type::ObjCObjectPointer: { + CompilerType pointee_clang_type = GetType( + llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr()) + ->getPointeeType()); + return pointee_clang_type.GetIndexOfChildWithName( + name, omit_empty_base_classes); + } break; + + case clang::Type::ConstantArray: { + // const clang::ConstantArrayType *array = + // llvm::cast<clang::ConstantArrayType>(parent_qual_type.getTypePtr()); + // const uint64_t element_count = + // array->getSize().getLimitedValue(); + // + // if (idx < element_count) + // { + // std::pair<uint64_t, unsigned> field_type_info = + // ast->getTypeInfo(array->getElementType()); + // + // char element_name[32]; + // ::snprintf (element_name, sizeof (element_name), + // "%s[%u]", parent_name ? parent_name : "", idx); + // + // child_name.assign(element_name); + // assert(field_type_info.first % 8 == 0); + // child_byte_size = field_type_info.first / 8; + // child_byte_offset = idx * child_byte_size; + // return array->getElementType().getAsOpaquePtr(); + // } + } break; + + // case clang::Type::MemberPointerType: + // { + // MemberPointerType *mem_ptr_type = + // llvm::cast<MemberPointerType>(qual_type.getTypePtr()); + // clang::QualType pointee_type = + // mem_ptr_type->getPointeeType(); + // + // if (TypeSystemClang::IsAggregateType + // (pointee_type.getAsOpaquePtr())) + // { + // return GetIndexOfChildWithName (ast, + // mem_ptr_type->getPointeeType().getAsOpaquePtr(), + // name); + // } + // } + // break; + // + case clang::Type::LValueReference: + case clang::Type::RValueReference: { + const clang::ReferenceType *reference_type = + llvm::cast<clang::ReferenceType>(qual_type.getTypePtr()); + CompilerType pointee_type = GetType(reference_type->getPointeeType()); + + if (pointee_type.IsAggregateType()) { + return pointee_type.GetIndexOfChildWithName(name, + omit_empty_base_classes); + } + } break; + + case clang::Type::Pointer: { + const clang::PointerType *pointer_type = + llvm::cast<clang::PointerType>(qual_type.getTypePtr()); + CompilerType pointee_type = GetType(pointer_type->getPointeeType()); + + if (pointee_type.IsAggregateType()) { + return pointee_type.GetIndexOfChildWithName(name, + omit_empty_base_classes); + } else { + // if (parent_name) + // { + // child_name.assign(1, '*'); + // child_name += parent_name; + // } + // + // // We have a pointer to an simple type + // if (idx == 0) + // { + // std::pair<uint64_t, unsigned> clang_type_info + // = ast->getTypeInfo(pointee_type); + // assert(clang_type_info.first % 8 == 0); + // child_byte_size = clang_type_info.first / 8; + // child_byte_offset = 0; + // return pointee_type.getAsOpaquePtr(); + // } + } + } break; + + default: + break; + } + } + return UINT32_MAX; +} + +size_t +TypeSystemClang::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) { + if (!type) + return 0; + + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: + if (GetCompleteType(type)) { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + const clang::ClassTemplateSpecializationDecl *template_decl = + llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>( + cxx_record_decl); + if (template_decl) + return template_decl->getTemplateArgs().size(); + } + } + break; + + default: + break; + } + + return 0; +} + +const clang::ClassTemplateSpecializationDecl * +TypeSystemClang::GetAsTemplateSpecialization( + lldb::opaque_compiler_type_t type) { + if (!type) + return nullptr; + + clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: { + if (! GetCompleteType(type)) + return nullptr; + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (!cxx_record_decl) + return nullptr; + return llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>( + cxx_record_decl); + } + + default: + return nullptr; + } +} + +lldb::TemplateArgumentKind +TypeSystemClang::GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, + size_t arg_idx) { + const clang::ClassTemplateSpecializationDecl *template_decl = + GetAsTemplateSpecialization(type); + if (! template_decl || arg_idx >= template_decl->getTemplateArgs().size()) + return eTemplateArgumentKindNull; + + switch (template_decl->getTemplateArgs()[arg_idx].getKind()) { + case clang::TemplateArgument::Null: + return eTemplateArgumentKindNull; + + case clang::TemplateArgument::NullPtr: + return eTemplateArgumentKindNullPtr; + + case clang::TemplateArgument::Type: + return eTemplateArgumentKindType; + + case clang::TemplateArgument::Declaration: + return eTemplateArgumentKindDeclaration; + + case clang::TemplateArgument::Integral: + return eTemplateArgumentKindIntegral; + + case clang::TemplateArgument::Template: + return eTemplateArgumentKindTemplate; + + case clang::TemplateArgument::TemplateExpansion: + return eTemplateArgumentKindTemplateExpansion; + + case clang::TemplateArgument::Expression: + return eTemplateArgumentKindExpression; + + case clang::TemplateArgument::Pack: + return eTemplateArgumentKindPack; + } + llvm_unreachable("Unhandled clang::TemplateArgument::ArgKind"); +} + +CompilerType +TypeSystemClang::GetTypeTemplateArgument(lldb::opaque_compiler_type_t type, + size_t idx) { + const clang::ClassTemplateSpecializationDecl *template_decl = + GetAsTemplateSpecialization(type); + if (!template_decl || idx >= template_decl->getTemplateArgs().size()) + return CompilerType(); + + const clang::TemplateArgument &template_arg = + template_decl->getTemplateArgs()[idx]; + if (template_arg.getKind() != clang::TemplateArgument::Type) + return CompilerType(); + + return GetType(template_arg.getAsType()); +} + +Optional<CompilerType::IntegralTemplateArgument> +TypeSystemClang::GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, + size_t idx) { + const clang::ClassTemplateSpecializationDecl *template_decl = + GetAsTemplateSpecialization(type); + if (! template_decl || idx >= template_decl->getTemplateArgs().size()) + return llvm::None; + + const clang::TemplateArgument &template_arg = + template_decl->getTemplateArgs()[idx]; + if (template_arg.getKind() != clang::TemplateArgument::Integral) + return llvm::None; + + return { + {template_arg.getAsIntegral(), GetType(template_arg.getIntegralType())}}; +} + +CompilerType TypeSystemClang::GetTypeForFormatters(void *type) { + if (type) + return ClangUtil::RemoveFastQualifiers(CompilerType(this, type)); + return CompilerType(); +} + +clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) { + const clang::EnumType *enutype = + llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type)); + if (enutype) + return enutype->getDecl(); + return nullptr; +} + +clang::RecordDecl *TypeSystemClang::GetAsRecordDecl(const CompilerType &type) { + const clang::RecordType *record_type = + llvm::dyn_cast<clang::RecordType>(ClangUtil::GetCanonicalQualType(type)); + if (record_type) + return record_type->getDecl(); + return nullptr; +} + +clang::TagDecl *TypeSystemClang::GetAsTagDecl(const CompilerType &type) { + return ClangUtil::GetAsTagDecl(type); +} + +clang::TypedefNameDecl * +TypeSystemClang::GetAsTypedefDecl(const CompilerType &type) { + const clang::TypedefType *typedef_type = + llvm::dyn_cast<clang::TypedefType>(ClangUtil::GetQualType(type)); + if (typedef_type) + return typedef_type->getDecl(); + return nullptr; +} + +clang::CXXRecordDecl * +TypeSystemClang::GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type) { + return GetCanonicalQualType(type)->getAsCXXRecordDecl(); +} + +clang::ObjCInterfaceDecl * +TypeSystemClang::GetAsObjCInterfaceDecl(const CompilerType &type) { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>( + ClangUtil::GetCanonicalQualType(type)); + if (objc_class_type) + return objc_class_type->getInterface(); + return nullptr; +} + +clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( + const CompilerType &type, llvm::StringRef name, + const CompilerType &field_clang_type, AccessType access, + uint32_t bitfield_bit_size) { + if (!type.IsValid() || !field_clang_type.IsValid()) + return nullptr; + TypeSystemClang *ast = + llvm::dyn_cast_or_null<TypeSystemClang>(type.GetTypeSystem()); + if (!ast) + return nullptr; + clang::ASTContext &clang_ast = ast->getASTContext(); + clang::IdentifierInfo *ident = nullptr; + if (!name.empty()) + ident = &clang_ast.Idents.get(name); + + clang::FieldDecl *field = nullptr; + + clang::Expr *bit_width = nullptr; + if (bitfield_bit_size != 0) { + llvm::APInt bitfield_bit_size_apint(clang_ast.getTypeSize(clang_ast.IntTy), + bitfield_bit_size); + bit_width = new (clang_ast) + clang::IntegerLiteral(clang_ast, bitfield_bit_size_apint, + clang_ast.IntTy, clang::SourceLocation()); + } + + clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type); + if (record_decl) { + field = clang::FieldDecl::CreateDeserialized(clang_ast, 0); + field->setDeclContext(record_decl); + field->setDeclName(ident); + field->setType(ClangUtil::GetQualType(field_clang_type)); + if (bit_width) + field->setBitWidth(bit_width); + SetMemberOwningModule(field, record_decl); + + if (name.empty()) { + // Determine whether this field corresponds to an anonymous struct or + // union. + if (const clang::TagType *TagT = + field->getType()->getAs<clang::TagType>()) { + if (clang::RecordDecl *Rec = + llvm::dyn_cast<clang::RecordDecl>(TagT->getDecl())) + if (!Rec->getDeclName()) { + Rec->setAnonymousStructOrUnion(true); + field->setImplicit(); + } + } + } + + if (field) { + field->setAccess( + TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access)); + + record_decl->addDecl(field); + + VerifyDecl(field); + } + } else { + clang::ObjCInterfaceDecl *class_interface_decl = + ast->GetAsObjCInterfaceDecl(type); + + if (class_interface_decl) { + const bool is_synthesized = false; + + field_clang_type.GetCompleteType(); + + auto *ivar = clang::ObjCIvarDecl::CreateDeserialized(clang_ast, 0); + ivar->setDeclContext(class_interface_decl); + ivar->setDeclName(ident); + ivar->setType(ClangUtil::GetQualType(field_clang_type)); + ivar->setAccessControl(ConvertAccessTypeToObjCIvarAccessControl(access)); + if (bit_width) + ivar->setBitWidth(bit_width); + ivar->setSynthesize(is_synthesized); + field = ivar; + SetMemberOwningModule(field, class_interface_decl); + + if (field) { + class_interface_decl->addDecl(field); + + VerifyDecl(field); + } + } + } + return field; +} + +void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { + if (!type) + return; + + TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!ast) + return; + + clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type); + + if (!record_decl) + return; + + typedef llvm::SmallVector<clang::IndirectFieldDecl *, 1> IndirectFieldVector; + + IndirectFieldVector indirect_fields; + clang::RecordDecl::field_iterator field_pos; + clang::RecordDecl::field_iterator field_end_pos = record_decl->field_end(); + clang::RecordDecl::field_iterator last_field_pos = field_end_pos; + for (field_pos = record_decl->field_begin(); field_pos != field_end_pos; + last_field_pos = field_pos++) { + if (field_pos->isAnonymousStructOrUnion()) { + clang::QualType field_qual_type = field_pos->getType(); + + const clang::RecordType *field_record_type = + field_qual_type->getAs<clang::RecordType>(); + + if (!field_record_type) + continue; + + clang::RecordDecl *field_record_decl = field_record_type->getDecl(); + + if (!field_record_decl) + continue; + + for (clang::RecordDecl::decl_iterator + di = field_record_decl->decls_begin(), + de = field_record_decl->decls_end(); + di != de; ++di) { + if (clang::FieldDecl *nested_field_decl = + llvm::dyn_cast<clang::FieldDecl>(*di)) { + clang::NamedDecl **chain = + new (ast->getASTContext()) clang::NamedDecl *[2]; + chain[0] = *field_pos; + chain[1] = nested_field_decl; + clang::IndirectFieldDecl *indirect_field = + clang::IndirectFieldDecl::Create( + ast->getASTContext(), record_decl, clang::SourceLocation(), + nested_field_decl->getIdentifier(), + nested_field_decl->getType(), {chain, 2}); + SetMemberOwningModule(indirect_field, record_decl); + + indirect_field->setImplicit(); + + indirect_field->setAccess(TypeSystemClang::UnifyAccessSpecifiers( + field_pos->getAccess(), nested_field_decl->getAccess())); + + indirect_fields.push_back(indirect_field); + } else if (clang::IndirectFieldDecl *nested_indirect_field_decl = + llvm::dyn_cast<clang::IndirectFieldDecl>(*di)) { + size_t nested_chain_size = + nested_indirect_field_decl->getChainingSize(); + clang::NamedDecl **chain = new (ast->getASTContext()) + clang::NamedDecl *[nested_chain_size + 1]; + chain[0] = *field_pos; + + int chain_index = 1; + for (clang::IndirectFieldDecl::chain_iterator + nci = nested_indirect_field_decl->chain_begin(), + nce = nested_indirect_field_decl->chain_end(); + nci < nce; ++nci) { + chain[chain_index] = *nci; + chain_index++; + } + + clang::IndirectFieldDecl *indirect_field = + clang::IndirectFieldDecl::Create( + ast->getASTContext(), record_decl, clang::SourceLocation(), + nested_indirect_field_decl->getIdentifier(), + nested_indirect_field_decl->getType(), + {chain, nested_chain_size + 1}); + SetMemberOwningModule(indirect_field, record_decl); + + indirect_field->setImplicit(); + + indirect_field->setAccess(TypeSystemClang::UnifyAccessSpecifiers( + field_pos->getAccess(), nested_indirect_field_decl->getAccess())); + + indirect_fields.push_back(indirect_field); + } + } + } + } + + // Check the last field to see if it has an incomplete array type as its last + // member and if it does, the tell the record decl about it + if (last_field_pos != field_end_pos) { + if (last_field_pos->getType()->isIncompleteArrayType()) + record_decl->hasFlexibleArrayMember(); + } + + for (IndirectFieldVector::iterator ifi = indirect_fields.begin(), + ife = indirect_fields.end(); + ifi < ife; ++ifi) { + record_decl->addDecl(*ifi); + } +} + +void TypeSystemClang::SetIsPacked(const CompilerType &type) { + if (type) { + TypeSystemClang *ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (ast) { + clang::RecordDecl *record_decl = GetAsRecordDecl(type); + + if (!record_decl) + return; + + record_decl->addAttr( + clang::PackedAttr::CreateImplicit(ast->getASTContext())); + } + } +} + +clang::VarDecl *TypeSystemClang::AddVariableToRecordType( + const CompilerType &type, llvm::StringRef name, + const CompilerType &var_type, AccessType access) { + if (!type.IsValid() || !var_type.IsValid()) + return nullptr; + + TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!ast) + return nullptr; + + clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type); + if (!record_decl) + return nullptr; + + clang::VarDecl *var_decl = nullptr; + clang::IdentifierInfo *ident = nullptr; + if (!name.empty()) + ident = &ast->getASTContext().Idents.get(name); + + var_decl = clang::VarDecl::CreateDeserialized(ast->getASTContext(), 0); + var_decl->setDeclContext(record_decl); + var_decl->setDeclName(ident); + var_decl->setType(ClangUtil::GetQualType(var_type)); + var_decl->setStorageClass(clang::SC_Static); + SetMemberOwningModule(var_decl, record_decl); + if (!var_decl) + return nullptr; + + var_decl->setAccess( + TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access)); + record_decl->addDecl(var_decl); + + VerifyDecl(var_decl); + + return var_decl; +} + +void TypeSystemClang::SetIntegerInitializerForVariable( + VarDecl *var, const llvm::APInt &init_value) { + assert(!var->hasInit() && "variable already initialized"); + + clang::ASTContext &ast = var->getASTContext(); + QualType qt = var->getType(); + assert(qt->isIntegralOrEnumerationType() && + "only integer or enum types supported"); + // If the variable is an enum type, take the underlying integer type as + // the type of the integer literal. + if (const EnumType *enum_type = llvm::dyn_cast<EnumType>(qt.getTypePtr())) { + const EnumDecl *enum_decl = enum_type->getDecl(); + qt = enum_decl->getIntegerType(); + } + var->setInit(IntegerLiteral::Create(ast, init_value, qt.getUnqualifiedType(), + SourceLocation())); +} + +void TypeSystemClang::SetFloatingInitializerForVariable( + clang::VarDecl *var, const llvm::APFloat &init_value) { + assert(!var->hasInit() && "variable already initialized"); + + clang::ASTContext &ast = var->getASTContext(); + QualType qt = var->getType(); + assert(qt->isFloatingType() && "only floating point types supported"); + var->setInit(FloatingLiteral::Create( + ast, init_value, true, qt.getUnqualifiedType(), SourceLocation())); +} + +clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( + lldb::opaque_compiler_type_t type, llvm::StringRef name, + const char *mangled_name, const CompilerType &method_clang_type, + lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, + bool is_explicit, bool is_attr_used, bool is_artificial) { + if (!type || !method_clang_type.IsValid() || name.empty()) + return nullptr; + + clang::QualType record_qual_type(GetCanonicalQualType(type)); + + clang::CXXRecordDecl *cxx_record_decl = + record_qual_type->getAsCXXRecordDecl(); + + if (cxx_record_decl == nullptr) + return nullptr; + + clang::QualType method_qual_type(ClangUtil::GetQualType(method_clang_type)); + + clang::CXXMethodDecl *cxx_method_decl = nullptr; + + clang::DeclarationName decl_name(&getASTContext().Idents.get(name)); + + const clang::FunctionType *function_type = + llvm::dyn_cast<clang::FunctionType>(method_qual_type.getTypePtr()); + + if (function_type == nullptr) + return nullptr; + + const clang::FunctionProtoType *method_function_prototype( + llvm::dyn_cast<clang::FunctionProtoType>(function_type)); + + if (!method_function_prototype) + return nullptr; + + unsigned int num_params = method_function_prototype->getNumParams(); + + clang::CXXDestructorDecl *cxx_dtor_decl(nullptr); + clang::CXXConstructorDecl *cxx_ctor_decl(nullptr); + + if (is_artificial) + return nullptr; // skip everything artificial + + const clang::ExplicitSpecifier explicit_spec( + nullptr /*expr*/, is_explicit ? clang::ExplicitSpecKind::ResolvedTrue + : clang::ExplicitSpecKind::ResolvedFalse); + + if (name.startswith("~")) { + cxx_dtor_decl = + clang::CXXDestructorDecl::CreateDeserialized(getASTContext(), 0); + cxx_dtor_decl->setDeclContext(cxx_record_decl); + cxx_dtor_decl->setDeclName( + getASTContext().DeclarationNames.getCXXDestructorName( + getASTContext().getCanonicalType(record_qual_type))); + cxx_dtor_decl->setType(method_qual_type); + cxx_dtor_decl->setImplicit(is_artificial); + cxx_dtor_decl->setInlineSpecified(is_inline); + cxx_dtor_decl->setConstexprKind(CSK_unspecified); + cxx_method_decl = cxx_dtor_decl; + } else if (decl_name == cxx_record_decl->getDeclName()) { + cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized( + getASTContext(), 0, 0); + cxx_ctor_decl->setDeclContext(cxx_record_decl); + cxx_ctor_decl->setDeclName( + getASTContext().DeclarationNames.getCXXConstructorName( + getASTContext().getCanonicalType(record_qual_type))); + cxx_ctor_decl->setType(method_qual_type); + cxx_ctor_decl->setImplicit(is_artificial); + cxx_ctor_decl->setInlineSpecified(is_inline); + cxx_ctor_decl->setConstexprKind(CSK_unspecified); + cxx_ctor_decl->setNumCtorInitializers(0); + cxx_ctor_decl->setExplicitSpecifier(explicit_spec); + cxx_method_decl = cxx_ctor_decl; + } else { + clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None; + clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; + + if (IsOperator(name, op_kind)) { + if (op_kind != clang::NUM_OVERLOADED_OPERATORS) { + // Check the number of operator parameters. Sometimes we have seen bad + // DWARF that doesn't correctly describe operators and if we try to + // create a method and add it to the class, clang will assert and + // crash, so we need to make sure things are acceptable. + const bool is_method = true; + if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount( + is_method, op_kind, num_params)) + return nullptr; + cxx_method_decl = + clang::CXXMethodDecl::CreateDeserialized(getASTContext(), 0); + cxx_method_decl->setDeclContext(cxx_record_decl); + cxx_method_decl->setDeclName( + getASTContext().DeclarationNames.getCXXOperatorName(op_kind)); + cxx_method_decl->setType(method_qual_type); + cxx_method_decl->setStorageClass(SC); + cxx_method_decl->setInlineSpecified(is_inline); + cxx_method_decl->setConstexprKind(CSK_unspecified); + } else if (num_params == 0) { + // Conversion operators don't take params... + auto *cxx_conversion_decl = + clang::CXXConversionDecl::CreateDeserialized(getASTContext(), 0); + cxx_conversion_decl->setDeclContext(cxx_record_decl); + cxx_conversion_decl->setDeclName( + getASTContext().DeclarationNames.getCXXConversionFunctionName( + getASTContext().getCanonicalType( + function_type->getReturnType()))); + cxx_conversion_decl->setType(method_qual_type); + cxx_conversion_decl->setInlineSpecified(is_inline); + cxx_conversion_decl->setExplicitSpecifier(explicit_spec); + cxx_conversion_decl->setConstexprKind(CSK_unspecified); + cxx_method_decl = cxx_conversion_decl; + } + } + + if (cxx_method_decl == nullptr) { + cxx_method_decl = + clang::CXXMethodDecl::CreateDeserialized(getASTContext(), 0); + cxx_method_decl->setDeclContext(cxx_record_decl); + cxx_method_decl->setDeclName(decl_name); + cxx_method_decl->setType(method_qual_type); + cxx_method_decl->setInlineSpecified(is_inline); + cxx_method_decl->setStorageClass(SC); + cxx_method_decl->setConstexprKind(CSK_unspecified); + } + } + SetMemberOwningModule(cxx_method_decl, cxx_record_decl); + + clang::AccessSpecifier access_specifier = + TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access); + + cxx_method_decl->setAccess(access_specifier); + cxx_method_decl->setVirtualAsWritten(is_virtual); + + if (is_attr_used) + cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext())); + + if (mangled_name != nullptr) { + cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( + getASTContext(), mangled_name, /*literal=*/false)); + } + + // Populate the method decl with parameter decls + + llvm::SmallVector<clang::ParmVarDecl *, 12> params; + + for (unsigned param_index = 0; param_index < num_params; ++param_index) { + params.push_back(clang::ParmVarDecl::Create( + getASTContext(), cxx_method_decl, clang::SourceLocation(), + clang::SourceLocation(), + nullptr, // anonymous + method_function_prototype->getParamType(param_index), nullptr, + clang::SC_None, nullptr)); + } + + cxx_method_decl->setParams(llvm::ArrayRef<clang::ParmVarDecl *>(params)); + + cxx_record_decl->addDecl(cxx_method_decl); + + // Sometimes the debug info will mention a constructor (default/copy/move), + // destructor, or assignment operator (copy/move) but there won't be any + // version of this in the code. So we check if the function was artificially + // generated and if it is trivial and this lets the compiler/backend know + // that it can inline the IR for these when it needs to and we can avoid a + // "missing function" error when running expressions. + + if (is_artificial) { + if (cxx_ctor_decl && ((cxx_ctor_decl->isDefaultConstructor() && + cxx_record_decl->hasTrivialDefaultConstructor()) || + (cxx_ctor_decl->isCopyConstructor() && + cxx_record_decl->hasTrivialCopyConstructor()) || + (cxx_ctor_decl->isMoveConstructor() && + cxx_record_decl->hasTrivialMoveConstructor()))) { + cxx_ctor_decl->setDefaulted(); + cxx_ctor_decl->setTrivial(true); + } else if (cxx_dtor_decl) { + if (cxx_record_decl->hasTrivialDestructor()) { + cxx_dtor_decl->setDefaulted(); + cxx_dtor_decl->setTrivial(true); + } + } else if ((cxx_method_decl->isCopyAssignmentOperator() && + cxx_record_decl->hasTrivialCopyAssignment()) || + (cxx_method_decl->isMoveAssignmentOperator() && + cxx_record_decl->hasTrivialMoveAssignment())) { + cxx_method_decl->setDefaulted(); + cxx_method_decl->setTrivial(true); + } + } + + VerifyDecl(cxx_method_decl); + + return cxx_method_decl; +} + +void TypeSystemClang::AddMethodOverridesForCXXRecordType( + lldb::opaque_compiler_type_t type) { + if (auto *record = GetAsCXXRecordDecl(type)) + for (auto *method : record->methods()) + addOverridesForMethod(method); +} + +#pragma mark C++ Base Classes + +std::unique_ptr<clang::CXXBaseSpecifier> +TypeSystemClang::CreateBaseClassSpecifier(lldb::opaque_compiler_type_t type, + AccessType access, bool is_virtual, + bool base_of_class) { + if (!type) + return nullptr; + + return std::make_unique<clang::CXXBaseSpecifier>( + clang::SourceRange(), is_virtual, base_of_class, + TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access), + getASTContext().getTrivialTypeSourceInfo(GetQualType(type)), + clang::SourceLocation()); +} + +bool TypeSystemClang::TransferBaseClasses( + lldb::opaque_compiler_type_t type, + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases) { + if (!type) + return false; + clang::CXXRecordDecl *cxx_record_decl = GetAsCXXRecordDecl(type); + if (!cxx_record_decl) + return false; + std::vector<clang::CXXBaseSpecifier *> raw_bases; + raw_bases.reserve(bases.size()); + + // Clang will make a copy of them, so it's ok that we pass pointers that we're + // about to destroy. + for (auto &b : bases) + raw_bases.push_back(b.get()); + cxx_record_decl->setBases(raw_bases.data(), raw_bases.size()); + return true; +} + +bool TypeSystemClang::SetObjCSuperClass( + const CompilerType &type, const CompilerType &superclass_clang_type) { + TypeSystemClang *ast = + llvm::dyn_cast_or_null<TypeSystemClang>(type.GetTypeSystem()); + if (!ast) + return false; + clang::ASTContext &clang_ast = ast->getASTContext(); + + if (type && superclass_clang_type.IsValid() && + superclass_clang_type.GetTypeSystem() == type.GetTypeSystem()) { + clang::ObjCInterfaceDecl *class_interface_decl = + GetAsObjCInterfaceDecl(type); + clang::ObjCInterfaceDecl *super_interface_decl = + GetAsObjCInterfaceDecl(superclass_clang_type); + if (class_interface_decl && super_interface_decl) { + class_interface_decl->setSuperClass(clang_ast.getTrivialTypeSourceInfo( + clang_ast.getObjCInterfaceType(super_interface_decl))); + return true; + } + } + return false; +} + +bool TypeSystemClang::AddObjCClassProperty( + const CompilerType &type, const char *property_name, + const CompilerType &property_clang_type, clang::ObjCIvarDecl *ivar_decl, + const char *property_setter_name, const char *property_getter_name, + uint32_t property_attributes, ClangASTMetadata *metadata) { + if (!type || !property_clang_type.IsValid() || property_name == nullptr || + property_name[0] == '\0') + return false; + TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!ast) + return false; + clang::ASTContext &clang_ast = ast->getASTContext(); + + clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type); + if (!class_interface_decl) + return false; + + CompilerType property_clang_type_to_access; + + if (property_clang_type.IsValid()) + property_clang_type_to_access = property_clang_type; + else if (ivar_decl) + property_clang_type_to_access = ast->GetType(ivar_decl->getType()); + + if (!class_interface_decl || !property_clang_type_to_access.IsValid()) + return false; + + clang::TypeSourceInfo *prop_type_source; + if (ivar_decl) + prop_type_source = clang_ast.getTrivialTypeSourceInfo(ivar_decl->getType()); + else + prop_type_source = clang_ast.getTrivialTypeSourceInfo( + ClangUtil::GetQualType(property_clang_type)); + + clang::ObjCPropertyDecl *property_decl = + clang::ObjCPropertyDecl::CreateDeserialized(clang_ast, 0); + property_decl->setDeclContext(class_interface_decl); + property_decl->setDeclName(&clang_ast.Idents.get(property_name)); + property_decl->setType(ivar_decl + ? ivar_decl->getType() + : ClangUtil::GetQualType(property_clang_type), + prop_type_source); + SetMemberOwningModule(property_decl, class_interface_decl); + + if (!property_decl) + return false; + + if (metadata) + ast->SetMetadata(property_decl, *metadata); + + class_interface_decl->addDecl(property_decl); + + clang::Selector setter_sel, getter_sel; + + if (property_setter_name) { + std::string property_setter_no_colon(property_setter_name, + strlen(property_setter_name) - 1); + clang::IdentifierInfo *setter_ident = + &clang_ast.Idents.get(property_setter_no_colon); + setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident); + } else if (!(property_attributes & DW_APPLE_PROPERTY_readonly)) { + std::string setter_sel_string("set"); + setter_sel_string.push_back(::toupper(property_name[0])); + setter_sel_string.append(&property_name[1]); + clang::IdentifierInfo *setter_ident = + &clang_ast.Idents.get(setter_sel_string); + setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident); + } + property_decl->setSetterName(setter_sel); + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_setter); + + if (property_getter_name != nullptr) { + clang::IdentifierInfo *getter_ident = + &clang_ast.Idents.get(property_getter_name); + getter_sel = clang_ast.Selectors.getSelector(0, &getter_ident); + } else { + clang::IdentifierInfo *getter_ident = &clang_ast.Idents.get(property_name); + getter_sel = clang_ast.Selectors.getSelector(0, &getter_ident); + } + property_decl->setGetterName(getter_sel); + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_getter); + + if (ivar_decl) + property_decl->setPropertyIvarDecl(ivar_decl); + + if (property_attributes & DW_APPLE_PROPERTY_readonly) + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly); + if (property_attributes & DW_APPLE_PROPERTY_readwrite) + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite); + if (property_attributes & DW_APPLE_PROPERTY_assign) + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign); + if (property_attributes & DW_APPLE_PROPERTY_retain) + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_retain); + if (property_attributes & DW_APPLE_PROPERTY_copy) + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_copy); + if (property_attributes & DW_APPLE_PROPERTY_nonatomic) + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic); + if (property_attributes & ObjCPropertyAttribute::kind_nullability) + property_decl->setPropertyAttributes( + ObjCPropertyAttribute::kind_nullability); + if (property_attributes & ObjCPropertyAttribute::kind_null_resettable) + property_decl->setPropertyAttributes( + ObjCPropertyAttribute::kind_null_resettable); + if (property_attributes & ObjCPropertyAttribute::kind_class) + property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_class); + + const bool isInstance = + (property_attributes & ObjCPropertyAttribute::kind_class) == 0; + + clang::ObjCMethodDecl *getter = nullptr; + if (!getter_sel.isNull()) + getter = isInstance ? class_interface_decl->lookupInstanceMethod(getter_sel) + : class_interface_decl->lookupClassMethod(getter_sel); + if (!getter_sel.isNull() && !getter) { + const bool isVariadic = false; + const bool isPropertyAccessor = true; + const bool isSynthesizedAccessorStub = false; + const bool isImplicitlyDeclared = true; + const bool isDefined = false; + const clang::ObjCMethodDecl::ImplementationControl impControl = + clang::ObjCMethodDecl::None; + const bool HasRelatedResultType = false; + + getter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); + getter->setDeclName(getter_sel); + getter->setReturnType(ClangUtil::GetQualType(property_clang_type_to_access)); + getter->setDeclContext(class_interface_decl); + getter->setInstanceMethod(isInstance); + getter->setVariadic(isVariadic); + getter->setPropertyAccessor(isPropertyAccessor); + getter->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + getter->setImplicit(isImplicitlyDeclared); + getter->setDefined(isDefined); + getter->setDeclImplementation(impControl); + getter->setRelatedResultType(HasRelatedResultType); + SetMemberOwningModule(getter, class_interface_decl); + + if (getter) { + if (metadata) + ast->SetMetadata(getter, *metadata); + + getter->setMethodParams(clang_ast, llvm::ArrayRef<clang::ParmVarDecl *>(), + llvm::ArrayRef<clang::SourceLocation>()); + class_interface_decl->addDecl(getter); + } + } + if (getter) { + getter->setPropertyAccessor(true); + property_decl->setGetterMethodDecl(getter); + } + + clang::ObjCMethodDecl *setter = nullptr; + setter = isInstance ? class_interface_decl->lookupInstanceMethod(setter_sel) + : class_interface_decl->lookupClassMethod(setter_sel); + if (!setter_sel.isNull() && !setter) { + clang::QualType result_type = clang_ast.VoidTy; + const bool isVariadic = false; + const bool isPropertyAccessor = true; + const bool isSynthesizedAccessorStub = false; + const bool isImplicitlyDeclared = true; + const bool isDefined = false; + const clang::ObjCMethodDecl::ImplementationControl impControl = + clang::ObjCMethodDecl::None; + const bool HasRelatedResultType = false; + + setter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); + setter->setDeclName(setter_sel); + setter->setReturnType(result_type); + setter->setDeclContext(class_interface_decl); + setter->setInstanceMethod(isInstance); + setter->setVariadic(isVariadic); + setter->setPropertyAccessor(isPropertyAccessor); + setter->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + setter->setImplicit(isImplicitlyDeclared); + setter->setDefined(isDefined); + setter->setDeclImplementation(impControl); + setter->setRelatedResultType(HasRelatedResultType); + SetMemberOwningModule(setter, class_interface_decl); + + if (setter) { + if (metadata) + ast->SetMetadata(setter, *metadata); + + llvm::SmallVector<clang::ParmVarDecl *, 1> params; + params.push_back(clang::ParmVarDecl::Create( + clang_ast, setter, clang::SourceLocation(), clang::SourceLocation(), + nullptr, // anonymous + ClangUtil::GetQualType(property_clang_type_to_access), nullptr, + clang::SC_Auto, nullptr)); + + setter->setMethodParams(clang_ast, + llvm::ArrayRef<clang::ParmVarDecl *>(params), + llvm::ArrayRef<clang::SourceLocation>()); + + class_interface_decl->addDecl(setter); + } + } + if (setter) { + setter->setPropertyAccessor(true); + property_decl->setSetterMethodDecl(setter); + } + + return true; +} + +bool TypeSystemClang::IsObjCClassTypeAndHasIVars(const CompilerType &type, + bool check_superclass) { + clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type); + if (class_interface_decl) + return ObjCDeclHasIVars(class_interface_decl, check_superclass); + return false; +} + +clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( + const CompilerType &type, + 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) { + if (!type || !method_clang_type.IsValid()) + return nullptr; + + clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type); + + if (class_interface_decl == nullptr) + return nullptr; + TypeSystemClang *lldb_ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (lldb_ast == nullptr) + return nullptr; + clang::ASTContext &ast = lldb_ast->getASTContext(); + + const char *selector_start = ::strchr(name, ' '); + if (selector_start == nullptr) + return nullptr; + + selector_start++; + llvm::SmallVector<clang::IdentifierInfo *, 12> selector_idents; + + size_t len = 0; + const char *start; + + unsigned num_selectors_with_args = 0; + for (start = selector_start; start && *start != '\0' && *start != ']'; + start += len) { + len = ::strcspn(start, ":]"); + bool has_arg = (start[len] == ':'); + if (has_arg) + ++num_selectors_with_args; + selector_idents.push_back(&ast.Idents.get(llvm::StringRef(start, len))); + if (has_arg) + len += 1; + } + + if (selector_idents.size() == 0) + return nullptr; + + clang::Selector method_selector = ast.Selectors.getSelector( + num_selectors_with_args ? selector_idents.size() : 0, + selector_idents.data()); + + clang::QualType method_qual_type(ClangUtil::GetQualType(method_clang_type)); + + // Populate the method decl with parameter decls + const clang::Type *method_type(method_qual_type.getTypePtr()); + + if (method_type == nullptr) + return nullptr; + + const clang::FunctionProtoType *method_function_prototype( + llvm::dyn_cast<clang::FunctionProtoType>(method_type)); + + if (!method_function_prototype) + return nullptr; + + const bool isInstance = (name[0] == '-'); + const bool isVariadic = is_variadic; + const bool isPropertyAccessor = false; + const bool isSynthesizedAccessorStub = false; + /// 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 bool HasRelatedResultType = false; + + const unsigned num_args = method_function_prototype->getNumParams(); + + if (num_args != num_selectors_with_args) + return nullptr; // some debug information is corrupt. We are not going to + // deal with it. + + auto *objc_method_decl = clang::ObjCMethodDecl::CreateDeserialized(ast, 0); + objc_method_decl->setDeclName(method_selector); + objc_method_decl->setReturnType(method_function_prototype->getReturnType()); + objc_method_decl->setDeclContext( + lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type))); + objc_method_decl->setInstanceMethod(isInstance); + objc_method_decl->setVariadic(isVariadic); + objc_method_decl->setPropertyAccessor(isPropertyAccessor); + objc_method_decl->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + objc_method_decl->setImplicit(isImplicitlyDeclared); + objc_method_decl->setDefined(isDefined); + objc_method_decl->setDeclImplementation(impControl); + objc_method_decl->setRelatedResultType(HasRelatedResultType); + SetMemberOwningModule(objc_method_decl, class_interface_decl); + + if (objc_method_decl == nullptr) + return nullptr; + + if (num_args > 0) { + llvm::SmallVector<clang::ParmVarDecl *, 12> params; + + for (unsigned param_index = 0; param_index < num_args; ++param_index) { + params.push_back(clang::ParmVarDecl::Create( + ast, objc_method_decl, clang::SourceLocation(), + clang::SourceLocation(), + nullptr, // anonymous + method_function_prototype->getParamType(param_index), nullptr, + clang::SC_Auto, nullptr)); + } + + objc_method_decl->setMethodParams( + ast, llvm::ArrayRef<clang::ParmVarDecl *>(params), + llvm::ArrayRef<clang::SourceLocation>()); + } + + if (is_objc_direct_call) { + // Add a the objc_direct attribute to the declaration we generate that + // we generate a direct method call for this ObjCMethodDecl. + objc_method_decl->addAttr( + clang::ObjCDirectAttr::CreateImplicit(ast, SourceLocation())); + // Usually Sema is creating implicit parameters (e.g., self) when it + // parses the method. We don't have a parsing Sema when we build our own + // AST here so we manually need to create these implicit parameters to + // make the direct call code generation happy. + objc_method_decl->createImplicitParams(ast, class_interface_decl); + } + + class_interface_decl->addDecl(objc_method_decl); + + VerifyDecl(objc_method_decl); + + return objc_method_decl; +} + +bool TypeSystemClang::SetHasExternalStorage(lldb::opaque_compiler_type_t type, + bool has_extern) { + if (!type) + return false; + + clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: { + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + cxx_record_decl->setHasExternalLexicalStorage(has_extern); + cxx_record_decl->setHasExternalVisibleStorage(has_extern); + return true; + } + } break; + + case clang::Type::Enum: { + clang::EnumDecl *enum_decl = + llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) { + enum_decl->setHasExternalLexicalStorage(has_extern); + enum_decl->setHasExternalVisibleStorage(has_extern); + return true; + } + } break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert(objc_class_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + + if (class_interface_decl) { + class_interface_decl->setHasExternalLexicalStorage(has_extern); + class_interface_decl->setHasExternalVisibleStorage(has_extern); + return true; + } + } + } break; + + default: + break; + } + return false; +} + +#pragma mark TagDecl + +bool TypeSystemClang::StartTagDeclarationDefinition(const CompilerType &type) { + clang::QualType qual_type(ClangUtil::GetQualType(type)); + if (!qual_type.isNull()) { + const clang::TagType *tag_type = qual_type->getAs<clang::TagType>(); + if (tag_type) { + clang::TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) { + tag_decl->startDefinition(); + return true; + } + } + + const clang::ObjCObjectType *object_type = + qual_type->getAs<clang::ObjCObjectType>(); + if (object_type) { + clang::ObjCInterfaceDecl *interface_decl = object_type->getInterface(); + if (interface_decl) { + interface_decl->startDefinition(); + return true; + } + } + } + return false; +} + +bool TypeSystemClang::CompleteTagDeclarationDefinition( + const CompilerType &type) { + clang::QualType qual_type(ClangUtil::GetQualType(type)); + if (qual_type.isNull()) + return false; + + // Make sure we use the same methodology as + // TypeSystemClang::StartTagDeclarationDefinition() as to how we start/end + // the definition. + const clang::TagType *tag_type = qual_type->getAs<clang::TagType>(); + if (tag_type) { + clang::TagDecl *tag_decl = tag_type->getDecl(); + + if (auto *cxx_record_decl = llvm::dyn_cast<CXXRecordDecl>(tag_decl)) { + // If we have a move constructor declared but no copy constructor we + // need to explicitly mark it as deleted. Usually Sema would do this for + // us in Sema::DeclareImplicitCopyConstructor but we don't have a Sema + // when building an AST from debug information. + // See also: + // C++11 [class.copy]p7, p18: + // If the class definition declares a move constructor or move assignment + // operator, an implicitly declared copy constructor or copy assignment + // operator is defined as deleted. + if (cxx_record_decl->hasUserDeclaredMoveConstructor() || + cxx_record_decl->hasUserDeclaredMoveAssignment()) { + if (cxx_record_decl->needsImplicitCopyConstructor()) + cxx_record_decl->setImplicitCopyConstructorIsDeleted(); + if (cxx_record_decl->needsImplicitCopyAssignment()) + cxx_record_decl->setImplicitCopyAssignmentIsDeleted(); + } + + if (!cxx_record_decl->isCompleteDefinition()) + cxx_record_decl->completeDefinition(); + cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true); + cxx_record_decl->setHasExternalLexicalStorage(false); + cxx_record_decl->setHasExternalVisibleStorage(false); + return true; + } + } + + const clang::EnumType *enutype = qual_type->getAs<clang::EnumType>(); + + if (!enutype) + return false; + clang::EnumDecl *enum_decl = enutype->getDecl(); + + if (enum_decl->isCompleteDefinition()) + return true; + + TypeSystemClang *lldb_ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (lldb_ast == nullptr) + return false; + clang::ASTContext &ast = lldb_ast->getASTContext(); + + /// TODO This really needs to be fixed. + + QualType integer_type(enum_decl->getIntegerType()); + if (!integer_type.isNull()) { + unsigned NumPositiveBits = 1; + unsigned NumNegativeBits = 0; + + clang::QualType promotion_qual_type; + // If the enum integer type is less than an integer in bit width, + // then we must promote it to an integer size. + if (ast.getTypeSize(enum_decl->getIntegerType()) < + ast.getTypeSize(ast.IntTy)) { + if (enum_decl->getIntegerType()->isSignedIntegerType()) + promotion_qual_type = ast.IntTy; + else + promotion_qual_type = ast.UnsignedIntTy; + } else + promotion_qual_type = enum_decl->getIntegerType(); + + enum_decl->completeDefinition(enum_decl->getIntegerType(), + promotion_qual_type, NumPositiveBits, + NumNegativeBits); + } + return true; +} + +clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType( + const CompilerType &enum_type, const Declaration &decl, const char *name, + const llvm::APSInt &value) { + + if (!enum_type || ConstString(name).IsEmpty()) + return nullptr; + + lldbassert(enum_type.GetTypeSystem() == static_cast<TypeSystem *>(this)); + + lldb::opaque_compiler_type_t enum_opaque_compiler_type = + enum_type.GetOpaqueQualType(); + + if (!enum_opaque_compiler_type) + return nullptr; + + clang::QualType enum_qual_type( + GetCanonicalQualType(enum_opaque_compiler_type)); + + const clang::Type *clang_type = enum_qual_type.getTypePtr(); + + if (!clang_type) + return nullptr; + + const clang::EnumType *enutype = llvm::dyn_cast<clang::EnumType>(clang_type); + + if (!enutype) + return nullptr; + + clang::EnumConstantDecl *enumerator_decl = + clang::EnumConstantDecl::CreateDeserialized(getASTContext(), 0); + enumerator_decl->setDeclContext(enutype->getDecl()); + if (name && name[0]) + enumerator_decl->setDeclName(&getASTContext().Idents.get(name)); + enumerator_decl->setType(clang::QualType(enutype, 0)); + enumerator_decl->setInitVal(value); + SetMemberOwningModule(enumerator_decl, enutype->getDecl()); + + if (!enumerator_decl) + return nullptr; + + enutype->getDecl()->addDecl(enumerator_decl); + + VerifyDecl(enumerator_decl); + return enumerator_decl; +} + +clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType( + const CompilerType &enum_type, const Declaration &decl, const char *name, + int64_t enum_value, uint32_t enum_value_bit_size) { + CompilerType underlying_type = GetEnumerationIntegerType(enum_type); + bool is_signed = false; + underlying_type.IsIntegerType(is_signed); + + llvm::APSInt value(enum_value_bit_size, is_signed); + value = enum_value; + + return AddEnumerationValueToEnumerationType(enum_type, decl, name, value); +} + +CompilerType TypeSystemClang::GetEnumerationIntegerType(CompilerType type) { + clang::QualType qt(ClangUtil::GetQualType(type)); + const clang::Type *clang_type = qt.getTypePtrOrNull(); + const auto *enum_type = llvm::dyn_cast_or_null<clang::EnumType>(clang_type); + if (!enum_type) + return CompilerType(); + + return GetType(enum_type->getDecl()->getIntegerType()); +} + +CompilerType +TypeSystemClang::CreateMemberPointerType(const CompilerType &type, + const CompilerType &pointee_type) { + if (type && pointee_type.IsValid() && + type.GetTypeSystem() == pointee_type.GetTypeSystem()) { + TypeSystemClang *ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!ast) + return CompilerType(); + return ast->GetType(ast->getASTContext().getMemberPointerType( + ClangUtil::GetQualType(pointee_type), + ClangUtil::GetQualType(type).getTypePtr())); + } + return CompilerType(); +} + +// Dumping types +#define DEPTH_INCREMENT 2 + +#ifndef NDEBUG +LLVM_DUMP_METHOD void +TypeSystemClang::dump(lldb::opaque_compiler_type_t type) const { + if (!type) + return; + clang::QualType qual_type(GetQualType(type)); + qual_type.dump(); +} +#endif + +void TypeSystemClang::Dump(Stream &s) { + Decl *tu = Decl::castFromDeclContext(GetTranslationUnitDecl()); + tu->dump(s.AsRawOstream()); +} + +void TypeSystemClang::DumpFromSymbolFile(Stream &s, + llvm::StringRef symbol_name) { + SymbolFile *symfile = GetSymbolFile(); + + if (!symfile) + return; + + lldb_private::TypeList type_list; + symfile->GetTypes(nullptr, eTypeClassAny, type_list); + size_t ntypes = type_list.GetSize(); + + for (size_t i = 0; i < ntypes; ++i) { + TypeSP type = type_list.GetTypeAtIndex(i); + + if (!symbol_name.empty()) + if (symbol_name != type->GetName().GetStringRef()) + continue; + + s << type->GetName().AsCString() << "\n"; + + CompilerType full_type = type->GetFullCompilerType(); + if (clang::TagDecl *tag_decl = GetAsTagDecl(full_type)) { + tag_decl->dump(s.AsRawOstream()); + continue; + } + if (clang::TypedefNameDecl *typedef_decl = GetAsTypedefDecl(full_type)) { + typedef_decl->dump(s.AsRawOstream()); + continue; + } + if (auto *objc_obj = llvm::dyn_cast<clang::ObjCObjectType>( + ClangUtil::GetQualType(full_type).getTypePtr())) { + if (clang::ObjCInterfaceDecl *interface_decl = objc_obj->getInterface()) { + interface_decl->dump(s.AsRawOstream()); + continue; + } + } + GetCanonicalQualType(full_type.GetOpaqueQualType()) + .dump(s.AsRawOstream(), getASTContext()); + } +} + +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, + uint32_t bitfield_bit_size) { + const clang::EnumType *enutype = + llvm::cast<clang::EnumType>(qual_type.getTypePtr()); + const clang::EnumDecl *enum_decl = enutype->getDecl(); + assert(enum_decl); + lldb::offset_t offset = byte_offset; + const uint64_t enum_svalue = data.GetMaxS64Bitfield( + &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); + bool can_be_bitfield = true; + uint64_t covered_bits = 0; + int num_enumerators = 0; + + // Try to find an exact match for the value. + // At the same time, we're applying a heuristic to determine whether we want + // to print this enum as a bitfield. We're likely dealing with a bitfield if + // every enumerator is either a one bit value or a superset of the previous + // enumerators. Also 0 doesn't make sense when the enumerators are used as + // flags. + for (auto *enumerator : enum_decl->enumerators()) { + uint64_t val = enumerator->getInitVal().getSExtValue(); + val = llvm::SignExtend64(val, 8*byte_size); + if (llvm::countPopulation(val) != 1 && (val & ~covered_bits) != 0) + can_be_bitfield = false; + covered_bits |= val; + ++num_enumerators; + if (val == enum_svalue) { + // Found an exact match, that's all we need to do. + s->PutCString(enumerator->getNameAsString()); + return true; + } + } + + // Unsigned values make more sense for flags. + offset = byte_offset; + const uint64_t enum_uvalue = data.GetMaxU64Bitfield( + &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); + + // No exact match, but we don't think this is a bitfield. Print the value as + // decimal. + if (!can_be_bitfield) { + if (qual_type->isSignedIntegerOrEnumerationType()) + s->Printf("%" PRIi64, enum_svalue); + else + s->Printf("%" PRIu64, enum_uvalue); + return true; + } + + uint64_t remaining_value = enum_uvalue; + std::vector<std::pair<uint64_t, llvm::StringRef>> values; + values.reserve(num_enumerators); + for (auto *enumerator : enum_decl->enumerators()) + if (auto val = enumerator->getInitVal().getZExtValue()) + values.emplace_back(val, enumerator->getName()); + + // Sort in reverse order of the number of the population count, so that in + // `enum {A, B, ALL = A|B }` we visit ALL first. Use a stable sort so that + // A | C where A is declared before C is displayed in this order. + std::stable_sort(values.begin(), values.end(), [](const auto &a, const auto &b) { + return llvm::countPopulation(a.first) > llvm::countPopulation(b.first); + }); + + for (const auto &val : values) { + if ((remaining_value & val.first) != val.first) + continue; + remaining_value &= ~val.first; + s->PutCString(val.second); + if (remaining_value) + s->PutCString(" | "); + } + + // If there is a remainder that is not covered by the value, print it as hex. + if (remaining_value) + s->Printf("0x%" PRIx64, remaining_value); + + return true; +} + +bool TypeSystemClang::DumpTypeValue( + lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format, + const lldb_private::DataExtractor &data, lldb::offset_t byte_offset, + size_t byte_size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, + ExecutionContextScope *exe_scope) { + if (!type) + return false; + if (IsAggregateType(type)) { + return false; + } else { + clang::QualType qual_type(GetQualType(type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + + if (type_class == clang::Type::Elaborated) { + qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType(); + return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data, byte_offset, byte_size, + bitfield_bit_size, bitfield_bit_offset, exe_scope); + } + + switch (type_class) { + 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); + if (format == eFormatDefault) + 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.DumpTypeValue( + s, + format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + byte_offset, // Offset into "data" where to grab value from + typedef_byte_size, // Size of this type in bytes + bitfield_bit_size, // Size in bits of a bitfield value, if zero don't + // treat as a bitfield + bitfield_bit_offset, // Offset in bits of a bitfield value if + // bitfield_bit_size != 0 + exe_scope); + } break; + + case clang::Type::Enum: + // If our format is enum or default, show the enumeration value as its + // enumeration string value, else just display it as requested. + if ((format == eFormatEnum || format == eFormatDefault) && + GetCompleteType(type)) + return DumpEnumValue(qual_type, s, data, byte_offset, byte_size, + bitfield_bit_offset, bitfield_bit_size); + // format was not enum, just fall through and dump the value as + // requested.... + LLVM_FALLTHROUGH; + + default: + // We are down to a scalar type that we just need to display. + { + uint32_t item_count = 1; + // A few formats, we might need to modify our size and count for + // depending + // on how we are trying to display the value... + switch (format) { + default: + case eFormatBoolean: + case eFormatBinary: + case eFormatComplex: + case eFormatCString: // NULL terminated C strings + case eFormatDecimal: + case eFormatEnum: + case eFormatHex: + case eFormatHexUppercase: + case eFormatFloat: + case eFormatOctal: + case eFormatOSType: + case eFormatUnsigned: + case eFormatPointer: + case eFormatVectorOfChar: + case eFormatVectorOfSInt8: + case eFormatVectorOfUInt8: + case eFormatVectorOfSInt16: + case eFormatVectorOfUInt16: + case eFormatVectorOfSInt32: + case eFormatVectorOfUInt32: + case eFormatVectorOfSInt64: + case eFormatVectorOfUInt64: + case eFormatVectorOfFloat32: + case eFormatVectorOfFloat64: + case eFormatVectorOfUInt128: + break; + + case eFormatChar: + case eFormatCharPrintable: + case eFormatCharArray: + case eFormatBytes: + case eFormatBytesWithASCII: + item_count = byte_size; + byte_size = 1; + break; + + case eFormatUnicode16: + item_count = byte_size / 2; + byte_size = 2; + break; + + case eFormatUnicode32: + item_count = byte_size / 4; + byte_size = 4; + break; + } + return DumpDataExtractor(data, s, byte_offset, format, byte_size, + item_count, UINT32_MAX, LLDB_INVALID_ADDRESS, + bitfield_bit_size, bitfield_bit_offset, + exe_scope); + } + break; + } + } + 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); + DumpTypeDescription(type, &s, level); + + CompilerType ct(this, type); + const clang::Type *clang_type = ClangUtil::GetQualType(ct).getTypePtr(); + ClangASTMetadata *metadata = GetMetadata(clang_type); + if (metadata) { + metadata->Dump(&s); + } +} + +void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type, + Stream *s, + lldb::DescriptionLevel level) { + if (type) { + clang::QualType qual_type = + RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef}); + + llvm::SmallVector<char, 1024> buf; + llvm::raw_svector_ostream llvm_ostrm(buf); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: { + GetCompleteType(type); + + auto *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr()); + assert(objc_class_type); + if (!objc_class_type) + break; + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + if (!class_interface_decl) + break; + if (level == eDescriptionLevelVerbose) + class_interface_decl->dump(llvm_ostrm); + else + class_interface_decl->print(llvm_ostrm, + getASTContext().getPrintingPolicy(), + s->GetIndentLevel()); + } break; + + case clang::Type::Typedef: { + auto *typedef_type = qual_type->getAs<clang::TypedefType>(); + if (!typedef_type) + break; + const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); + if (level == eDescriptionLevelVerbose) + typedef_decl->dump(llvm_ostrm); + else { + std::string clang_typedef_name( + typedef_decl->getQualifiedNameAsString()); + if (!clang_typedef_name.empty()) { + s->PutCString("typedef "); + s->PutCString(clang_typedef_name); + } + } + } break; + + case clang::Type::Record: { + GetCompleteType(type); + + auto *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + if (level == eDescriptionLevelVerbose) + record_decl->dump(llvm_ostrm); + else { + if (auto *cxx_record_decl = + llvm::dyn_cast<clang::CXXRecordDecl>(record_decl)) + cxx_record_decl->print(llvm_ostrm, + getASTContext().getPrintingPolicy(), + s->GetIndentLevel()); + else + record_decl->print(llvm_ostrm, getASTContext().getPrintingPolicy(), + s->GetIndentLevel()); + } + } break; + + default: { + if (auto *tag_type = + llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr())) { + if (clang::TagDecl *tag_decl = tag_type->getDecl()) { + if (level == eDescriptionLevelVerbose) + tag_decl->dump(llvm_ostrm); + else + tag_decl->print(llvm_ostrm, 0); + } + } else { + if (level == eDescriptionLevelVerbose) + qual_type->dump(llvm_ostrm, getASTContext()); + else { + std::string clang_type_name(qual_type.getAsString()); + if (!clang_type_name.empty()) + s->PutCString(clang_type_name); + } + } + } + } + + if (buf.size() > 0) { + s->Write(buf.data(), buf.size()); + } +} +} + +void TypeSystemClang::DumpTypeName(const CompilerType &type) { + if (ClangUtil::IsClangType(type)) { + clang::QualType qual_type( + ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + printf("class %s", cxx_record_decl->getName().str().c_str()); + } break; + + case clang::Type::Enum: { + clang::EnumDecl *enum_decl = + llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) { + printf("enum %s", enum_decl->getName().str().c_str()); + } + } break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly + // added ASTContext because it only supports TagDecl objects right + // now... + if (class_interface_decl) + printf("@class %s", class_interface_decl->getName().str().c_str()); + } + } break; + + case clang::Type::Typedef: + printf("typedef %s", llvm::cast<clang::TypedefType>(qual_type) + ->getDecl() + ->getName() + .str() + .c_str()); + break; + + case clang::Type::Auto: + printf("auto "); + return DumpTypeName(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::AutoType>(qual_type) + ->getDeducedType() + .getAsOpaquePtr())); + + case clang::Type::Elaborated: + printf("elaborated "); + return DumpTypeName(CompilerType( + type.GetTypeSystem(), llvm::cast<clang::ElaboratedType>(qual_type) + ->getNamedType() + .getAsOpaquePtr())); + + case clang::Type::Paren: + printf("paren "); + return DumpTypeName(CompilerType( + type.GetTypeSystem(), + llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); + + default: + printf("TypeSystemClang::DumpTypeName() type_class = %u", type_class); + break; + } + } +} + +clang::ClassTemplateDecl *TypeSystemClang::ParseClassTemplateDecl( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + lldb::AccessType access_type, const char *parent_name, int tag_decl_kind, + const TypeSystemClang::TemplateParameterInfos &template_param_infos) { + if (template_param_infos.IsValid()) { + std::string template_basename(parent_name); + template_basename.erase(template_basename.find('<')); + + return CreateClassTemplateDecl(decl_ctx, owning_module, access_type, + template_basename.c_str(), tag_decl_kind, + template_param_infos); + } + return nullptr; +} + +void TypeSystemClang::CompleteTagDecl(clang::TagDecl *decl) { + SymbolFile *sym_file = GetSymbolFile(); + if (sym_file) { + CompilerType clang_type = GetTypeForDecl(decl); + if (clang_type) + sym_file->CompleteType(clang_type); + } +} + +void TypeSystemClang::CompleteObjCInterfaceDecl( + clang::ObjCInterfaceDecl *decl) { + SymbolFile *sym_file = GetSymbolFile(); + if (sym_file) { + CompilerType clang_type = GetTypeForDecl(decl); + if (clang_type) + sym_file->CompleteType(clang_type); + } +} + +DWARFASTParser *TypeSystemClang::GetDWARFParser() { + if (!m_dwarf_ast_parser_up) + m_dwarf_ast_parser_up = std::make_unique<DWARFASTParserClang>(*this); + return m_dwarf_ast_parser_up.get(); +} + +PDBASTParser *TypeSystemClang::GetPDBParser() { + if (!m_pdb_ast_parser_up) + m_pdb_ast_parser_up = std::make_unique<PDBASTParser>(*this); + return m_pdb_ast_parser_up.get(); +} + +bool TypeSystemClang::LayoutRecordType( + const clang::RecordDecl *record_decl, uint64_t &bit_size, + uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets) { + lldb_private::ClangASTImporter *importer = nullptr; + if (m_dwarf_ast_parser_up) + importer = &m_dwarf_ast_parser_up->GetClangASTImporter(); + if (!importer && m_pdb_ast_parser_up) + importer = &m_pdb_ast_parser_up->GetClangASTImporter(); + if (!importer) + return false; + + return importer->LayoutRecordType(record_decl, bit_size, alignment, + field_offsets, base_offsets, vbase_offsets); +} + +// CompilerDecl override functions + +ConstString TypeSystemClang::DeclGetName(void *opaque_decl) { + if (opaque_decl) { + clang::NamedDecl *nd = + llvm::dyn_cast<NamedDecl>((clang::Decl *)opaque_decl); + if (nd != nullptr) + return ConstString(nd->getDeclName().getAsString()); + } + return ConstString(); +} + +ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) { + if (opaque_decl) { + clang::NamedDecl *nd = + llvm::dyn_cast<clang::NamedDecl>((clang::Decl *)opaque_decl); + if (nd != nullptr && !llvm::isa<clang::ObjCMethodDecl>(nd)) { + clang::MangleContext *mc = getMangleContext(); + if (mc && mc->shouldMangleCXXName(nd)) { + llvm::SmallVector<char, 1024> buf; + llvm::raw_svector_ostream llvm_ostrm(buf); + if (llvm::isa<clang::CXXConstructorDecl>(nd)) { + mc->mangleName( + clang::GlobalDecl(llvm::dyn_cast<clang::CXXConstructorDecl>(nd), + Ctor_Complete), + llvm_ostrm); + } else if (llvm::isa<clang::CXXDestructorDecl>(nd)) { + mc->mangleName( + clang::GlobalDecl(llvm::dyn_cast<clang::CXXDestructorDecl>(nd), + Dtor_Complete), + llvm_ostrm); + } else { + mc->mangleName(nd, llvm_ostrm); + } + if (buf.size() > 0) + return ConstString(buf.data(), buf.size()); + } + } + } + return ConstString(); +} + +CompilerDeclContext TypeSystemClang::DeclGetDeclContext(void *opaque_decl) { + if (opaque_decl) + return CreateDeclContext(((clang::Decl *)opaque_decl)->getDeclContext()); + return CompilerDeclContext(); +} + +CompilerType TypeSystemClang::DeclGetFunctionReturnType(void *opaque_decl) { + if (clang::FunctionDecl *func_decl = + llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl)) + return GetType(func_decl->getReturnType()); + if (clang::ObjCMethodDecl *objc_method = + llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl *)opaque_decl)) + return GetType(objc_method->getReturnType()); + else + return CompilerType(); +} + +size_t TypeSystemClang::DeclGetFunctionNumArguments(void *opaque_decl) { + if (clang::FunctionDecl *func_decl = + llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl)) + return func_decl->param_size(); + if (clang::ObjCMethodDecl *objc_method = + llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl *)opaque_decl)) + return objc_method->param_size(); + else + return 0; +} + +CompilerType TypeSystemClang::DeclGetFunctionArgumentType(void *opaque_decl, + size_t idx) { + if (clang::FunctionDecl *func_decl = + llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl)) { + if (idx < func_decl->param_size()) { + ParmVarDecl *var_decl = func_decl->getParamDecl(idx); + if (var_decl) + return GetType(var_decl->getOriginalType()); + } + } else if (clang::ObjCMethodDecl *objc_method = + llvm::dyn_cast<clang::ObjCMethodDecl>( + (clang::Decl *)opaque_decl)) { + if (idx < objc_method->param_size()) + return GetType(objc_method->parameters()[idx]->getOriginalType()); + } + return CompilerType(); +} + +// CompilerDeclContext functions + +std::vector<CompilerDecl> TypeSystemClang::DeclContextFindDeclByName( + void *opaque_decl_ctx, ConstString name, const bool ignore_using_decls) { + std::vector<CompilerDecl> found_decls; + if (opaque_decl_ctx) { + DeclContext *root_decl_ctx = (DeclContext *)opaque_decl_ctx; + std::set<DeclContext *> searched; + std::multimap<DeclContext *, DeclContext *> search_queue; + SymbolFile *symbol_file = GetSymbolFile(); + + for (clang::DeclContext *decl_context = root_decl_ctx; + decl_context != nullptr && found_decls.empty(); + decl_context = decl_context->getParent()) { + search_queue.insert(std::make_pair(decl_context, decl_context)); + + for (auto it = search_queue.find(decl_context); it != search_queue.end(); + it++) { + if (!searched.insert(it->second).second) + continue; + symbol_file->ParseDeclsForContext( + CreateDeclContext(it->second)); + + for (clang::Decl *child : it->second->decls()) { + if (clang::UsingDirectiveDecl *ud = + llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) { + if (ignore_using_decls) + continue; + clang::DeclContext *from = ud->getCommonAncestor(); + if (searched.find(ud->getNominatedNamespace()) == searched.end()) + search_queue.insert( + std::make_pair(from, ud->getNominatedNamespace())); + } else if (clang::UsingDecl *ud = + llvm::dyn_cast<clang::UsingDecl>(child)) { + if (ignore_using_decls) + continue; + for (clang::UsingShadowDecl *usd : ud->shadows()) { + clang::Decl *target = usd->getTargetDecl(); + if (clang::NamedDecl *nd = + llvm::dyn_cast<clang::NamedDecl>(target)) { + IdentifierInfo *ii = nd->getIdentifier(); + if (ii != nullptr && + ii->getName().equals(name.AsCString(nullptr))) + found_decls.push_back(GetCompilerDecl(nd)); + } + } + } else if (clang::NamedDecl *nd = + llvm::dyn_cast<clang::NamedDecl>(child)) { + IdentifierInfo *ii = nd->getIdentifier(); + if (ii != nullptr && ii->getName().equals(name.AsCString(nullptr))) + found_decls.push_back(GetCompilerDecl(nd)); + } + } + } + } + } + return found_decls; +} + +// Look for child_decl_ctx's lookup scope in frame_decl_ctx and its parents, +// and return the number of levels it took to find it, or +// LLDB_INVALID_DECL_LEVEL if not found. If the decl was imported via a using +// declaration, its name and/or type, if set, will be used to check that the +// decl found in the scope is a match. +// +// The optional name is required by languages (like C++) to handle using +// declarations like: +// +// void poo(); +// namespace ns { +// void foo(); +// void goo(); +// } +// void bar() { +// using ns::foo; +// // CountDeclLevels returns 0 for 'foo', 1 for 'poo', and +// // LLDB_INVALID_DECL_LEVEL for 'goo'. +// } +// +// The optional type is useful in the case that there's a specific overload +// that we're looking for that might otherwise be shadowed, like: +// +// void foo(int); +// namespace ns { +// void foo(); +// } +// void bar() { +// using ns::foo; +// // CountDeclLevels returns 0 for { 'foo', void() }, +// // 1 for { 'foo', void(int) }, and +// // LLDB_INVALID_DECL_LEVEL for { 'foo', void(int, int) }. +// } +// +// NOTE: Because file statics are at the TranslationUnit along with globals, a +// function at file scope will return the same level as a function at global +// scope. Ideally we'd like to treat the file scope as an additional scope just +// below the global scope. More work needs to be done to recognise that, if +// the decl we're trying to look up is static, we should compare its source +// file with that of the current scope and return a lower number for it. +uint32_t TypeSystemClang::CountDeclLevels(clang::DeclContext *frame_decl_ctx, + clang::DeclContext *child_decl_ctx, + ConstString *child_name, + CompilerType *child_type) { + if (frame_decl_ctx) { + std::set<DeclContext *> searched; + std::multimap<DeclContext *, DeclContext *> search_queue; + SymbolFile *symbol_file = GetSymbolFile(); + + // Get the lookup scope for the decl we're trying to find. + clang::DeclContext *parent_decl_ctx = child_decl_ctx->getParent(); + + // Look for it in our scope's decl context and its parents. + uint32_t level = 0; + for (clang::DeclContext *decl_ctx = frame_decl_ctx; decl_ctx != nullptr; + decl_ctx = decl_ctx->getParent()) { + if (!decl_ctx->isLookupContext()) + continue; + if (decl_ctx == parent_decl_ctx) + // Found it! + return level; + search_queue.insert(std::make_pair(decl_ctx, decl_ctx)); + for (auto it = search_queue.find(decl_ctx); it != search_queue.end(); + it++) { + if (searched.find(it->second) != searched.end()) + continue; + + // Currently DWARF has one shared translation unit for all Decls at top + // level, so this would erroneously find using statements anywhere. So + // don't look at the top-level translation unit. + // TODO fix this and add a testcase that depends on it. + + if (llvm::isa<clang::TranslationUnitDecl>(it->second)) + continue; + + searched.insert(it->second); + symbol_file->ParseDeclsForContext( + CreateDeclContext(it->second)); + + for (clang::Decl *child : it->second->decls()) { + if (clang::UsingDirectiveDecl *ud = + llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) { + clang::DeclContext *ns = ud->getNominatedNamespace(); + if (ns == parent_decl_ctx) + // Found it! + return level; + clang::DeclContext *from = ud->getCommonAncestor(); + if (searched.find(ns) == searched.end()) + search_queue.insert(std::make_pair(from, ns)); + } else if (child_name) { + if (clang::UsingDecl *ud = + llvm::dyn_cast<clang::UsingDecl>(child)) { + for (clang::UsingShadowDecl *usd : ud->shadows()) { + clang::Decl *target = usd->getTargetDecl(); + clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(target); + if (!nd) + continue; + // Check names. + IdentifierInfo *ii = nd->getIdentifier(); + if (ii == nullptr || + !ii->getName().equals(child_name->AsCString(nullptr))) + continue; + // Check types, if one was provided. + if (child_type) { + CompilerType clang_type = GetTypeForDecl(nd); + if (!AreTypesSame(clang_type, *child_type, + /*ignore_qualifiers=*/true)) + continue; + } + // Found it! + return level; + } + } + } + } + } + ++level; + } + } + return LLDB_INVALID_DECL_LEVEL; +} + +ConstString TypeSystemClang::DeclContextGetName(void *opaque_decl_ctx) { + if (opaque_decl_ctx) { + clang::NamedDecl *named_decl = + llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx); + if (named_decl) + return ConstString(named_decl->getName()); + } + return ConstString(); +} + +ConstString +TypeSystemClang::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) { + if (opaque_decl_ctx) { + clang::NamedDecl *named_decl = + llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx); + if (named_decl) + return ConstString( + llvm::StringRef(named_decl->getQualifiedNameAsString())); + } + return ConstString(); +} + +bool TypeSystemClang::DeclContextIsClassMethod( + void *opaque_decl_ctx, lldb::LanguageType *language_ptr, + bool *is_instance_method_ptr, ConstString *language_object_name_ptr) { + if (opaque_decl_ctx) { + clang::DeclContext *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; + if (ObjCMethodDecl *objc_method = + llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx)) { + if (is_instance_method_ptr) + *is_instance_method_ptr = objc_method->isInstanceMethod(); + if (language_ptr) + *language_ptr = eLanguageTypeObjC; + if (language_object_name_ptr) + language_object_name_ptr->SetCString("self"); + return true; + } else if (CXXMethodDecl *cxx_method = + llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx)) { + if (is_instance_method_ptr) + *is_instance_method_ptr = cxx_method->isInstance(); + if (language_ptr) + *language_ptr = eLanguageTypeC_plus_plus; + if (language_object_name_ptr) + language_object_name_ptr->SetCString("this"); + return true; + } else if (clang::FunctionDecl *function_decl = + llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) { + ClangASTMetadata *metadata = GetMetadata(function_decl); + if (metadata && metadata->HasObjectPtr()) { + if (is_instance_method_ptr) + *is_instance_method_ptr = true; + if (language_ptr) + *language_ptr = eLanguageTypeObjC; + if (language_object_name_ptr) + language_object_name_ptr->SetCString(metadata->GetObjectPtrName()); + return true; + } + } + } + return false; +} + +bool TypeSystemClang::DeclContextIsContainedInLookup( + void *opaque_decl_ctx, void *other_opaque_decl_ctx) { + auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; + auto *other = (clang::DeclContext *)other_opaque_decl_ctx; + + do { + // A decl context always includes its own contents in its lookup. + if (decl_ctx == other) + return true; + + // If we have an inline namespace, then the lookup of the parent context + // also includes the inline namespace contents. + } while (other->isInlineNamespace() && (other = other->getParent())); + + return false; +} + +static bool IsClangDeclContext(const CompilerDeclContext &dc) { + return dc.IsValid() && isa<TypeSystemClang>(dc.GetTypeSystem()); +} + +clang::DeclContext * +TypeSystemClang::DeclContextGetAsDeclContext(const CompilerDeclContext &dc) { + if (IsClangDeclContext(dc)) + return (clang::DeclContext *)dc.GetOpaqueDeclContext(); + return nullptr; +} + +ObjCMethodDecl * +TypeSystemClang::DeclContextGetAsObjCMethodDecl(const CompilerDeclContext &dc) { + if (IsClangDeclContext(dc)) + return llvm::dyn_cast<clang::ObjCMethodDecl>( + (clang::DeclContext *)dc.GetOpaqueDeclContext()); + return nullptr; +} + +CXXMethodDecl * +TypeSystemClang::DeclContextGetAsCXXMethodDecl(const CompilerDeclContext &dc) { + if (IsClangDeclContext(dc)) + return llvm::dyn_cast<clang::CXXMethodDecl>( + (clang::DeclContext *)dc.GetOpaqueDeclContext()); + return nullptr; +} + +clang::FunctionDecl * +TypeSystemClang::DeclContextGetAsFunctionDecl(const CompilerDeclContext &dc) { + if (IsClangDeclContext(dc)) + return llvm::dyn_cast<clang::FunctionDecl>( + (clang::DeclContext *)dc.GetOpaqueDeclContext()); + return nullptr; +} + +clang::NamespaceDecl * +TypeSystemClang::DeclContextGetAsNamespaceDecl(const CompilerDeclContext &dc) { + if (IsClangDeclContext(dc)) + return llvm::dyn_cast<clang::NamespaceDecl>( + (clang::DeclContext *)dc.GetOpaqueDeclContext()); + return nullptr; +} + +ClangASTMetadata * +TypeSystemClang::DeclContextGetMetaData(const CompilerDeclContext &dc, + const Decl *object) { + TypeSystemClang *ast = llvm::cast<TypeSystemClang>(dc.GetTypeSystem()); + return ast->GetMetadata(object); +} + +clang::ASTContext * +TypeSystemClang::DeclContextGetTypeSystemClang(const CompilerDeclContext &dc) { + TypeSystemClang *ast = + llvm::dyn_cast_or_null<TypeSystemClang>(dc.GetTypeSystem()); + if (ast) + return &ast->getASTContext(); + return nullptr; +} + +TypeSystemClangForExpressions::TypeSystemClangForExpressions( + Target &target, llvm::Triple triple) + : TypeSystemClang("scratch ASTContext", triple), + m_target_wp(target.shared_from_this()), + m_persistent_variables(new ClangPersistentVariables) { + m_scratch_ast_source_up = std::make_unique<ClangASTSource>( + target.shared_from_this(), m_persistent_variables->GetClangASTImporter()); + m_scratch_ast_source_up->InstallASTContext(*this); + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source( + m_scratch_ast_source_up->CreateProxy()); + SetExternalSource(proxy_ast_source); +} + +void TypeSystemClangForExpressions::Finalize() { + TypeSystemClang::Finalize(); + m_scratch_ast_source_up.reset(); +} + +UserExpression *TypeSystemClangForExpressions::GetUserExpression( + llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, + Expression::ResultType desired_type, + const EvaluateExpressionOptions &options, + ValueObject *ctx_obj) { + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + return new ClangUserExpression(*target_sp.get(), expr, prefix, language, + desired_type, options, ctx_obj); +} + +FunctionCaller *TypeSystemClangForExpressions::GetFunctionCaller( + const CompilerType &return_type, const Address &function_address, + const ValueList &arg_value_list, const char *name) { + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + Process *process = target_sp->GetProcessSP().get(); + if (!process) + return nullptr; + + return new ClangFunctionCaller(*process, return_type, function_address, + arg_value_list, name); +} + +UtilityFunction * +TypeSystemClangForExpressions::GetUtilityFunction(const char *text, + const char *name) { + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + return new ClangUtilityFunction(*target_sp.get(), text, name); +} + +PersistentExpressionState * +TypeSystemClangForExpressions::GetPersistentExpressionState() { + return m_persistent_variables.get(); +} diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h new file mode 100644 index 000000000000..9475e4d9f442 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -0,0 +1,1153 @@ +//===-- TypeSystemClang.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_TYPESYSTEM_CLANG_TYPESYSTEMCLANG_H +#define LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_TYPESYSTEMCLANG_H + +#include <stdint.h> + +#include <functional> +#include <initializer_list> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTFwd.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallVector.h" + +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/TypeSystem.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Flags.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/lldb-enumerations.h" + +class DWARFASTParserClang; +class PDBASTParser; + +namespace clang { +class FileManager; +class HeaderSearch; +class ModuleMap; +} // namespace clang + +namespace lldb_private { + +class ClangASTMetadata; +class ClangASTSource; +class Declaration; + +/// A Clang module ID. +class OptionalClangModuleID { + unsigned m_id = 0; + +public: + OptionalClangModuleID() = default; + explicit OptionalClangModuleID(unsigned id) : m_id(id) {} + bool HasValue() const { return m_id != 0; } + unsigned GetValue() const { return m_id; } +}; + +/// The implementation of lldb::Type's m_payload field for TypeSystemClang. +class TypePayloadClang { + /// The Layout is as follows: + /// \verbatim + /// bit 0..30 ... Owning Module ID. + /// bit 31 ...... IsCompleteObjCClass. + /// \endverbatim + Type::Payload m_payload = 0; + +public: + TypePayloadClang() = default; + explicit TypePayloadClang(OptionalClangModuleID owning_module, + bool is_complete_objc_class = false); + explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} + operator Type::Payload() { return m_payload; } + + static constexpr unsigned ObjCClassBit = 1 << 31; + bool IsCompleteObjCClass() { return Flags(m_payload).Test(ObjCClassBit); } + void SetIsCompleteObjCClass(bool is_complete_objc_class) { + m_payload = is_complete_objc_class ? Flags(m_payload).Set(ObjCClassBit) + : Flags(m_payload).Clear(ObjCClassBit); + } + OptionalClangModuleID GetOwningModule() { + return OptionalClangModuleID(Flags(m_payload).Clear(ObjCClassBit)); + } + void SetOwningModule(OptionalClangModuleID id); + /// \} +}; + +/// A TypeSystem implementation based on Clang. +/// +/// This class uses a single clang::ASTContext as the backend for storing +/// its types and declarations. Every clang::ASTContext should also just have +/// a single associated TypeSystemClang instance that manages it. +/// +/// The clang::ASTContext instance can either be created by TypeSystemClang +/// itself or it can adopt an existing clang::ASTContext (for example, when +/// it is necessary to provide a TypeSystem interface for an existing +/// clang::ASTContext that was created by clang::CompilerInstance). +class TypeSystemClang : public TypeSystem { + // LLVM RTTI support + static char ID; + +public: + typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *); + typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton, + clang::ObjCInterfaceDecl *); + + // llvm casting support + bool isA(const void *ClassID) const override { return ClassID == &ID; } + static bool classof(const TypeSystem *ts) { return ts->isA(&ID); } + + /// Constructs a TypeSystemClang with an ASTContext using the given triple. + /// + /// \param name The name for the TypeSystemClang (for logging purposes) + /// \param triple The llvm::Triple used for the ASTContext. The triple defines + /// certain characteristics of the ASTContext and its types + /// (e.g., whether certain primitive types exist or what their + /// signedness is). + explicit TypeSystemClang(llvm::StringRef name, llvm::Triple triple); + + /// Constructs a TypeSystemClang that uses an existing ASTContext internally. + /// Useful when having an existing ASTContext created by Clang. + /// + /// \param name The name for the TypeSystemClang (for logging purposes) + /// \param existing_ctxt An existing ASTContext. + explicit TypeSystemClang(llvm::StringRef name, + clang::ASTContext &existing_ctxt); + + ~TypeSystemClang() override; + + void Finalize() override; + + // PluginInterface functions + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + static ConstString GetPluginNameStatic(); + + static lldb::TypeSystemSP CreateInstance(lldb::LanguageType language, + Module *module, Target *target); + + static LanguageSet GetSupportedLanguagesForTypes(); + static LanguageSet GetSupportedLanguagesForExpressions(); + + static void Initialize(); + + static void Terminate(); + + static TypeSystemClang *GetASTContext(clang::ASTContext *ast_ctx); + + static TypeSystemClang *GetScratch(Target &target, + bool create_on_demand = true) { + auto type_system_or_err = target.GetScratchTypeSystemForLanguage( + lldb::eLanguageTypeC, create_on_demand); + if (auto err = type_system_or_err.takeError()) { + LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET), + std::move(err), "Couldn't get scratch TypeSystemClang"); + return nullptr; + } + return llvm::dyn_cast<TypeSystemClang>(&type_system_or_err.get()); + } + + /// Returns the display name of this TypeSystemClang that indicates what + /// purpose it serves in LLDB. Used for example in logs. + llvm::StringRef getDisplayName() const { return m_display_name; } + + /// Returns the clang::ASTContext instance managed by this TypeSystemClang. + clang::ASTContext &getASTContext(); + + clang::MangleContext *getMangleContext(); + + std::shared_ptr<clang::TargetOptions> &getTargetOptions(); + + clang::TargetInfo *getTargetInfo(); + + void setSema(clang::Sema *s); + clang::Sema *getSema() { return m_sema; } + + const char *GetTargetTriple(); + + void SetExternalSource( + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> &ast_source_up); + + bool GetCompleteDecl(clang::Decl *decl) { + return TypeSystemClang::GetCompleteDecl(&getASTContext(), decl); + } + + static void DumpDeclHiearchy(clang::Decl *decl); + + 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); + void SetMetadataAsUserID(const clang::Type *type, lldb::user_id_t user_id); + + void SetMetadata(const clang::Decl *object, ClangASTMetadata &meta_data); + + void SetMetadata(const clang::Type *object, ClangASTMetadata &meta_data); + ClangASTMetadata *GetMetadata(const clang::Decl *object); + ClangASTMetadata *GetMetadata(const clang::Type *object); + + // Basic Types + CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, + size_t bit_size) override; + + CompilerType GetBasicType(lldb::BasicType type); + + static lldb::BasicType GetBasicTypeEnumeration(ConstString name); + + CompilerType + GetBuiltinTypeForDWARFEncodingAndBitSize(llvm::StringRef type_name, + uint32_t dw_ate, uint32_t bit_size); + + CompilerType GetCStringType(bool is_const); + + static clang::DeclContext *GetDeclContextForType(clang::QualType type); + + static clang::DeclContext *GetDeclContextForType(const CompilerType &type); + + uint32_t GetPointerByteSize() override; + + clang::TranslationUnitDecl *GetTranslationUnitDecl() { + return getASTContext().getTranslationUnitDecl(); + } + + static bool AreTypesSame(CompilerType type1, CompilerType type2, + bool ignore_qualifiers = false); + + /// Creates a CompilerType form the given QualType with the current + /// TypeSystemClang instance as the CompilerType's typesystem. + /// \param qt The QualType for a type that belongs to the ASTContext of this + /// TypeSystemClang. + /// \return The CompilerType representing the given QualType. If the + /// QualType's type pointer is a nullptr then the function returns an + /// invalid CompilerType. + CompilerType GetType(clang::QualType qt) { + if (qt.getTypePtrOrNull() == nullptr) + return CompilerType(); + // Check that the type actually belongs to this TypeSystemClang. + assert(qt->getAsTagDecl() == nullptr || + &qt->getAsTagDecl()->getASTContext() == &getASTContext()); + return CompilerType(this, qt.getAsOpaquePtr()); + } + + CompilerType GetTypeForDecl(clang::NamedDecl *decl); + + CompilerType GetTypeForDecl(clang::TagDecl *decl); + + CompilerType GetTypeForDecl(clang::ObjCInterfaceDecl *objc_decl); + + template <typename RecordDeclType> + CompilerType + GetTypeForIdentifier(ConstString type_name, + clang::DeclContext *decl_context = nullptr) { + CompilerType compiler_type; + + if (type_name.GetLength()) { + clang::ASTContext &ast = getASTContext(); + if (!decl_context) + decl_context = ast.getTranslationUnitDecl(); + + clang::IdentifierInfo &myIdent = ast.Idents.get(type_name.GetCString()); + clang::DeclarationName myName = + ast.DeclarationNames.getIdentifier(&myIdent); + + clang::DeclContext::lookup_result result = decl_context->lookup(myName); + + if (!result.empty()) { + clang::NamedDecl *named_decl = result[0]; + if (const RecordDeclType *record_decl = + llvm::dyn_cast<RecordDeclType>(named_decl)) + compiler_type.SetCompilerType( + this, clang::QualType(record_decl->getTypeForDecl(), 0) + .getAsOpaquePtr()); + } + } + + return compiler_type; + } + + CompilerType CreateStructForIdentifier( + ConstString type_name, + const std::initializer_list<std::pair<const char *, CompilerType>> + &type_fields, + bool packed = false); + + CompilerType GetOrCreateStructForIdentifier( + ConstString type_name, + const std::initializer_list<std::pair<const char *, CompilerType>> + &type_fields, + bool packed = false); + + static bool IsOperator(llvm::StringRef name, + clang::OverloadedOperatorKind &op_kind); + + // Structure, Unions, Classes + + static clang::AccessSpecifier + ConvertAccessTypeToAccessSpecifier(lldb::AccessType access); + + static clang::AccessSpecifier + UnifyAccessSpecifiers(clang::AccessSpecifier lhs, clang::AccessSpecifier rhs); + + static uint32_t GetNumBaseClasses(const clang::CXXRecordDecl *cxx_record_decl, + bool omit_empty_base_classes); + + /// Synthesize a clang::Module and return its ID or a default-constructed ID. + OptionalClangModuleID GetOrCreateClangModule(llvm::StringRef name, + OptionalClangModuleID parent, + bool is_framework = false, + bool is_explicit = false); + + CompilerType CreateRecordType(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + lldb::AccessType access_type, + llvm::StringRef name, int kind, + lldb::LanguageType language, + ClangASTMetadata *metadata = nullptr, + bool exports_symbols = false); + + class TemplateParameterInfos { + public: + bool IsValid() const { + if (args.empty()) + return false; + return args.size() == names.size() && + ((bool)pack_name == (bool)packed_args) && + (!packed_args || !packed_args->packed_args); + } + + llvm::SmallVector<const char *, 2> names; + llvm::SmallVector<clang::TemplateArgument, 2> args; + + const char * pack_name = nullptr; + std::unique_ptr<TemplateParameterInfos> packed_args; + }; + + clang::FunctionTemplateDecl * + CreateFunctionTemplateDecl(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + clang::FunctionDecl *func_decl, const char *name, + const TemplateParameterInfos &infos); + + void CreateFunctionTemplateSpecializationInfo( + clang::FunctionDecl *func_decl, clang::FunctionTemplateDecl *Template, + const TemplateParameterInfos &infos); + + clang::ClassTemplateDecl * + CreateClassTemplateDecl(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + lldb::AccessType access_type, const char *class_name, + int kind, const TemplateParameterInfos &infos); + + clang::TemplateTemplateParmDecl * + CreateTemplateTemplateParmDecl(const char *template_name); + + clang::ClassTemplateSpecializationDecl *CreateClassTemplateSpecializationDecl( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + clang::ClassTemplateDecl *class_template_decl, int kind, + const TemplateParameterInfos &infos); + + CompilerType + CreateClassTemplateSpecializationType(clang::ClassTemplateSpecializationDecl * + class_template_specialization_decl); + + static clang::DeclContext * + GetAsDeclContext(clang::FunctionDecl *function_decl); + + static bool CheckOverloadedOperatorKindParameterCount( + bool is_method, clang::OverloadedOperatorKind op_kind, + uint32_t num_params); + + bool FieldIsBitfield(clang::FieldDecl *field, uint32_t &bitfield_bit_size); + + static bool RecordHasFields(const clang::RecordDecl *record_decl); + + CompilerType CreateObjCClass(llvm::StringRef name, + clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + bool isForwardDecl, bool isInternal, + ClangASTMetadata *metadata = nullptr); + + bool SetTagTypeKind(clang::QualType type, int kind) const; + + bool SetDefaultAccessForRecordFields(clang::RecordDecl *record_decl, + int default_accessibility, + int *assigned_accessibilities, + size_t num_assigned_accessibilities); + + // Returns a mask containing bits from the TypeSystemClang::eTypeXXX + // enumerations + + // Namespace Declarations + + clang::NamespaceDecl * + GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + bool is_inline = false); + + // Function Types + + clang::FunctionDecl * + CreateFunctionDeclaration(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + const char *name, const CompilerType &function_Type, + int storage, bool is_inline); + + CompilerType CreateFunctionType(const CompilerType &result_type, + const CompilerType *args, unsigned num_args, + bool is_variadic, unsigned type_quals, + clang::CallingConv cc); + + CompilerType CreateFunctionType(const CompilerType &result_type, + const CompilerType *args, unsigned num_args, + bool is_variadic, unsigned type_quals) { + return CreateFunctionType(result_type, args, num_args, is_variadic, + type_quals, clang::CC_C); + } + + clang::ParmVarDecl * + CreateParameterDeclaration(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + const char *name, const CompilerType ¶m_type, + int storage, bool add_decl = false); + + void SetFunctionParameters(clang::FunctionDecl *function_decl, + clang::ParmVarDecl **params, unsigned num_params); + + CompilerType CreateBlockPointerType(const CompilerType &function_type); + + // Array Types + + CompilerType CreateArrayType(const CompilerType &element_type, + size_t element_count, bool is_vector); + + // Enumeration Types + CompilerType CreateEnumerationType(const char *name, + clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + const Declaration &decl, + const CompilerType &integer_qual_type, + bool is_scoped); + + // Integer type functions + + CompilerType GetIntTypeFromBitSize(size_t bit_size, bool is_signed); + + CompilerType GetPointerSizedIntType(bool is_signed); + + // Floating point functions + + static CompilerType GetFloatTypeFromBitSize(clang::ASTContext *ast, + size_t bit_size); + + // TypeSystem methods + DWARFASTParser *GetDWARFParser() override; + PDBASTParser *GetPDBParser() override; + + // TypeSystemClang callbacks for external source lookups. + void CompleteTagDecl(clang::TagDecl *); + + void CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *); + + bool LayoutRecordType( + const clang::RecordDecl *record_decl, uint64_t &size, uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets); + + /// Creates a CompilerDecl from the given Decl with the current + /// TypeSystemClang instance as its typesystem. + /// The Decl has to come from the ASTContext of this + /// TypeSystemClang. + CompilerDecl GetCompilerDecl(clang::Decl *decl) { + assert(&decl->getASTContext() == &getASTContext() && + "CreateCompilerDecl for Decl from wrong ASTContext?"); + return CompilerDecl(this, decl); + } + + // CompilerDecl override functions + ConstString DeclGetName(void *opaque_decl) override; + + ConstString DeclGetMangledName(void *opaque_decl) override; + + CompilerDeclContext DeclGetDeclContext(void *opaque_decl) override; + + CompilerType DeclGetFunctionReturnType(void *opaque_decl) override; + + size_t DeclGetFunctionNumArguments(void *opaque_decl) override; + + CompilerType DeclGetFunctionArgumentType(void *opaque_decl, + size_t arg_idx) override; + + CompilerType GetTypeForDecl(void *opaque_decl) override; + + // CompilerDeclContext override functions + + /// Creates a CompilerDeclContext from the given DeclContext + /// with the current TypeSystemClang instance as its typesystem. + /// The DeclContext has to come from the ASTContext of this + /// TypeSystemClang. + CompilerDeclContext CreateDeclContext(clang::DeclContext *ctx); + + /// Set the owning module for \p decl. + static void SetOwningModule(clang::Decl *decl, + OptionalClangModuleID owning_module); + + std::vector<CompilerDecl> + DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name, + const bool ignore_using_decls) override; + + ConstString DeclContextGetName(void *opaque_decl_ctx) override; + + ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override; + + bool DeclContextIsClassMethod(void *opaque_decl_ctx, + lldb::LanguageType *language_ptr, + bool *is_instance_method_ptr, + ConstString *language_object_name_ptr) override; + + bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, + void *other_opaque_decl_ctx) override; + + // Clang specific clang::DeclContext functions + + static clang::DeclContext * + DeclContextGetAsDeclContext(const CompilerDeclContext &dc); + + static clang::ObjCMethodDecl * + DeclContextGetAsObjCMethodDecl(const CompilerDeclContext &dc); + + static clang::CXXMethodDecl * + DeclContextGetAsCXXMethodDecl(const CompilerDeclContext &dc); + + static clang::FunctionDecl * + DeclContextGetAsFunctionDecl(const CompilerDeclContext &dc); + + static clang::NamespaceDecl * + DeclContextGetAsNamespaceDecl(const CompilerDeclContext &dc); + + static ClangASTMetadata *DeclContextGetMetaData(const CompilerDeclContext &dc, + const clang::Decl *object); + + static clang::ASTContext * + DeclContextGetTypeSystemClang(const CompilerDeclContext &dc); + + // Tests + +#ifndef NDEBUG + bool Verify(lldb::opaque_compiler_type_t type) override; +#endif + + bool IsArrayType(lldb::opaque_compiler_type_t type, + CompilerType *element_type, uint64_t *size, + bool *is_incomplete) override; + + bool IsVectorType(lldb::opaque_compiler_type_t type, + CompilerType *element_type, uint64_t *size) override; + + bool IsAggregateType(lldb::opaque_compiler_type_t type) override; + + bool IsAnonymousType(lldb::opaque_compiler_type_t type) override; + + bool IsBeingDefined(lldb::opaque_compiler_type_t type) override; + + bool IsCharType(lldb::opaque_compiler_type_t type) override; + + bool IsCompleteType(lldb::opaque_compiler_type_t type) override; + + bool IsConst(lldb::opaque_compiler_type_t type) override; + + bool IsCStringType(lldb::opaque_compiler_type_t type, + uint32_t &length) override; + + static bool IsCXXClassType(const CompilerType &type); + + bool IsDefined(lldb::opaque_compiler_type_t type) override; + + bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, + bool &is_complex) override; + + bool IsFunctionType(lldb::opaque_compiler_type_t type, + bool *is_variadic_ptr) override; + + uint32_t IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, + CompilerType *base_type_ptr) override; + + size_t + GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type) override; + + CompilerType GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type, + const size_t index) override; + + bool IsFunctionPointerType(lldb::opaque_compiler_type_t type) override; + + bool IsBlockPointerType(lldb::opaque_compiler_type_t type, + CompilerType *function_pointer_type_ptr) override; + + bool IsIntegerType(lldb::opaque_compiler_type_t type, + bool &is_signed) override; + + bool IsEnumerationType(lldb::opaque_compiler_type_t type, + bool &is_signed) override; + + static bool IsObjCClassType(const CompilerType &type); + + static bool IsObjCClassTypeAndHasIVars(const CompilerType &type, + bool check_superclass); + + static bool IsObjCObjectOrInterfaceType(const CompilerType &type); + + static bool IsObjCObjectPointerType(const CompilerType &type, + CompilerType *target_type = nullptr); + + bool IsPolymorphicClass(lldb::opaque_compiler_type_t type) override; + + static bool IsClassType(lldb::opaque_compiler_type_t type); + + static bool IsEnumType(lldb::opaque_compiler_type_t type); + + bool IsPossibleDynamicType(lldb::opaque_compiler_type_t type, + CompilerType *target_type, // Can pass nullptr + bool check_cplusplus, bool check_objc) override; + + bool IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) override; + + bool IsPointerType(lldb::opaque_compiler_type_t type, + CompilerType *pointee_type) override; + + bool IsPointerOrReferenceType(lldb::opaque_compiler_type_t type, + CompilerType *pointee_type) override; + + bool IsReferenceType(lldb::opaque_compiler_type_t type, + CompilerType *pointee_type, bool *is_rvalue) override; + + bool IsScalarType(lldb::opaque_compiler_type_t type) override; + + bool IsTypedefType(lldb::opaque_compiler_type_t type) override; + + bool IsVoidType(lldb::opaque_compiler_type_t type) override; + + bool CanPassInRegisters(const CompilerType &type) override; + + bool SupportsLanguage(lldb::LanguageType language) override; + + static llvm::Optional<std::string> GetCXXClassName(const CompilerType &type); + + // Type Completion + + bool GetCompleteType(lldb::opaque_compiler_type_t type) override; + + // Accessors + + ConstString GetTypeName(lldb::opaque_compiler_type_t type) override; + + ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type) override; + + uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type, + CompilerType *pointee_or_element_compiler_type) override; + + lldb::LanguageType + GetMinimumLanguage(lldb::opaque_compiler_type_t type) override; + + lldb::TypeClass GetTypeClass(lldb::opaque_compiler_type_t type) override; + + unsigned GetTypeQualifiers(lldb::opaque_compiler_type_t type) override; + + // Creating related types + + /// Using the current type, create a new typedef to that type using + /// "typedef_name" as the name and "decl_ctx" as the decl context. + /// \param payload is an opaque TypePayloadClang. + static CompilerType + CreateTypedefType(const CompilerType &type, const char *typedef_name, + const CompilerDeclContext &compiler_decl_ctx, + uint32_t opaque_payload); + + CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type, + uint64_t *stride) override; + + CompilerType GetArrayType(lldb::opaque_compiler_type_t type, + uint64_t size) override; + + CompilerType GetCanonicalType(lldb::opaque_compiler_type_t type) override; + + CompilerType + GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) override; + + // Returns -1 if this isn't a function of if the function doesn't have a + // prototype Returns a value >= 0 if there is a prototype. + int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) override; + + CompilerType GetFunctionArgumentTypeAtIndex(lldb::opaque_compiler_type_t type, + size_t idx) override; + + CompilerType + GetFunctionReturnType(lldb::opaque_compiler_type_t type) override; + + size_t GetNumMemberFunctions(lldb::opaque_compiler_type_t type) override; + + TypeMemberFunctionImpl + GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type, + size_t idx) override; + + CompilerType GetNonReferenceType(lldb::opaque_compiler_type_t type) override; + + CompilerType GetPointeeType(lldb::opaque_compiler_type_t type) override; + + CompilerType GetPointerType(lldb::opaque_compiler_type_t type) override; + + CompilerType + GetLValueReferenceType(lldb::opaque_compiler_type_t type) override; + + CompilerType + GetRValueReferenceType(lldb::opaque_compiler_type_t type) override; + + CompilerType GetAtomicType(lldb::opaque_compiler_type_t type) override; + + CompilerType AddConstModifier(lldb::opaque_compiler_type_t type) override; + + CompilerType AddVolatileModifier(lldb::opaque_compiler_type_t type) override; + + CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type) override; + + CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, + const char *name, + const CompilerDeclContext &decl_ctx, + uint32_t opaque_payload) override; + + // If the current object represents a typedef type, get the underlying type + CompilerType GetTypedefedType(lldb::opaque_compiler_type_t type) override; + + // Create related types using the current type's AST + CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override; + + // Exploring the type + + const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override; + + llvm::Optional<uint64_t> GetByteSize(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + if (llvm::Optional<uint64_t> bit_size = GetBitSize(type, exe_scope)) + return (*bit_size + 7) / 8; + return llvm::None; + } + + llvm::Optional<uint64_t> + GetBitSize(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) override; + + lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type, + uint64_t &count) override; + + lldb::Format GetFormat(lldb::opaque_compiler_type_t type) override; + + llvm::Optional<size_t> + GetTypeBitAlign(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) override; + + uint32_t GetNumChildren(lldb::opaque_compiler_type_t type, + bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) override; + + CompilerType GetBuiltinTypeByName(ConstString name) override; + + lldb::BasicType + GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) override; + + static lldb::BasicType + GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type, + ConstString name); + + void ForEachEnumerator( + lldb::opaque_compiler_type_t type, + std::function<bool(const CompilerType &integer_type, + ConstString name, + const llvm::APSInt &value)> const &callback) override; + + uint32_t GetNumFields(lldb::opaque_compiler_type_t type) override; + + CompilerType GetFieldAtIndex(lldb::opaque_compiler_type_t type, size_t idx, + std::string &name, uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, + bool *is_bitfield_ptr) override; + + uint32_t GetNumDirectBaseClasses(lldb::opaque_compiler_type_t type) override; + + uint32_t GetNumVirtualBaseClasses(lldb::opaque_compiler_type_t type) override; + + CompilerType GetDirectBaseClassAtIndex(lldb::opaque_compiler_type_t type, + size_t idx, + uint32_t *bit_offset_ptr) override; + + CompilerType GetVirtualBaseClassAtIndex(lldb::opaque_compiler_type_t type, + size_t idx, + uint32_t *bit_offset_ptr) override; + + static uint32_t GetNumPointeeChildren(clang::QualType type); + + CompilerType GetChildCompilerTypeAtIndex( + lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, + bool transparent_pointers, bool omit_empty_base_classes, + bool ignore_array_bounds, std::string &child_name, + uint32_t &child_byte_size, int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset, + bool &child_is_base_class, bool &child_is_deref_of_parent, + ValueObject *valobj, uint64_t &language_flags) override; + + // Lookup a child given a name. This function will match base class names and + // member member names in "clang_type" only, not descendants. + uint32_t GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, + const char *name, + bool omit_empty_base_classes) override; + + // Lookup a child member given a name. This function will match member names + // only and will descend into "clang_type" children in search for the first + // member in this class, or any base class that matches "name". + // TODO: Return all matches for a given name by returning a + // vector<vector<uint32_t>> + // so we catch all names that match a given child name, not just the first. + size_t + GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type, + const char *name, bool omit_empty_base_classes, + std::vector<uint32_t> &child_indexes) override; + + size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override; + + lldb::TemplateArgumentKind + GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, + size_t idx) override; + CompilerType GetTypeTemplateArgument(lldb::opaque_compiler_type_t type, + size_t idx) override; + llvm::Optional<CompilerType::IntegralTemplateArgument> + GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, + size_t idx) override; + + CompilerType GetTypeForFormatters(void *type) override; + +#define LLDB_INVALID_DECL_LEVEL UINT32_MAX + // LLDB_INVALID_DECL_LEVEL is returned by CountDeclLevels if child_decl_ctx + // could not be found in decl_ctx. + uint32_t CountDeclLevels(clang::DeclContext *frame_decl_ctx, + clang::DeclContext *child_decl_ctx, + ConstString *child_name = nullptr, + CompilerType *child_type = nullptr); + + // Modifying RecordType + static clang::FieldDecl *AddFieldToRecordType(const CompilerType &type, + llvm::StringRef name, + const CompilerType &field_type, + lldb::AccessType access, + uint32_t bitfield_bit_size); + + static void BuildIndirectFields(const CompilerType &type); + + static void SetIsPacked(const CompilerType &type); + + static clang::VarDecl *AddVariableToRecordType(const CompilerType &type, + llvm::StringRef name, + const CompilerType &var_type, + lldb::AccessType access); + + /// Initializes a variable with an integer value. + /// \param var The variable to initialize. Must not already have an + /// initializer and must have an integer or enum type. + /// \param init_value The integer value that the variable should be + /// initialized to. Has to match the bit width of the + /// variable type. + static void SetIntegerInitializerForVariable(clang::VarDecl *var, + const llvm::APInt &init_value); + + /// Initializes a variable with a floating point value. + /// \param var The variable to initialize. Must not already have an + /// initializer and must have a floating point type. + /// \param init_value The float value that the variable should be + /// initialized to. + static void + SetFloatingInitializerForVariable(clang::VarDecl *var, + const llvm::APFloat &init_value); + + clang::CXXMethodDecl *AddMethodToCXXRecordType( + lldb::opaque_compiler_type_t type, llvm::StringRef name, + const char *mangled_name, const CompilerType &method_type, + lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, + bool is_explicit, bool is_attr_used, bool is_artificial); + + void AddMethodOverridesForCXXRecordType(lldb::opaque_compiler_type_t type); + + // C++ Base Classes + std::unique_ptr<clang::CXXBaseSpecifier> + CreateBaseClassSpecifier(lldb::opaque_compiler_type_t type, + lldb::AccessType access, bool is_virtual, + bool base_of_class); + + bool TransferBaseClasses( + lldb::opaque_compiler_type_t type, + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases); + + static bool SetObjCSuperClass(const CompilerType &type, + const CompilerType &superclass_compiler_type); + + static bool AddObjCClassProperty(const CompilerType &type, + const char *property_name, + const CompilerType &property_compiler_type, + clang::ObjCIvarDecl *ivar_decl, + const char *property_setter_name, + const char *property_getter_name, + uint32_t property_attributes, + ClangASTMetadata *metadata); + + static clang::ObjCMethodDecl *AddMethodToObjCObjectType( + const CompilerType &type, + 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); + + static bool SetHasExternalStorage(lldb::opaque_compiler_type_t type, + bool has_extern); + + // Tag Declarations + static bool StartTagDeclarationDefinition(const CompilerType &type); + + static bool CompleteTagDeclarationDefinition(const CompilerType &type); + + // Modifying Enumeration types + clang::EnumConstantDecl *AddEnumerationValueToEnumerationType( + const CompilerType &enum_type, const Declaration &decl, const char *name, + int64_t enum_value, uint32_t enum_value_bit_size); + clang::EnumConstantDecl *AddEnumerationValueToEnumerationType( + const CompilerType &enum_type, const Declaration &decl, const char *name, + const llvm::APSInt &value); + + /// Returns the underlying integer type for an enum type. If the given type + /// is invalid or not an enum-type, the function returns an invalid + /// CompilerType. + CompilerType GetEnumerationIntegerType(CompilerType type); + + // Pointers & References + + // Call this function using the class type when you want to make a member + // pointer type to pointee_type. + static CompilerType CreateMemberPointerType(const CompilerType &type, + const CompilerType &pointee_type); + + // Dumping types +#ifndef NDEBUG + /// Convenience LLVM-style dump method for use in the debugger only. + /// In contrast to the other \p Dump() methods this directly invokes + /// \p clang::QualType::dump(). + LLVM_DUMP_METHOD void dump(lldb::opaque_compiler_type_t type) const override; +#endif + + void Dump(Stream &s); + + /// Dump clang AST types from the symbol file. + /// + /// \param[in] s + /// A stream to send the dumped AST node(s) to + /// \param[in] symbol_name + /// 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; + + void DumpTypeDescription( + lldb::opaque_compiler_type_t type, Stream *s, + lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override; + + static void DumpTypeName(const CompilerType &type); + + static clang::EnumDecl *GetAsEnumDecl(const CompilerType &type); + + static clang::RecordDecl *GetAsRecordDecl(const CompilerType &type); + + static clang::TagDecl *GetAsTagDecl(const CompilerType &type); + + static clang::TypedefNameDecl *GetAsTypedefDecl(const CompilerType &type); + + static clang::CXXRecordDecl * + GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type); + + static clang::ObjCInterfaceDecl * + GetAsObjCInterfaceDecl(const CompilerType &type); + + clang::ClassTemplateDecl *ParseClassTemplateDecl( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + lldb::AccessType access_type, const char *parent_name, int tag_decl_kind, + const TypeSystemClang::TemplateParameterInfos &template_param_infos); + + clang::BlockDecl *CreateBlockDeclaration(clang::DeclContext *ctx, + OptionalClangModuleID owning_module); + + clang::UsingDirectiveDecl * + CreateUsingDirectiveDeclaration(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + clang::NamespaceDecl *ns_decl); + + clang::UsingDecl *CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, + OptionalClangModuleID owning_module, + clang::NamedDecl *target); + + clang::VarDecl *CreateVariableDeclaration(clang::DeclContext *decl_context, + OptionalClangModuleID owning_module, + const char *name, + clang::QualType type); + + static lldb::opaque_compiler_type_t + GetOpaqueCompilerType(clang::ASTContext *ast, lldb::BasicType basic_type); + + static clang::QualType GetQualType(lldb::opaque_compiler_type_t type) { + if (type) + return clang::QualType::getFromOpaquePtr(type); + return clang::QualType(); + } + + static clang::QualType + GetCanonicalQualType(lldb::opaque_compiler_type_t type) { + if (type) + return clang::QualType::getFromOpaquePtr(type).getCanonicalType(); + return clang::QualType(); + } + + clang::DeclarationName + GetDeclarationName(const char *name, const CompilerType &function_clang_type); + + clang::LangOptions *GetLangOpts() const { + return m_language_options_up.get(); + } + clang::SourceManager *GetSourceMgr() const { + return m_source_manager_up.get(); + } + +private: + const clang::ClassTemplateSpecializationDecl * + GetAsTemplateSpecialization(lldb::opaque_compiler_type_t type); + + // Classes that inherit from TypeSystemClang can see and modify these + std::string m_target_triple; + std::unique_ptr<clang::ASTContext> m_ast_up; + std::unique_ptr<clang::LangOptions> m_language_options_up; + std::unique_ptr<clang::FileManager> m_file_manager_up; + std::unique_ptr<clang::SourceManager> m_source_manager_up; + std::unique_ptr<clang::DiagnosticsEngine> m_diagnostics_engine_up; + std::unique_ptr<clang::DiagnosticConsumer> m_diagnostic_consumer_up; + std::shared_ptr<clang::TargetOptions> m_target_options_rp; + std::unique_ptr<clang::TargetInfo> m_target_info_up; + std::unique_ptr<clang::IdentifierTable> m_identifier_table_up; + std::unique_ptr<clang::SelectorTable> m_selector_table_up; + std::unique_ptr<clang::Builtin::Context> m_builtins_up; + std::unique_ptr<clang::HeaderSearch> m_header_search_up; + std::unique_ptr<clang::ModuleMap> m_module_map_up; + std::unique_ptr<DWARFASTParserClang> m_dwarf_ast_parser_up; + std::unique_ptr<PDBASTParser> m_pdb_ast_parser_up; + std::unique_ptr<clang::MangleContext> m_mangle_ctx_up; + uint32_t m_pointer_byte_size = 0; + bool m_ast_owned = false; + /// A string describing what this TypeSystemClang represents (e.g., + /// AST for debug information, an expression, some other utility ClangAST). + /// Useful for logging and debugging. + std::string m_display_name; + + typedef llvm::DenseMap<const clang::Decl *, ClangASTMetadata> DeclMetadataMap; + /// Maps Decls to their associated ClangASTMetadata. + DeclMetadataMap m_decl_metadata; + + typedef llvm::DenseMap<const clang::Type *, ClangASTMetadata> TypeMetadataMap; + /// Maps Types to their associated ClangASTMetadata. + TypeMetadataMap m_type_metadata; + + /// The sema associated that is currently used to build this ASTContext. + /// May be null if we are already done parsing this ASTContext or the + /// ASTContext wasn't created by parsing source code. + clang::Sema *m_sema = nullptr; + + // For TypeSystemClang only + TypeSystemClang(const TypeSystemClang &); + const TypeSystemClang &operator=(const TypeSystemClang &); + /// Creates the internal ASTContext. + void CreateASTContext(); + void SetTargetTriple(llvm::StringRef target_triple); +}; + +/// The TypeSystemClang instance used for the scratch ASTContext in a +/// lldb::Target. +class TypeSystemClangForExpressions : public TypeSystemClang { +public: + TypeSystemClangForExpressions(Target &target, llvm::Triple triple); + + ~TypeSystemClangForExpressions() override = default; + + void Finalize() override; + + UserExpression * + GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix, + lldb::LanguageType language, + Expression::ResultType desired_type, + const EvaluateExpressionOptions &options, + ValueObject *ctx_obj) override; + + FunctionCaller *GetFunctionCaller(const CompilerType &return_type, + const Address &function_address, + const ValueList &arg_value_list, + const char *name) override; + + UtilityFunction *GetUtilityFunction(const char *text, + const char *name) override; + + PersistentExpressionState *GetPersistentExpressionState() override; +private: + lldb::TargetWP m_target_wp; + std::unique_ptr<ClangPersistentVariables> + m_persistent_variables; // These are the persistent variables associated + // with this process for the expression parser + std::unique_ptr<ClangASTSource> m_scratch_ast_source_up; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_TYPESYSTEMCLANG_H diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index 4aa9fb634b61..1bc071c2b161 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -1,4 +1,4 @@ -//===-- UnwindAssemblyInstEmulation.cpp --------------------------*- C++-*-===// +//===-- UnwindAssemblyInstEmulation.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -28,6 +28,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(UnwindAssemblyInstEmulation) + // UnwindAssemblyInstEmulation method definitions bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( @@ -123,18 +125,12 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( // Add the initial state to the save list with offset 0. saved_unwind_states.insert({0, {last_row, m_register_values}}); - // cache the pc register number (in whatever register numbering this - // UnwindPlan uses) for quick reference during instruction parsing. - RegisterInfo pc_reg_info; - m_inst_emulator_up->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info); - - // cache the return address register number (in whatever register + // cache the stack pointer register number (in whatever register // numbering this UnwindPlan uses) for quick reference during // instruction parsing. - RegisterInfo ra_reg_info; + RegisterInfo sp_reg_info; m_inst_emulator_up->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info); + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp_reg_info); // The architecture dependent condition code of the last processed // instruction. @@ -165,6 +161,23 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( *newrow = *it->second.first; m_curr_row.reset(newrow); m_register_values = it->second.second; + // re-set the CFA register ivars to match the + // new m_curr_row. + if (sp_reg_info.name && + m_curr_row->GetCFAValue().IsRegisterPlusOffset()) { + uint32_t row_cfa_regnum = + m_curr_row->GetCFAValue().GetRegisterNumber(); + lldb::RegisterKind row_kind = + m_unwind_plan_ptr->GetRegisterKind(); + // set m_cfa_reg_info to the row's CFA reg. + m_inst_emulator_up->GetRegisterInfo(row_kind, row_cfa_regnum, + m_cfa_reg_info); + // set m_fp_is_cfa. + if (sp_reg_info.kinds[row_kind] == row_cfa_regnum) + m_fp_is_cfa = false; + else + m_fp_is_cfa = true; + } } m_inst_emulator_up->SetInstruction(inst->GetOpcode(), @@ -195,6 +208,23 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( std::make_shared<UnwindPlan::Row>(*saved_state.first); m_curr_row->SetOffset(current_offset); m_register_values = saved_state.second; + // re-set the CFA register ivars to match the + // new m_curr_row. + if (sp_reg_info.name && + m_curr_row->GetCFAValue().IsRegisterPlusOffset()) { + uint32_t row_cfa_regnum = + m_curr_row->GetCFAValue().GetRegisterNumber(); + lldb::RegisterKind row_kind = + m_unwind_plan_ptr->GetRegisterKind(); + // set m_cfa_reg_info to the row's CFA reg. + m_inst_emulator_up->GetRegisterInfo(row_kind, row_cfa_regnum, + m_cfa_reg_info); + // set m_fp_is_cfa. + if (sp_reg_info.kinds[row_kind] == row_cfa_regnum) + m_fp_is_cfa = false; + else + m_fp_is_cfa = true; + } bool replace_existing = true; // The last instruction might already // created a row for this offset and diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h index 9125bd5b1fe3..5784a42a8269 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_UnwindAssemblyInstEmulation_h_ -#define liblldb_UnwindAssemblyInstEmulation_h_ +#ifndef LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_INSTEMULATION_UNWINDASSEMBLYINSTEMULATION_H +#define LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_INSTEMULATION_UNWINDASSEMBLYINSTEMULATION_H #include "lldb/Core/EmulateInstruction.h" #include "lldb/Symbol/UnwindPlan.h" @@ -151,4 +151,4 @@ private: uint32_t m_forward_branch_offset; }; -#endif // liblldb_UnwindAssemblyInstEmulation_h_ +#endif // LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_INSTEMULATION_UNWINDASSEMBLYINSTEMULATION_H diff --git a/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp index ce168f021047..fe1275d5b0cf 100644 --- a/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp +++ b/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp @@ -1,4 +1,4 @@ -//===-- UnwindAssembly-x86.cpp ----------------------------------*- C++ -*-===// +//===-- UnwindAssembly-x86.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -30,6 +30,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(UnwindAssembly_x86, UnwindAssemblyX86) + // UnwindAssemblyParser_x86 method definitions UnwindAssembly_x86::UnwindAssembly_x86(const ArchSpec &arch) @@ -139,7 +141,7 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( // and we don't need to modify it at all. if (first_row_pc_loc.GetOffset() == -wordsize) { - do_augment_unwindplan = false; + return true; } } } diff --git a/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h b/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h index 7c198bbc33af..3e1588f2065c 100644 --- a/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h +++ b/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_UnwindAssembly_x86_h_ -#define liblldb_UnwindAssembly_x86_h_ +#ifndef LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_X86_UNWINDASSEMBLY_X86_H +#define LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_X86_UNWINDASSEMBLY_X86_H #include "x86AssemblyInspectionEngine.h" @@ -62,4 +62,4 @@ private: lldb_private::x86AssemblyInspectionEngine *m_assembly_inspection_engine; }; -#endif // liblldb_UnwindAssembly_x86_h_ +#endif // LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_X86_UNWINDASSEMBLY_X86_H diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp index bf6f60a2d26c..36e7b90cad24 100644 --- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp +++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp @@ -1,4 +1,4 @@ -//===-- x86AssemblyInspectionEngine.cpp -------------------------*- C++ -*-===// +//===-- x86AssemblyInspectionEngine.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h index 680598abdeff..f39dce1afaa6 100644 --- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h +++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_x86AssemblyInspectionEngine_h_ -#define liblldb_x86AssemblyInspectionEngine_h_ +#ifndef LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_X86_X86ASSEMBLYINSPECTIONENGINE_H +#define LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_X86_X86ASSEMBLYINSPECTIONENGINE_H #include "llvm-c/Disassembler.h" @@ -191,9 +191,11 @@ private: ::LLVMDisasmContextRef m_disasm_context; - DISALLOW_COPY_AND_ASSIGN(x86AssemblyInspectionEngine); + x86AssemblyInspectionEngine(const x86AssemblyInspectionEngine &) = delete; + const x86AssemblyInspectionEngine & + operator=(const x86AssemblyInspectionEngine &) = delete; }; } // namespace lldb_private -#endif // liblldb_x86AssemblyInspectionEngine_h_ +#endif // LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_X86_X86ASSEMBLYINSPECTIONENGINE_H |